diff --git a/.github/workflows/check_pr_source.yml b/.github/workflows/check_pr_source.yml new file mode 100644 index 0000000000..877ab85c73 --- /dev/null +++ b/.github/workflows/check_pr_source.yml @@ -0,0 +1,19 @@ +name: Enforce test-staging → main + +on: + pull_request: + branches: + - master + +jobs: + require-test-staging: + runs-on: ubuntu-22.04 + steps: + - name: Ensure PR source is test-staging + run: | + echo "Base: ${{ github.event.pull_request.base.ref }}" + echo "Head: ${{ github.event.pull_request.head.ref }}" + if [ "${{ github.event.pull_request.head.ref }}" != "test-staging" ]; then + echo "✖ Pull request must come from test-staging" + exit 1 + fi diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..a23a7e67fa --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,136 @@ +# Pull Request + +Describe what this change does and why it is needed... + +--- + +## Design Philosophy + +We prioritize **stability, performance, and predictability** over behavioral realism. +Complex player-mimicking logic is intentionally limited due to its negative impact on scalability, maintainability, and +long-term robustness. + +Excessive processing overhead can lead to server hiccups, increased CPU usage, and degraded performance for all +participants. Because every action and +decision tree is executed **per bot and per trigger**, even small increases in logic complexity can scale poorly and +negatively affect both players and +world (random) bots. Bots are not expected to behave perfectly, and perfect simulation of human decision-making is not a +project goal. Increased behavioral +realism often introduces disproportionate cost, reduced predictability, and significantly higher maintenance overhead. + +Every additional branch of logic increases long-term responsibility. All decision paths must be tested, validated, and +maintained continuously as the system evolves. +If advanced or AI-intensive behavior is introduced, the **default configuration must remain the lightweight decision +model**. More complex behavior should only be +available as an **explicit opt-in option**, clearly documented as having a measurable performance cost. + +Principles: + +- **Stability before intelligence** + A stable system is always preferred over a smarter one. + +- **Performance is a shared resource** + Any increase in bot cost affects all players and all bots. + +- **Simple logic scales better than smart logic** + Predictable behavior under load is more valuable than perfect decisions. + +- **Complexity must justify itself** + If a feature cannot clearly explain its cost, it should not exist. + +- **Defaults must be cheap** + Expensive behavior must always be optional and clearly communicated. + +- **Bots should look reasonable, not perfect** + The goal is believable behavior, not human simulation. + +Before submitting, confirm that this change aligns with those principles. + +--- + +## Feature Evaluation + +Please answer the following: + +- Describe the **minimum logic** required to achieve the intended behavior? +- Describe the **cheapest implementation** that produces an acceptable result? +- Describe the **runtime cost** when this logic executes across many bots? + +--- + +## How to Test the Changes + +- Step-by-step instructions to test the change +- Any required setup (e.g. multiple players, bots, specific configuration) +- Expected behavior and how to verify it + +## Complexity & Impact + +Does this change add new decision branches? +``` +[ ] No +[ ] Yes (**explain below**) +``` + +Does this change increase per-bot or per-tick processing? +``` +[ ] No +[ ] Yes (**describe and justify impact**) +``` + +Could this logic scale poorly under load? +``` +[ ] No +[ ] Yes (**explain why**) +``` +--- + +## Defaults & Configuration + +Does this change modify default bot behavior? +``` +[ ] No +[ ] Yes (**explain why**) +``` + +If this introduces more advanced or AI-heavy logic: +``` +[ ] Lightweight mode remains the default +[ ] More complex behavior is optional and thereby configurable +``` +--- + +## AI Assistance + +Was AI assistance (e.g. ChatGPT or similar tools) used while working on this change? +``` +[ ] No +[ ] Yes (**explain below**) +``` + +If yes, please specify: + +- AI tool or model used (e.g. ChatGPT, GPT-4, Claude, etc.) +- Purpose of usage (e.g. brainstorming, refactoring, documentation, code generation) +- Which parts of the change were influenced or generated +- Whether the result was manually reviewed and adapted + +AI assistance is allowed, but all submitted code must be fully understood, reviewed, and owned by the contributor. +Any AI-influenced changes must be verified against existing CORE and PB logic. We expect contributors to be honest +about what they do and do not understand. + +--- + +## Final Checklist + +- [ ] Stability is not compromised +- [ ] Performance impact is understood, tested, and acceptable +- [ ] Added logic complexity is justified and explained +- [ ] Documentation updated if needed + +--- + +## Notes for Reviewers + +Anything that significantly improves realism at the cost of stability or performance should be carefully discussed +before merging. diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 81668a9559..22615b4071 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -544,8 +544,8 @@ AiPlayerbot.AutoGearQualityLimit = 3 # Max iLVL Phase 1(MC, Ony, ZG) = 78 | Phase 2(BWL) = 83 | Phase 2.5(AQ40) = 88 | Phase 3(Naxx40) = 92 # TBC # Max iLVL Tier 4 = 120 | Tier 5 = 133 | Tier 6 = 164 -# Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 1.5(ZA) = 138 | Phase 2(SC, TK) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164 -# Wotlk +# Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 2(SSC, TK, ZA) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164 +# WotLK # Max iLVL Tier 7(10/25) = 200/213 | Tier 8(10/25) = 225/232 | Tier 9(10/25) = 232/245 | Tier 10(10/25/HC) = 251/264/290 # Max iLVL Phase 1(Naxx) = 224 | Phase 2(Ulduar) = 245 | Phase 3(ToC) = 258 | Phase 4(ICC) = 290 # Default: 0 (no limit) @@ -736,7 +736,7 @@ AiPlayerbot.RandomGearQualityLimit = 3 # TBC # Max iLVL Tier 4 = 120 | Tier 5 = 133 | Tier 6 = 164 # Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 2(SSC, TK, ZA) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164 -# Wotlk +# WotLK # Max iLVL Tier 7(10/25) = 200/213 | Tier 8(10/25) = 225/232 | Tier 9(10/25) = 232/245 | Tier 10(10/25/HC) = 251/264/290 # Max iLVL Phase 1(Naxx) = 224 | Phase 2(Ulduar) = 245 | Phase 3(ToC) = 258 | Phase 4(ICC) = 290 # Default: 0 (no limit) @@ -1624,7 +1624,7 @@ AiPlayerbot.PremadeSpecLink.9.1.60 = -003203301135112530135201051 AiPlayerbot.PremadeSpecLink.9.1.70 = -003203301135112530135201051-55 AiPlayerbot.PremadeSpecLink.9.1.80 = -003203301135112530135221351-55000005 AiPlayerbot.PremadeSpecName.9.2 = destro pve -AiPlayerbot.PremadeSpecGlyph.9.2 = 45785,43390,50077,43394,43393,42454 +AiPlayerbot.PremadeSpecGlyph.9.2 = 45785,43390,42454,43394,43393,45785 AiPlayerbot.PremadeSpecLink.9.2.60 = --05203215200231051305031151 AiPlayerbot.PremadeSpecLink.9.2.80 = 23-0302-05203215220331051335231351 AiPlayerbot.PremadeSpecName.9.3 = affli pvp diff --git a/data/sql/characters/updates/2026_01_30_00_change_to_InnoDB.sql b/data/sql/characters/updates/2026_01_30_00_change_to_InnoDB.sql new file mode 100644 index 0000000000..8c2c226b51 --- /dev/null +++ b/data/sql/characters/updates/2026_01_30_00_change_to_InnoDB.sql @@ -0,0 +1,9 @@ +-- Temporarily disables innodb_strict_mode for the session to allow the script to complete even if legacy table definitions contain InnoDB-incompatible attributes +SET SESSION innodb_strict_mode = 0; + +-- Change the tables to InnoDB +ALTER TABLE playerbots_guild_names ENGINE=InnoDB; +ALTER TABLE playerbots_names ENGINE=InnoDB; + +-- Re-enables innodb_strict_mode +SET SESSION innodb_strict_mode = 1; diff --git a/data/sql/playerbots/updates/2026_01_30_00_change_to_InnoDB.sql b/data/sql/playerbots/updates/2026_01_30_00_change_to_InnoDB.sql new file mode 100644 index 0000000000..c7f9c51f0a --- /dev/null +++ b/data/sql/playerbots/updates/2026_01_30_00_change_to_InnoDB.sql @@ -0,0 +1,18 @@ +-- Temporarily disables innodb_strict_mode for the session to allow the script to complete even if legacy table definitions contain InnoDB-incompatible attributes +SET SESSION innodb_strict_mode = 0; + +-- Change the tables to InnoDB +ALTER TABLE playerbots_dungeon_suggestion_abbrevation ENGINE=InnoDB; +ALTER TABLE playerbots_dungeon_suggestion_definition ENGINE=InnoDB; +ALTER TABLE playerbots_dungeon_suggestion_strategy ENGINE=InnoDB; +ALTER TABLE playerbots_equip_cache ENGINE=InnoDB; +ALTER TABLE playerbots_item_info_cache ENGINE=InnoDB; +ALTER TABLE playerbots_rarity_cache ENGINE=InnoDB; +ALTER TABLE playerbots_rnditem_cache ENGINE=InnoDB; +ALTER TABLE playerbots_tele_cache ENGINE=InnoDB; +ALTER TABLE playerbots_travelnode ENGINE=InnoDB; +ALTER TABLE playerbots_travelnode_link ENGINE=InnoDB; +ALTER TABLE playerbots_travelnode_path ENGINE=InnoDB; + +-- Re-enables innodb_strict_mode +SET SESSION innodb_strict_mode = 1; diff --git a/data/sql/playerbots/updates/2026_01_31_00_ai_playerbot_multi_pvp_text_variables.sql b/data/sql/playerbots/updates/2026_01_31_00_ai_playerbot_multi_pvp_text_variables.sql new file mode 100644 index 0000000000..9889147f60 --- /dev/null +++ b/data/sql/playerbots/updates/2026_01_31_00_ai_playerbot_multi_pvp_text_variables.sql @@ -0,0 +1,101 @@ +-- ######################################################### +-- Playerbots - Add PVP / Arena texts for TellPvpAction +-- Localized for all WotLK locales (koKR, frFR, deDE, zhCN, +-- zhTW, esES, esMX, ruRU) +-- ######################################################### + +-- --------------------------------------------------------- +-- pvp_currency +-- [PVP] Arena points: %arena_points | Honor Points: %honor_points +-- --------------------------------------------------------- +INSERT INTO `ai_playerbot_texts` + (`name`, `text`, `say_type`, `reply_type`, + `text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`, + `text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`) +SELECT + 'pvp_currency', + '[PVP] Arena points: %arena_points | Honor Points: %honor_points', + 0, 0, + -- koKR + '[PVP] 투기장 점수: %arena_points | 명예 점수: %honor_points', + -- frFR + '[PVP] Points d''arène : %arena_points | Points d''honneur : %honor_points', + -- deDE + '[PVP] Arenapunkte: %arena_points | Ehrenpunkte: %honor_points', + -- zhCN + '[PVP] 竞技场点数:%arena_points | 荣誉点数:%honor_points', + -- zhTW + '[PVP] 競技場點數:%arena_points | 榮譽點數:%honor_points', + -- esES + '[PVP] Puntos de arena: %arena_points | Puntos de honor: %honor_points', + -- esMX + '[PVP] Puntos de arena: %arena_points | Puntos de honor: %honor_points', + -- ruRU + '[PVP] Очки арены: %arena_points | Очки чести: %honor_points' +WHERE NOT EXISTS ( + SELECT 1 FROM `ai_playerbot_texts` WHERE `name` = 'pvp_currency' +); + +-- --------------------------------------------------------- +-- pvp_arena_team +-- [PVP] %bracket: <%team_name> (rating %team_rating) +-- --------------------------------------------------------- +INSERT INTO `ai_playerbot_texts` + (`name`, `text`, `say_type`, `reply_type`, + `text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`, + `text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`) +SELECT + 'pvp_arena_team', + '[PVP] %bracket: <%team_name> (rating %team_rating)', + 0, 0, + -- koKR + '[PVP] %bracket: <%team_name> (평점 %team_rating)', + -- frFR + '[PVP] %bracket : <%team_name> (cote %team_rating)', + -- deDE + '[PVP] %bracket: <%team_name> (Wertung %team_rating)', + -- zhCN + '[PVP] %bracket: <%team_name> (评分 %team_rating)', + -- zhTW + '[PVP] %bracket: <%team_name> (評分 %team_rating)', + -- esES + '[PVP] %bracket: <%team_name> (índice %team_rating)', + -- esMX + '[PVP] %bracket: <%team_name> (índice %team_rating)', + -- ruRU + '[PVP] %bracket: <%team_name> (рейтинг %team_rating)' +WHERE NOT EXISTS ( + SELECT 1 FROM `ai_playerbot_texts` WHERE `name` = 'pvp_arena_team' +); + +-- --------------------------------------------------------- +-- pvp_no_arena_team +-- [PVP] I have no Arena Team. +-- --------------------------------------------------------- +INSERT INTO `ai_playerbot_texts` + (`name`, `text`, `say_type`, `reply_type`, + `text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`, + `text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`) +SELECT + 'pvp_no_arena_team', + '[PVP] I have no Arena Team.', + 0, 0, + -- koKR + '[PVP] 투기장 팀이 없습니다.', + -- frFR + '[PVP] Je n''ai aucune équipe d''arène.', + -- deDE + '[PVP] Ich habe kein Arenateam.', + -- zhCN + '[PVP] 我没有竞技场战队。', + -- zhTW + '[PVP] 我沒有競技場隊伍。', + -- esES + '[PVP] No tengo equipo de arena.', + -- esMX + '[PVP] No tengo equipo de arena.', + -- ruRU + '[PVP] У меня нет команды арены.' +WHERE NOT EXISTS ( + SELECT 1 FROM `ai_playerbot_texts` WHERE `name` = 'pvp_no_arena_team' +); diff --git a/src/Ai/Base/ActionContext.h b/src/Ai/Base/ActionContext.h index 93bba4afee..9f4e612ed4 100644 --- a/src/Ai/Base/ActionContext.h +++ b/src/Ai/Base/ActionContext.h @@ -46,6 +46,7 @@ #include "OutfitAction.h" #include "PositionAction.h" #include "DropQuestAction.h" +#include "RaidNaxxActions.h" #include "RandomBotUpdateAction.h" #include "ReachTargetActions.h" #include "ReleaseSpiritAction.h" diff --git a/src/Ai/Base/Actions/AcceptInvitationAction.cpp b/src/Ai/Base/Actions/AcceptInvitationAction.cpp index 5e0bffc47f..1be3c0921a 100644 --- a/src/Ai/Base/Actions/AcceptInvitationAction.cpp +++ b/src/Ai/Base/Actions/AcceptInvitationAction.cpp @@ -46,10 +46,10 @@ bool AcceptInvitationAction::Execute(Event event) if (!bot->GetGroup() || !bot->GetGroup()->IsMember(inviter->GetGUID())) return false; - if (sRandomPlayerbotMgr->IsRandomBot(bot)) + if (sRandomPlayerbotMgr.IsRandomBot(bot)) botAI->SetMaster(inviter); // else - // sPlayerbotRepository->Save(botAI); + // PlayerbotRepository::instance().Save(botAI); botAI->ResetStrategies(); botAI->ChangeStrategy("+follow,-lfg,-bg", BOT_STATE_NON_COMBAT); @@ -57,7 +57,7 @@ bool AcceptInvitationAction::Execute(Event event) botAI->TellMaster("Hello"); - if (sPlayerbotAIConfig->summonWhenGroup && bot->GetDistance(inviter) > sPlayerbotAIConfig->sightDistance) + if (sPlayerbotAIConfig.summonWhenGroup && bot->GetDistance(inviter) > sPlayerbotAIConfig.sightDistance) { Teleport(inviter, bot, true); } diff --git a/src/Ai/Base/Actions/AreaTriggerAction.cpp b/src/Ai/Base/Actions/AreaTriggerAction.cpp index f480277825..c610085400 100644 --- a/src/Ai/Base/Actions/AreaTriggerAction.cpp +++ b/src/Ai/Base/Actions/AreaTriggerAction.cpp @@ -50,7 +50,7 @@ bool ReachAreaTriggerAction::Execute(Event event) /*forceDestination*/ false); float distance = bot->GetDistance(at->x, at->y, at->z); - float delay = 1000.0f * distance / bot->GetSpeed(MOVE_RUN) + sPlayerbotAIConfig->reactDelay; + float delay = 1000.0f * distance / bot->GetSpeed(MOVE_RUN) + sPlayerbotAIConfig.reactDelay; botAI->TellError("Wait for me"); botAI->SetNextCheckDelay(delay); context->GetValue("last area trigger")->Get().lastAreaTrigger = triggerId; diff --git a/src/Ai/Base/Actions/AttackAction.cpp b/src/Ai/Base/Actions/AttackAction.cpp index 2b8c486f8b..87bbd31c6b 100644 --- a/src/Ai/Base/Actions/AttackAction.cpp +++ b/src/Ai/Base/Actions/AttackAction.cpp @@ -87,8 +87,8 @@ bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/) // Check if bot OR target is in prohibited zone/area (skip for duels) if ((target->IsPlayer() || target->IsPet()) && (!bot->duel || bot->duel->Opponent != target) && - (sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()) || - sPlayerbotAIConfig->IsPvpProhibited(target->GetZoneId(), target->GetAreaId()))) + (sPlayerbotAIConfig.IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()) || + sPlayerbotAIConfig.IsPvpProhibited(target->GetZoneId(), target->GetAreaId()))) { if (verbose) botAI->TellError("I cannot attack other players in PvP prohibited areas."); @@ -160,7 +160,7 @@ bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/) } if (botAI->CanMove() && !bot->HasInArc(CAST_ANGLE_IN_FRONT, target)) - sServerFacade->SetFacingTo(bot, target); + ServerFacade::instance().SetFacingTo(bot, target); botAI->ChangeEngine(BOT_STATE_COMBAT); diff --git a/src/Ai/Base/Actions/AutoMaintenanceOnLevelupAction.cpp b/src/Ai/Base/Actions/AutoMaintenanceOnLevelupAction.cpp index 6939e5c925..de8b5c6fdc 100644 --- a/src/Ai/Base/Actions/AutoMaintenanceOnLevelupAction.cpp +++ b/src/Ai/Base/Actions/AutoMaintenanceOnLevelupAction.cpp @@ -19,7 +19,7 @@ bool AutoMaintenanceOnLevelupAction::Execute(Event event) void AutoMaintenanceOnLevelupAction::AutoTeleportForLevel() { - if (!sPlayerbotAIConfig->autoTeleportForLevel || !sRandomPlayerbotMgr->IsRandomBot(bot)) + if (!sPlayerbotAIConfig.autoTeleportForLevel || !sRandomPlayerbotMgr.IsRandomBot(bot)) { return; } @@ -27,13 +27,13 @@ void AutoMaintenanceOnLevelupAction::AutoTeleportForLevel() { return; } - sRandomPlayerbotMgr->RandomTeleportForLevel(bot); + sRandomPlayerbotMgr.RandomTeleportForLevel(bot); return; } void AutoMaintenanceOnLevelupAction::AutoPickTalents() { - if (!sPlayerbotAIConfig->autoPickTalents || !sRandomPlayerbotMgr->IsRandomBot(bot)) + if (!sPlayerbotAIConfig.autoPickTalents || !sRandomPlayerbotMgr.IsRandomBot(bot)) return; if (bot->GetFreeTalentPoints() <= 0) @@ -65,10 +65,10 @@ void AutoMaintenanceOnLevelupAction::AutoLearnSpell() void AutoMaintenanceOnLevelupAction::LearnSpells(std::ostringstream* out) { BroadcastHelper::BroadcastLevelup(botAI, bot); - if (sPlayerbotAIConfig->autoLearnTrainerSpells && sRandomPlayerbotMgr->IsRandomBot(bot)) + if (sPlayerbotAIConfig.autoLearnTrainerSpells && sRandomPlayerbotMgr.IsRandomBot(bot)) LearnTrainerSpells(out); - if (sPlayerbotAIConfig->autoLearnQuestSpells && sRandomPlayerbotMgr->IsRandomBot(bot)) + if (sPlayerbotAIConfig.autoLearnQuestSpells && sRandomPlayerbotMgr.IsRandomBot(bot)) LearnQuestSpells(out); } @@ -166,7 +166,7 @@ std::string const AutoMaintenanceOnLevelupAction::FormatSpell(SpellInfo const* s void AutoMaintenanceOnLevelupAction::AutoUpgradeEquip() { - if (!sPlayerbotAIConfig->autoUpgradeEquip || !sRandomPlayerbotMgr->IsRandomBot(bot)) + if (!sPlayerbotAIConfig.autoUpgradeEquip || !sRandomPlayerbotMgr.IsRandomBot(bot)) return; PlayerbotFactory factory(bot, bot->GetLevel()); @@ -180,9 +180,9 @@ void AutoMaintenanceOnLevelupAction::AutoUpgradeEquip() factory.InitConsumables(); factory.InitPotions(); - if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel) + if (!sPlayerbotAIConfig.equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel) { - if (sPlayerbotAIConfig->incrementalGearInit) + if (sPlayerbotAIConfig.incrementalGearInit) factory.InitEquipment(true); } } diff --git a/src/Ai/Base/Actions/BattleGroundJoinAction.cpp b/src/Ai/Base/Actions/BattleGroundJoinAction.cpp index 542c7566ff..418b0f1fa7 100644 --- a/src/Ai/Base/Actions/BattleGroundJoinAction.cpp +++ b/src/Ai/Base/Actions/BattleGroundJoinAction.cpp @@ -89,7 +89,7 @@ bool BGJoinAction::gatherArenaTeam(ArenaType type) // continue; if (offline) - sRandomPlayerbotMgr->AddPlayerBot(itr->Guid, 0); + sRandomPlayerbotMgr.AddPlayerBot(itr->Guid, 0); if (member) { @@ -100,7 +100,7 @@ bool BGJoinAction::gatherArenaTeam(ArenaType type) if (member->GetGroup() && memberBotAI->HasRealPlayerMaster()) continue; - if (!sPlayerbotAIConfig->IsInRandomAccountList(member->GetSession()->GetAccountId())) + if (!sPlayerbotAIConfig.IsInRandomAccountList(member->GetSession()->GetAccountId())) continue; if (member->IsInCombat()) @@ -250,13 +250,13 @@ bool BGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battlegroun TeamSize = (uint32)type; // Check if bots should join Rated Arena (Only captains can queue) - uint32 ratedArenaBotCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].ratedArenaBotCount; + uint32 ratedArenaBotCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].ratedArenaBotCount; uint32 ratedArenaPlayerCount = - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].ratedArenaPlayerCount; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].ratedArenaPlayerCount; uint32 ratedArenaInstanceCount = - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].ratedArenaInstanceCount; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].ratedArenaInstanceCount; uint32 activeRatedArenaQueue = - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].activeRatedArenaQueue; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].activeRatedArenaQueue; bool isRated = (ratedArenaBotCount + ratedArenaPlayerCount) < (BracketSize * (activeRatedArenaQueue + ratedArenaInstanceCount)); @@ -265,7 +265,7 @@ bool BGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battlegroun { if (sArenaTeamMgr->GetArenaTeamByCaptain(bot->GetGUID(), type)) { - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].ratedArenaBotCount += TeamSize; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].ratedArenaBotCount += TeamSize; ratedList.push_back(queueTypeId); return true; } @@ -274,13 +274,13 @@ bool BGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battlegroun // Check if bots should join Skirmish Arena // We have extra bots queue because same faction can vs each other but can't be in the same group. uint32 skirmishArenaBotCount = - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].skirmishArenaBotCount; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].skirmishArenaBotCount; uint32 skirmishArenaPlayerCount = - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].skirmishArenaPlayerCount; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].skirmishArenaPlayerCount; uint32 skirmishArenaInstanceCount = - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].skirmishArenaInstanceCount; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].skirmishArenaInstanceCount; uint32 activeSkirmishArenaQueue = - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].activeSkirmishArenaQueue; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].activeSkirmishArenaQueue; uint32 maxRequiredSkirmishBots = BracketSize * (activeSkirmishArenaQueue + skirmishArenaInstanceCount); if (maxRequiredSkirmishBots != 0) maxRequiredSkirmishBots = maxRequiredSkirmishBots + TeamSize; @@ -294,12 +294,12 @@ bool BGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battlegroun } // Check if bots should join Battleground - uint32 bgAllianceBotCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgAllianceBotCount; - uint32 bgAlliancePlayerCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgAlliancePlayerCount; - uint32 bgHordeBotCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgHordeBotCount; - uint32 bgHordePlayerCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgHordePlayerCount; - uint32 activeBgQueue = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].activeBgQueue; - uint32 bgInstanceCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgInstanceCount; + uint32 bgAllianceBotCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgAllianceBotCount; + uint32 bgAlliancePlayerCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgAlliancePlayerCount; + uint32 bgHordeBotCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgHordeBotCount; + uint32 bgHordePlayerCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgHordePlayerCount; + uint32 activeBgQueue = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].activeBgQueue; + uint32 bgInstanceCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgInstanceCount; if (teamId == TEAM_ALLIANCE) { @@ -318,7 +318,7 @@ bool BGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battlegroun bool BGJoinAction::isUseful() { // do not try if BG bots disabled - if (!sPlayerbotAIConfig->randomBotJoinBG) + if (!sPlayerbotAIConfig.randomBotJoinBG) return false; // can't queue while in BG/Arena @@ -440,7 +440,7 @@ bool BGJoinAction::JoinQueue(uint32 type) // get battlemaster // Unit* unit = botAI->GetUnit(AI_VALUE2(CreatureData const*, "bg master", bgTypeId)); - Unit* unit = botAI->GetUnit(sRandomPlayerbotMgr->GetBattleMasterGUID(bot, bgTypeId)); + Unit* unit = botAI->GetUnit(sRandomPlayerbotMgr.GetBattleMasterGUID(bot, bgTypeId)); if (!unit && isArena) { botAI->GetAiObjectContext()->GetValue("bg type")->Set(0); @@ -450,7 +450,7 @@ bool BGJoinAction::JoinQueue(uint32 type) // This breaks groups as refresh includes a remove from group function call. // refresh food/regs - // sRandomPlayerbotMgr->Refresh(bot); + // sRandomPlayerbotMgr.Refresh(bot); bool joinAsGroup = bot->GetGroup() && bot->GetGroup()->GetLeaderGUID() == bot->GetGUID(); @@ -523,23 +523,23 @@ bool BGJoinAction::JoinQueue(uint32 type) { if (!isRated) { - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].skirmishArenaBotCount++; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].skirmishArenaBotCount++; } } else if (!joinAsGroup) { if (teamId == TEAM_ALLIANCE) - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgAllianceBotCount++; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgAllianceBotCount++; else - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgHordeBotCount++; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgHordeBotCount++; } else { if (teamId == TEAM_ALLIANCE) - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgAllianceBotCount += + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgAllianceBotCount += bot->GetGroup()->GetMembersCount(); else - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgHordeBotCount += + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgHordeBotCount += bot->GetGroup()->GetMembersCount(); } @@ -588,13 +588,13 @@ bool FreeBGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battleg TeamSize = (uint32)type; // Check if bots should join Rated Arena (Only captains can queue) - uint32 ratedArenaBotCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].ratedArenaBotCount; + uint32 ratedArenaBotCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].ratedArenaBotCount; uint32 ratedArenaPlayerCount = - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].ratedArenaPlayerCount; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].ratedArenaPlayerCount; uint32 ratedArenaInstanceCount = - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].ratedArenaInstanceCount; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].ratedArenaInstanceCount; uint32 activeRatedArenaQueue = - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].activeRatedArenaQueue; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].activeRatedArenaQueue; bool isRated = (ratedArenaBotCount + ratedArenaPlayerCount) < (BracketSize * (activeRatedArenaQueue + ratedArenaInstanceCount)); @@ -603,7 +603,7 @@ bool FreeBGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battleg { if (sArenaTeamMgr->GetArenaTeamByCaptain(bot->GetGUID(), type)) { - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].ratedArenaBotCount += TeamSize; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].ratedArenaBotCount += TeamSize; ratedList.push_back(queueTypeId); return true; } @@ -612,13 +612,13 @@ bool FreeBGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battleg // Check if bots should join Skirmish Arena // We have extra bots queue because same faction can vs each other but can't be in the same group. uint32 skirmishArenaBotCount = - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].skirmishArenaBotCount; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].skirmishArenaBotCount; uint32 skirmishArenaPlayerCount = - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].skirmishArenaPlayerCount; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].skirmishArenaPlayerCount; uint32 skirmishArenaInstanceCount = - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].skirmishArenaInstanceCount; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].skirmishArenaInstanceCount; uint32 activeSkirmishArenaQueue = - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].activeSkirmishArenaQueue; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].activeSkirmishArenaQueue; uint32 maxRequiredSkirmishBots = BracketSize * (activeSkirmishArenaQueue + skirmishArenaInstanceCount); if (maxRequiredSkirmishBots != 0) maxRequiredSkirmishBots = maxRequiredSkirmishBots + TeamSize; @@ -632,12 +632,12 @@ bool FreeBGJoinAction::shouldJoinBg(BattlegroundQueueTypeId queueTypeId, Battleg } // Check if bots should join Battleground - uint32 bgAllianceBotCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgAllianceBotCount; - uint32 bgAlliancePlayerCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgAlliancePlayerCount; - uint32 bgHordeBotCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgHordeBotCount; - uint32 bgHordePlayerCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgHordePlayerCount; - uint32 activeBgQueue = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].activeBgQueue; - uint32 bgInstanceCount = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].bgInstanceCount; + uint32 bgAllianceBotCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgAllianceBotCount; + uint32 bgAlliancePlayerCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgAlliancePlayerCount; + uint32 bgHordeBotCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgHordeBotCount; + uint32 bgHordePlayerCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgHordePlayerCount; + uint32 activeBgQueue = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].activeBgQueue; + uint32 bgInstanceCount = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].bgInstanceCount; if (teamId == TEAM_ALLIANCE) { @@ -670,7 +670,7 @@ bool BGLeaveAction::Execute(Event event) uint16 unk = 0x1F90; uint8 unk2 = 0x0; bool isArena = false; - bool IsRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot); + bool IsRandomBot = sRandomPlayerbotMgr.IsRandomBot(bot); ArenaType arenaType = ArenaType(BattlegroundMgr::BGArenaType(queueTypeId)); if (arenaType) @@ -709,7 +709,7 @@ bool BGStatusAction::LeaveBG(PlayerbotAI* botAI) if (!bg) return false; bool isArena = bg->isArena(); - bool isRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot); + bool isRandomBot = sRandomPlayerbotMgr.IsRandomBot(bot); if (isRandomBot) botAI->SetMaster(nullptr); @@ -805,7 +805,7 @@ bool BGStatusAction::Execute(Event event) break; } - bool IsRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot); + bool IsRandomBot = sRandomPlayerbotMgr.IsRandomBot(bot); BattlegroundQueueTypeId queueTypeId = bot->GetBattlegroundQueueTypeId(QueueSlot); BattlegroundTypeId _bgTypeId = BattlegroundMgr::BGTemplateId(queueTypeId); if (!queueTypeId) @@ -958,10 +958,10 @@ bool BGStatusAction::Execute(Event event) //TeamId teamId = bot->GetTeamId(); //not used, line marked for removal. bool realPlayers = false; if (isRated) - realPlayers = sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].ratedArenaPlayerCount > 0; + realPlayers = sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].ratedArenaPlayerCount > 0; else realPlayers = - sRandomPlayerbotMgr->BattlegroundData[queueTypeId][bracketId].skirmishArenaPlayerCount > 0; + sRandomPlayerbotMgr.BattlegroundData[queueTypeId][bracketId].skirmishArenaPlayerCount > 0; if (realPlayers) return false; diff --git a/src/Ai/Base/Actions/BattleGroundTactics.cpp b/src/Ai/Base/Actions/BattleGroundTactics.cpp index 827ab01970..2b198022e0 100644 --- a/src/Ai/Base/Actions/BattleGroundTactics.cpp +++ b/src/Ai/Base/Actions/BattleGroundTactics.cpp @@ -1276,7 +1276,7 @@ static std::pair IC_AttackObjectives[] = { // useful commands for fixing BG bugs and checking waypoints/paths bool BGTactics::HandleConsoleCommand(ChatHandler* handler, char const* args) { - if (!sPlayerbotAIConfig->enabled) + if (!sPlayerbotAIConfig.enabled) { handler->PSendSysMessage("|cffff0000Playerbot system is currently disabled!"); return true; @@ -2219,7 +2219,7 @@ bool BGTactics::selectObjective(bool reset) if (urand(0, 99) < 20 && teamFC) { target.Relocate(teamFC->GetPositionX(), teamFC->GetPositionY(), teamFC->GetPositionZ()); - if (sServerFacade->GetDistance2d(bot, teamFC) < 33.0f) + if (ServerFacade::instance().GetDistance2d(bot, teamFC) < 33.0f) Follow(teamFC); } else @@ -2227,8 +2227,8 @@ bool BGTactics::selectObjective(bool reset) } // Graveyard Camping if in lead else if (!hasFlag && role < 8 && - (team == TEAM_ALLIANCE && allianceScore == 2 && hordeScore == 0) || - (team == TEAM_HORDE && hordeScore == 2 && allianceScore == 0)) + ((team == TEAM_ALLIANCE && allianceScore == 2 && hordeScore == 0) || + (team == TEAM_HORDE && hordeScore == 2 && allianceScore == 0))) { if (team == TEAM_ALLIANCE) SetSafePos(WS_GY_CAMPING_HORDE, 10.0f); @@ -2263,7 +2263,7 @@ bool BGTactics::selectObjective(bool reset) if (urand(0, 99) < 70) { target.Relocate(teamFC->GetPositionX(), teamFC->GetPositionY(), teamFC->GetPositionZ()); - if (sServerFacade->GetDistance2d(bot, teamFC) < 33.0f) + if (ServerFacade::instance().GetDistance2d(bot, teamFC) < 33.0f) Follow(teamFC); } } @@ -2284,7 +2284,7 @@ bool BGTactics::selectObjective(bool reset) { // Assist own FC if not pursuing enemy FC target.Relocate(teamFC->GetPositionX(), teamFC->GetPositionY(), teamFC->GetPositionZ()); - if (sServerFacade->GetDistance2d(bot, teamFC) < 33.0f) + if (ServerFacade::instance().GetDistance2d(bot, teamFC) < 33.0f) Follow(teamFC); } else if (urand(0, 99) < 5) @@ -3197,11 +3197,11 @@ bool BGTactics::moveToObjective(bool ignoreDist) return true; } - if (!ignoreDist && sServerFacade->IsDistanceGreaterThan(sServerFacade->GetDistance2d(bot, pos.x, pos.y), 100.0f)) + if (!ignoreDist && ServerFacade::instance().IsDistanceGreaterThan(ServerFacade::instance().GetDistance2d(bot, pos.x, pos.y), 100.0f)) { // std::ostringstream out; // out << "It is too far away! " << pos.x << ", " << pos.y << ", Distance: " << - // sServerFacade->GetDistance2d(bot, pos.x, pos.y); bot->Say(out.str(), LANG_UNIVERSAL); + // ServerFacade::instance().GetDistance2d(bot, pos.x, pos.y); bot->Say(out.str(), LANG_UNIVERSAL); return false; } @@ -3213,7 +3213,7 @@ bool BGTactics::moveToObjective(bool ignoreDist) } // std::ostringstream out; out << "Moving to objective " << pos.x << ", " << pos.y << ", Distance: " << - // sServerFacade->GetDistance2d(bot, pos.x, pos.y); bot->Say(out.str(), LANG_UNIVERSAL); + // ServerFacade::instance().GetDistance2d(bot, pos.x, pos.y); bot->Say(out.str(), LANG_UNIVERSAL); // dont increase from 1.5 will cause bugs with horde capping AV towers return MoveNear(bot->GetMapId(), pos.x, pos.y, pos.z, 1.5f); @@ -3433,7 +3433,7 @@ bool BGTactics::moveToObjectiveWp(BattleBotPath* const& currentPath, uint32 curr // out << "WP: "; // reverse ? out << currPoint << " <<< -> " << nPoint : out << currPoint << ">>> ->" << nPoint; // out << ", " << nextPoint.x << ", " << nextPoint.y << " Path Size: " << currentPath->size() << ", Dist: " << - // sServerFacade->GetDistance2d(bot, nextPoint.x, nextPoint.y); bot->Say(out.str(), LANG_UNIVERSAL); + // ServerFacade::instance().GetDistance2d(bot, nextPoint.x, nextPoint.y); bot->Say(out.str(), LANG_UNIVERSAL); return MoveTo(bot->GetMapId(), nextPoint.x + frand(-2, 2), nextPoint.y + frand(-2, 2), nextPoint.z); } @@ -4039,9 +4039,9 @@ bool BGTactics::useBuff() if (closeObjects.empty()) return false; - bool needRegen = bot->GetHealthPct() < sPlayerbotAIConfig->mediumHealth || + bool needRegen = bot->GetHealthPct() < sPlayerbotAIConfig.mediumHealth || (AI_VALUE2(bool, "has mana", "self target") && - AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig->mediumMana); + AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig.mediumMana); bool needSpeed = (bgType != BATTLEGROUND_WS || bot->HasAura(BG_WS_SPELL_WARSONG_FLAG) || bot->HasAura(BG_WS_SPELL_SILVERWING_FLAG) || bot->HasAura(BG_EY_NETHERSTORM_FLAG_SPELL)) || !(teamFlagTaken() || flagTaken()); @@ -4057,7 +4057,7 @@ bool BGTactics::useBuff() continue; // use speed buff only if close - if (sServerFacade->IsDistanceGreaterThan(sServerFacade->GetDistance2d(bot, go), + if (ServerFacade::instance().IsDistanceGreaterThan(ServerFacade::instance().GetDistance2d(bot, go), go->GetEntry() == Buff_Entries[0] ? 20.0f : 50.0f)) continue; @@ -4107,7 +4107,7 @@ uint32 BGTactics::getPlayersInArea(TeamId teamId, Position point, float range, b if (!combat && player->IsInCombat()) continue; - if (sServerFacade->GetDistance2d(player, point.GetPositionX(), point.GetPositionY()) < range) + if (ServerFacade::instance().GetDistance2d(player, point.GetPositionX(), point.GetPositionY()) < range) ++defCount; } } @@ -4191,9 +4191,9 @@ bool BGTactics::IsLockedInsideKeep() // get closest portal if (bot->GetTeamId() == TEAM_ALLIANCE && go->GetEntry() == GO_TELEPORTER_4) { - float tempDist = sServerFacade->GetDistance2d(bot, go->GetPositionX(), go->GetPositionY()); + float tempDist = ServerFacade::instance().GetDistance2d(bot, go->GetPositionX(), go->GetPositionY()); - if (sServerFacade->IsDistanceLessThan(tempDist, closestDistance)) + if (ServerFacade::instance().IsDistanceLessThan(tempDist, closestDistance)) { closestDistance = tempDist; closestPortal = go; @@ -4204,9 +4204,9 @@ bool BGTactics::IsLockedInsideKeep() // get closest portal if (bot->GetTeamId() == TEAM_HORDE && go->GetEntry() == GO_TELEPORTER_2) { - float tempDist = sServerFacade->GetDistance2d(bot, go->GetPositionX(), go->GetPositionY()); + float tempDist = ServerFacade::instance().GetDistance2d(bot, go->GetPositionX(), go->GetPositionY()); - if (sServerFacade->IsDistanceLessThan(tempDist, closestDistance)) + if (ServerFacade::instance().IsDistanceLessThan(tempDist, closestDistance)) { closestDistance = tempDist; closestPortal = go; @@ -4253,7 +4253,7 @@ bool ArenaTactics::Execute(Event event) { if (!bot->InBattleground()) { - bool IsRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot->GetGUID().GetCounter()); + bool IsRandomBot = sRandomPlayerbotMgr.IsRandomBot(bot->GetGUID().GetCounter()); botAI->ChangeStrategy("-arena", BOT_STATE_COMBAT); botAI->ChangeStrategy("-arena", BOT_STATE_NON_COMBAT); botAI->ResetStrategies(!IsRandomBot); diff --git a/src/Ai/Base/Actions/CastCustomSpellAction.cpp b/src/Ai/Base/Actions/CastCustomSpellAction.cpp index 417ffb50d3..2ec7210d29 100644 --- a/src/Ai/Base/Actions/CastCustomSpellAction.cpp +++ b/src/Ai/Base/Actions/CastCustomSpellAction.cpp @@ -130,10 +130,10 @@ bool CastCustomSpellAction::Execute(Event event) return false; } - if (target != bot && !bot->HasInArc(CAST_ANGLE_IN_FRONT, target, sPlayerbotAIConfig->sightDistance)) + if (target != bot && !bot->HasInArc(CAST_ANGLE_IN_FRONT, target, sPlayerbotAIConfig.sightDistance)) { - sServerFacade->SetFacingTo(bot, target); - botAI->SetNextCheckDelay(sPlayerbotAIConfig->reactDelay); + ServerFacade::instance().SetFacingTo(bot, target); + botAI->SetNextCheckDelay(sPlayerbotAIConfig.reactDelay); msg << "cast " << text; botAI->HandleCommand(CHAT_MSG_WHISPER, msg.str(), master); @@ -286,7 +286,7 @@ bool CastRandomSpellAction::Execute(Event event) if (isCast) { - if (MultiCast && ((wo && bot->HasInArc(CAST_ANGLE_IN_FRONT, wo, sPlayerbotAIConfig->sightDistance)))) + if (MultiCast && ((wo && bot->HasInArc(CAST_ANGLE_IN_FRONT, wo, sPlayerbotAIConfig.sightDistance)))) { std::ostringstream cmd; cmd << "castnc " << chat->FormatWorldobject(wo) + " " << spellId << " " << 19; diff --git a/src/Ai/Base/Actions/ChangeStrategyAction.cpp b/src/Ai/Base/Actions/ChangeStrategyAction.cpp index d17cd005d3..b4fe5faaf2 100644 --- a/src/Ai/Base/Actions/ChangeStrategyAction.cpp +++ b/src/Ai/Base/Actions/ChangeStrategyAction.cpp @@ -24,7 +24,7 @@ bool ChangeCombatStrategyAction::Execute(Event event) case '+': case '-': case '~': - sPlayerbotRepository->Save(botAI); + PlayerbotRepository::instance().Save(botAI); break; case '?': break; @@ -40,7 +40,7 @@ bool ChangeNonCombatStrategyAction::Execute(Event event) std::string const text = event.getParam(); uint32 account = bot->GetSession()->GetAccountId(); - if (sPlayerbotAIConfig->IsInRandomAccountList(account) && botAI->GetMaster() && + if (sPlayerbotAIConfig.IsInRandomAccountList(account) && botAI->GetMaster() && botAI->GetMaster()->GetSession()->GetSecurity() < SEC_GAMEMASTER) { if (text.find("loot") != std::string::npos || text.find("gather") != std::string::npos) @@ -62,7 +62,7 @@ bool ChangeNonCombatStrategyAction::Execute(Event event) case '+': case '-': case '~': - sPlayerbotRepository->Save(botAI); + PlayerbotRepository::instance().Save(botAI); break; case '?': break; diff --git a/src/Ai/Base/Actions/ChangeTalentsAction.cpp b/src/Ai/Base/Actions/ChangeTalentsAction.cpp index c50e4a9274..9b57a201a0 100644 --- a/src/Ai/Base/Actions/ChangeTalentsAction.cpp +++ b/src/Ai/Base/Actions/ChangeTalentsAction.cpp @@ -110,20 +110,20 @@ std::string ChangeTalentsAction::SpecList() std::ostringstream out; for (int specNo = 0; specNo < MAX_SPECNO; ++specNo) { - if (sPlayerbotAIConfig->premadeSpecName[cls][specNo].size() == 0) + if (sPlayerbotAIConfig.premadeSpecName[cls][specNo].size() == 0) { break; } specFound++; std::ostringstream out; - std::vector> parsed = sPlayerbotAIConfig->parsedSpecLinkOrder[cls][specNo][80]; + std::vector> parsed = sPlayerbotAIConfig.parsedSpecLinkOrder[cls][specNo][80]; std::unordered_map tabCount; tabCount[0] = tabCount[1] = tabCount[2] = 0; for (auto& item : parsed) { tabCount[item[0]] += item[3]; } - out << specFound << ". " << sPlayerbotAIConfig->premadeSpecName[cls][specNo] << " ("; + out << specFound << ". " << sPlayerbotAIConfig.premadeSpecName[cls][specNo] << " ("; out << tabCount[0] << "-" << tabCount[1] << "-" << tabCount[2] << ")"; botAI->TellMasterNoFacing(out.str()); } @@ -137,11 +137,11 @@ std::string ChangeTalentsAction::SpecPick(std::string param) // int specFound = 0; //not used, line marked for removal. for (int specNo = 0; specNo < MAX_SPECNO; ++specNo) { - if (sPlayerbotAIConfig->premadeSpecName[cls][specNo].size() == 0) + if (sPlayerbotAIConfig.premadeSpecName[cls][specNo].size() == 0) { break; } - if (sPlayerbotAIConfig->premadeSpecName[cls][specNo] == param) + if (sPlayerbotAIConfig.premadeSpecName[cls][specNo] == param) { PlayerbotFactory::InitTalentsBySpecNo(bot, specNo, true); @@ -149,7 +149,7 @@ std::string ChangeTalentsAction::SpecPick(std::string param) factory.InitGlyphs(false); std::ostringstream out; - out << "Picking " << sPlayerbotAIConfig->premadeSpecName[cls][specNo]; + out << "Picking " << sPlayerbotAIConfig.premadeSpecName[cls][specNo]; return out.str(); } } @@ -176,7 +176,7 @@ std::string ChangeTalentsAction::SpecApply(std::string param) // std::vector ChangeTalentsAction::getPremadePaths(std::string const findName) // { // std::vector ret; -// // for (auto& path : sPlayerbotAIConfig->classSpecs[bot->getClass()].talentPath) +// // for (auto& path : sPlayerbotAIConfig.classSpecs[bot->getClass()].talentPath) // // { // // if (findName.empty() || path.name.find(findName) != std::string::npos) // // { @@ -191,7 +191,7 @@ std::string ChangeTalentsAction::SpecApply(std::string param) // { // std::vector ret; -// // for (auto& path : sPlayerbotAIConfig->classSpecs[bot->getClass()].talentPath) +// // for (auto& path : sPlayerbotAIConfig.classSpecs[bot->getClass()].talentPath) // // { // // TalentSpec newSpec = *GetBestPremadeSpec(path.id); // // newSpec.CropTalents(bot->GetLevel()); @@ -206,7 +206,7 @@ std::string ChangeTalentsAction::SpecApply(std::string param) // TalentPath* ChangeTalentsAction::getPremadePath(uint32 id) // { -// // for (auto& path : sPlayerbotAIConfig->classSpecs[bot->getClass()].talentPath) +// // for (auto& path : sPlayerbotAIConfig.classSpecs[bot->getClass()].talentPath) // // { // // if (id == path.id) // // { @@ -214,7 +214,7 @@ std::string ChangeTalentsAction::SpecApply(std::string param) // // } // // } -// // return &sPlayerbotAIConfig->classSpecs[bot->getClass()].talentPath[0]; +// // return &sPlayerbotAIConfig.classSpecs[bot->getClass()].talentPath[0]; // return nullptr; // } @@ -270,9 +270,9 @@ std::string ChangeTalentsAction::SpecApply(std::string param) // return false; // } -// uint32 specNo = sRandomPlayerbotMgr->GetValue(bot->GetGUID().GetCounter(), "specNo"); +// uint32 specNo = sRandomPlayerbotMgr.GetValue(bot->GetGUID().GetCounter(), "specNo"); // uint32 specId = specNo - 1; -// std::string specLink = sRandomPlayerbotMgr->GetData(bot->GetGUID().GetCounter(), "specLink"); +// std::string specLink = sRandomPlayerbotMgr.GetData(bot->GetGUID().GetCounter(), "specLink"); // //Continue the current spec // if (specNo > 0) @@ -319,15 +319,15 @@ std::string ChangeTalentsAction::SpecApply(std::string param) // specId = -1; // // specLink = ""; // } -// else if (paths.size() > 1 && false/*!sPlayerbotAIConfig->autoPickTalents*/ && -// !sRandomPlayerbotMgr->IsRandomBot(bot)) +// else if (paths.size() > 1 && false/*!sPlayerbotAIConfig.autoPickTalents*/ && +// !sRandomPlayerbotMgr.IsRandomBot(bot)) // { // *out << "Found multiple specs: "; // listPremadePaths(paths, out); // } // else // { -// specId = PickPremadePath(paths, sRandomPlayerbotMgr->IsRandomBot(bot))->id; +// specId = PickPremadePath(paths, sRandomPlayerbotMgr.IsRandomBot(bot))->id; // TalentSpec newSpec = *GetBestPremadeSpec(specId); // specLink = newSpec.GetTalentLink(); // newSpec.CropTalents(bot->GetLevel()); @@ -341,12 +341,12 @@ std::string ChangeTalentsAction::SpecApply(std::string param) // } // } -// sRandomPlayerbotMgr->SetValue(bot->GetGUID().GetCounter(), "specNo", specId + 1); +// sRandomPlayerbotMgr.SetValue(bot->GetGUID().GetCounter(), "specNo", specId + 1); // if (!specLink.empty() && specId == -1) -// sRandomPlayerbotMgr->SetValue(bot->GetGUID().GetCounter(), "specLink", 1, specLink); +// sRandomPlayerbotMgr.SetValue(bot->GetGUID().GetCounter(), "specLink", 1, specLink); // else -// sRandomPlayerbotMgr->SetValue(bot->GetGUID().GetCounter(), "specLink", 0); +// sRandomPlayerbotMgr.SetValue(bot->GetGUID().GetCounter(), "specLink", 0); // return (specNo == 0) ? false : true; // } @@ -364,7 +364,7 @@ std::string ChangeTalentsAction::SpecApply(std::string param) // if (path->talentSpec.size()) // return &path->talentSpec.back(); -// // return &sPlayerbotAIConfig->classSpecs[bot->getClassMask()].baseSpec; +// // return &sPlayerbotAIConfig.classSpecs[bot->getClassMask()].baseSpec; // return nullptr; // } @@ -372,7 +372,7 @@ bool AutoSetTalentsAction::Execute(Event event) { std::ostringstream out; - if (!sPlayerbotAIConfig->autoPickTalents || !sRandomPlayerbotMgr->IsRandomBot(bot)) + if (!sPlayerbotAIConfig.autoPickTalents || !sRandomPlayerbotMgr.IsRandomBot(bot)) return false; if (bot->GetFreeTalentPoints() <= 0) diff --git a/src/Ai/Base/Actions/ChatShortcutActions.cpp b/src/Ai/Base/Actions/ChatShortcutActions.cpp index 02c306b8f7..037787bab5 100644 --- a/src/Ai/Base/Actions/ChatShortcutActions.cpp +++ b/src/Ai/Base/Actions/ChatShortcutActions.cpp @@ -96,7 +96,7 @@ bool FollowChatShortcutAction::Execute(Event event) /* Default mechanics takes care of this now. if (bot->GetMapId() != master->GetMapId() || (master && bot->GetDistance(master) > - sPlayerbotAIConfig->sightDistance)) + sPlayerbotAIConfig.sightDistance)) { if (bot->isDead()) { @@ -161,7 +161,7 @@ bool FleeChatShortcutAction::Execute(Event event) ResetReturnPosition(); ResetStayPosition(); - if (bot->GetMapId() != master->GetMapId() || bot->GetDistance(master) > sPlayerbotAIConfig->sightDistance) + if (bot->GetMapId() != master->GetMapId() || bot->GetDistance(master) > sPlayerbotAIConfig.sightDistance) { botAI->TellError("I will not flee with you - too far away"); return true; @@ -241,6 +241,19 @@ bool MaxDpsChatShortcutAction::Execute(Event event) return true; } +bool NaxxChatShortcutAction::Execute(Event event) +{ + Player* master = GetMaster(); + if (!master) + return false; + + botAI->Reset(); + botAI->ChangeStrategy("+naxx", BOT_STATE_NON_COMBAT); + botAI->ChangeStrategy("+naxx", BOT_STATE_COMBAT); + botAI->TellMasterNoFacing("Add Naxx Strategies!"); + return true; +} + bool BwlChatShortcutAction::Execute(Event event) { Player* master = GetMaster(); diff --git a/src/Ai/Base/Actions/ChatShortcutActions.h b/src/Ai/Base/Actions/ChatShortcutActions.h index b7e4a9e963..fa941a4c86 100644 --- a/src/Ai/Base/Actions/ChatShortcutActions.h +++ b/src/Ai/Base/Actions/ChatShortcutActions.h @@ -85,6 +85,13 @@ class MaxDpsChatShortcutAction : public Action bool Execute(Event event) override; }; +class NaxxChatShortcutAction : public Action +{ +public: + NaxxChatShortcutAction(PlayerbotAI* ai) : Action(ai, "naxx chat shortcut") {} + virtual bool Execute(Event event); +}; + class BwlChatShortcutAction : public Action { public: diff --git a/src/Ai/Base/Actions/CheatAction.cpp b/src/Ai/Base/Actions/CheatAction.cpp index b3f4ec5cf7..790134e953 100644 --- a/src/Ai/Base/Actions/CheatAction.cpp +++ b/src/Ai/Base/Actions/CheatAction.cpp @@ -86,7 +86,7 @@ void CheatAction::ListCheats() for (int i = 0; i < log2((uint32)BotCheatMask::maxMask); i++) { BotCheatMask cheatMask = BotCheatMask(1 << i); - if ((uint32)cheatMask & (uint32)sPlayerbotAIConfig->botCheatMask) + if ((uint32)cheatMask & (uint32)sPlayerbotAIConfig.botCheatMask) out << "[conf:" << GetCheatName(BotCheatMask(cheatMask)) << "]"; else if (botAI->HasCheat(cheatMask)) out << "[" << GetCheatName(BotCheatMask(cheatMask)) << "]"; diff --git a/src/Ai/Base/Actions/CheckMailAction.cpp b/src/Ai/Base/Actions/CheckMailAction.cpp index 85df168f58..f9c70ff11f 100644 --- a/src/Ai/Base/Actions/CheckMailAction.cpp +++ b/src/Ai/Base/Actions/CheckMailAction.cpp @@ -28,7 +28,7 @@ bool CheckMailAction::Execute(Event event) continue; uint32 account = owner->GetSession()->GetAccountId(); - if (sPlayerbotAIConfig->IsInRandomAccountList(account)) + if (sPlayerbotAIConfig.IsInRandomAccountList(account)) continue; ProcessMail(mail, owner, trans); @@ -80,7 +80,7 @@ void CheckMailAction::ProcessMail(Mail* mail, Player* owner, CharacterDatabaseTr if (!item) continue; - if (!sGuildTaskMgr->CheckItemTask(i->item_template, item->GetCount(), owner, bot, true)) + if (!GuildTaskMgr::instance().CheckItemTask(i->item_template, item->GetCount(), owner, bot, true)) { std::ostringstream body; body << "Hello, " << owner->GetName() << ",\n"; diff --git a/src/Ai/Base/Actions/CheckMountStateAction.cpp b/src/Ai/Base/Actions/CheckMountStateAction.cpp index bf7a3a169a..5ab7cc0f92 100644 --- a/src/Ai/Base/Actions/CheckMountStateAction.cpp +++ b/src/Ai/Base/Actions/CheckMountStateAction.cpp @@ -89,7 +89,7 @@ bool CheckMountStateAction::isUseful() return false; // Not useful when level lower than minimum required - if (bot->GetLevel() < sPlayerbotAIConfig->useGroundMountAtMinLevel) + if (bot->GetLevel() < sPlayerbotAIConfig.useGroundMountAtMinLevel) return false; // Allow mounting while transformed only if the form allows it @@ -402,7 +402,7 @@ float CheckMountStateAction::CalculateDismountDistance() const // Warrior bots should dismount far enough to charge (because it's important for generating some initial rage), // a real player would be riding toward enemy mashing the charge key but the bots won't cast charge while mounted. bool isMelee = PlayerbotAI::IsMelee(bot); - float dismountDistance = isMelee ? sPlayerbotAIConfig->meleeDistance + 2.0f : sPlayerbotAIConfig->spellDistance + 2.0f; + float dismountDistance = isMelee ? sPlayerbotAIConfig.meleeDistance + 2.0f : sPlayerbotAIConfig.spellDistance + 2.0f; return bot->getClass() == CLASS_WARRIOR ? std::max(18.0f, dismountDistance) : dismountDistance; } @@ -413,7 +413,7 @@ float CheckMountStateAction::CalculateMountDistance() const // seconds: // 21 / 7 = 21 / 14 + 1.5 = 3 (7 = dismounted speed 14 = epic-mount speed 1.5 = mount-spell cast time) bool isMelee = PlayerbotAI::IsMelee(bot); - float baseDistance = isMelee ? sPlayerbotAIConfig->meleeDistance + 10.0f : sPlayerbotAIConfig->spellDistance + 10.0f; + float baseDistance = isMelee ? sPlayerbotAIConfig.meleeDistance + 10.0f : sPlayerbotAIConfig.spellDistance + 10.0f; return std::max(21.0f, baseDistance); } @@ -440,7 +440,7 @@ int32 CheckMountStateAction::CalculateMasterMountSpeed(Player* master, const Mou int32 ridingSkill = bot->GetPureSkillValue(SKILL_RIDING); int32 botLevel = bot->GetLevel(); - if (ridingSkill <= 75 && botLevel < static_cast(sPlayerbotAIConfig->useFastGroundMountAtMinLevel)) + if (ridingSkill <= 75 && botLevel < static_cast(sPlayerbotAIConfig.useFastGroundMountAtMinLevel)) return 59; // If there is a master and bot not in BG, use master's aura effects. diff --git a/src/Ai/Base/Actions/CheckValuesAction.cpp b/src/Ai/Base/Actions/CheckValuesAction.cpp index 1fc0d4c3a1..7c64b7c513 100644 --- a/src/Ai/Base/Actions/CheckValuesAction.cpp +++ b/src/Ai/Base/Actions/CheckValuesAction.cpp @@ -20,7 +20,7 @@ bool CheckValuesAction::Execute(Event event) if (botAI->HasStrategy("map", BOT_STATE_NON_COMBAT) || botAI->HasStrategy("map full", BOT_STATE_NON_COMBAT)) { - sTravelNodeMap->manageNodes(bot, botAI->HasStrategy("map full", BOT_STATE_NON_COMBAT)); + TravelNodeMap::instance().manageNodes(bot, botAI->HasStrategy("map full", BOT_STATE_NON_COMBAT)); } GuidVector possible_targets = *context->GetValue("possible targets"); diff --git a/src/Ai/Base/Actions/ChooseRpgTargetAction.cpp b/src/Ai/Base/Actions/ChooseRpgTargetAction.cpp index a888aa14ee..7d83c2b2bc 100644 --- a/src/Ai/Base/Actions/ChooseRpgTargetAction.cpp +++ b/src/Ai/Base/Actions/ChooseRpgTargetAction.cpp @@ -248,7 +248,7 @@ bool ChooseRpgTargetAction::Execute(Event event) } std::mt19937 gen(time(0)); - sTravelMgr->weighted_shuffle(guidps.begin(), guidps.end(), relevances.begin(), relevances.end(), gen); + TravelMgr::instance().weighted_shuffle(guidps.begin(), guidps.end(), relevances.begin(), relevances.end(), gen); GuidPosition guidP(guidps.front()); if (!guidP) @@ -279,7 +279,7 @@ bool ChooseRpgTargetAction::isUseful() GuidPosition guidP = AI_VALUE(GuidPosition, "rpg target"); - if (guidP && guidP.distance(bot) < sPlayerbotAIConfig->reactDistance * 2) + if (guidP && guidP.distance(bot) < sPlayerbotAIConfig.reactDistance * 2) return false; // TravelTarget* travelTarget = AI_VALUE(TravelTarget*, "travel target"); //not used, line marked for removal. @@ -330,7 +330,7 @@ bool ChooseRpgTargetAction::isFollowValid(Player* bot, WorldPosition pos) if (!botAI->HasStrategy("follow", BOT_STATE_NON_COMBAT)) return true; - if (bot->GetDistance(groupLeader) > sPlayerbotAIConfig->rpgDistance * 2) + if (bot->GetDistance(groupLeader) > sPlayerbotAIConfig.rpgDistance * 2) return false; Formation* formation = AI_VALUE(Formation*, "formation"); @@ -340,7 +340,7 @@ bool ChooseRpgTargetAction::isFollowValid(Player* bot, WorldPosition pos) { Player* player = groupLeader; if (groupLeader && !groupLeader->isMoving() || - PAI_VALUE(WorldPosition, "last long move").distance(pos) < sPlayerbotAIConfig->reactDistance) + PAI_VALUE(WorldPosition, "last long move").distance(pos) < sPlayerbotAIConfig.reactDistance) return true; } diff --git a/src/Ai/Base/Actions/ChooseTargetActions.cpp b/src/Ai/Base/Actions/ChooseTargetActions.cpp index ab533e7136..200094c900 100644 --- a/src/Ai/Base/Actions/ChooseTargetActions.cpp +++ b/src/Ai/Base/Actions/ChooseTargetActions.cpp @@ -20,13 +20,13 @@ bool AttackEnemyPlayerAction::isUseful() if (PlayerHasFlag::IsCapturingFlag(bot)) return false; - return !sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()); + return !sPlayerbotAIConfig.IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()); } bool AttackEnemyFlagCarrierAction::isUseful() { Unit* target = context->GetValue("enemy flag carrier")->Get(); - return target && sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, target), 100.0f) && + return target && ServerFacade::instance().IsDistanceLessOrEqualThan(ServerFacade::instance().GetDistance2d(bot, target), 100.0f) && PlayerHasFlag::IsCapturingFlag(bot); } diff --git a/src/Ai/Base/Actions/ChooseTravelTargetAction.cpp b/src/Ai/Base/Actions/ChooseTravelTargetAction.cpp index cf6dddd40c..0f75a30798 100644 --- a/src/Ai/Base/Actions/ChooseTravelTargetAction.cpp +++ b/src/Ai/Base/Actions/ChooseTravelTargetAction.cpp @@ -366,7 +366,7 @@ bool ChooseTravelTargetAction::getBestDestination(std::vector availablePoints = - sTravelMgr->getNextPoint(&botLocation, *activePoints); // Pick a good point. + TravelMgr::instance().getNextPoint(&botLocation, *activePoints); // Pick a good point. if (availablePoints.empty()) // No points available. return false; @@ -488,7 +488,7 @@ bool ChooseTravelTargetAction::SetQuestTarget(TravelTarget* target, bool onlyCom if (newQuests) { // Prefer new quests near the player at lower levels. - activeDestinations = sTravelMgr->getQuestTravelDestinations(bot, -1, true, false, 400 + bot->GetLevel() * 10); + activeDestinations = TravelMgr::instance().getQuestTravelDestinations(bot, -1, true, false, 400 + bot->GetLevel() * 10); } if (activeQuests || completedQuests) { @@ -510,7 +510,7 @@ bool ChooseTravelTargetAction::SetQuestTarget(TravelTarget* target, bool onlyCom continue; //Find quest takers or objectives - std::vector questDestinations = sTravelMgr->getQuestTravelDestinations(bot, questId, true, false, 0); + std::vector questDestinations = TravelMgr::instance().getQuestTravelDestinations(bot, questId, true, false, 0); if (onlyClassQuest && activeDestinations.size() && questDestinations.size()) //Only do class quests if we have any. { @@ -525,7 +525,7 @@ bool ChooseTravelTargetAction::SetQuestTarget(TravelTarget* target, bool onlyCom } } if (newQuests && activeDestinations.empty()) - activeDestinations = sTravelMgr->getQuestTravelDestinations(bot, -1, true, false); //If we really don't find any new quests look futher away. + activeDestinations = TravelMgr::instance().getQuestTravelDestinations(bot, -1, true, false); //If we really don't find any new quests look futher away. if (botAI->HasStrategy("debug travel", BotState::BOT_STATE_NON_COMBAT)) botAI->TellMasterNoFacing(std::to_string(activeDestinations.size()) + " quest destinations found."); @@ -547,7 +547,7 @@ bool ChooseTravelTargetAction::SetNewQuestTarget(TravelTarget* target) // Find quest givers. std::vector TravelDestinations = - sTravelMgr->getQuestTravelDestinations(bot, -1, botAI->HasRealPlayerMaster()); + TravelMgr::instance().getQuestTravelDestinations(bot, -1, botAI->HasRealPlayerMaster()); activeDestinations.insert(activeDestinations.end(), TravelDestinations.begin(), TravelDestinations.end()); @@ -576,7 +576,7 @@ bool ChooseTravelTargetAction::SetRpgTarget(TravelTarget* target) // Find rpg npcs std::vector TravelDestinations = - sTravelMgr->getRpgTravelDestinations(bot, botAI->HasRealPlayerMaster()); + TravelMgr::instance().getRpgTravelDestinations(bot, botAI->HasRealPlayerMaster()); activeDestinations.insert(activeDestinations.end(), TravelDestinations.begin(), TravelDestinations.end()); @@ -605,7 +605,7 @@ bool ChooseTravelTargetAction::SetGrindTarget(TravelTarget* target) // Find grind mobs. std::vector TravelDestinations = - sTravelMgr->getGrindTravelDestinations(bot, botAI->HasRealPlayerMaster()); + TravelMgr::instance().getGrindTravelDestinations(bot, botAI->HasRealPlayerMaster()); activeDestinations.insert(activeDestinations.end(), TravelDestinations.begin(), TravelDestinations.end()); @@ -634,7 +634,7 @@ bool ChooseTravelTargetAction::SetBossTarget(TravelTarget* target) // Find boss mobs. std::vector TravelDestinations = - sTravelMgr->getBossTravelDestinations(bot, botAI->HasRealPlayerMaster()); + TravelMgr::instance().getBossTravelDestinations(bot, botAI->HasRealPlayerMaster()); activeDestinations.insert(activeDestinations.end(), TravelDestinations.begin(), TravelDestinations.end()); @@ -662,7 +662,7 @@ bool ChooseTravelTargetAction::SetExploreTarget(TravelTarget* target) WorldPosition botLocation(bot); // Find quest givers. - std::vector TravelDestinations = sTravelMgr->getExploreTravelDestinations(bot, true, true); + std::vector TravelDestinations = TravelMgr::instance().getExploreTravelDestinations(bot, true, true); activeDestinations.insert(activeDestinations.end(), TravelDestinations.begin(), TravelDestinations.end()); /* @@ -681,7 +681,7 @@ bool ChooseTravelTargetAction::SetExploreTarget(TravelTarget* target) if (activePoints.empty()) { - TravelDestinations = sTravelMgr->getExploreTravelDestinations(bot, botAI->HasRealPlayerMaster()); + TravelDestinations = TravelMgr::instance().getExploreTravelDestinations(bot, botAI->HasRealPlayerMaster()); for (auto& activeTarget : activeDestinations) { @@ -710,7 +710,7 @@ bool ChooseTravelTargetAction::SetNpcFlagTarget(TravelTarget* target, std::vecto std::vector dests; - for (auto& d : sTravelMgr->getRpgTravelDestinations(bot, true, true)) + for (auto& d : TravelMgr::instance().getRpgTravelDestinations(bot, true, true)) { if (!d->getEntry()) continue; @@ -813,7 +813,7 @@ std::vector TravelMgr::getBossTravelDestinations(Player* bot bool ChooseTravelTargetAction::SetNullTarget(TravelTarget* target) { - target->setTarget(sTravelMgr->nullTravelDestination, sTravelMgr->nullWorldPosition, true); + target->setTarget(TravelMgr::instance().nullTravelDestination, TravelMgr::instance().nullWorldPosition, true); return true; } @@ -832,7 +832,7 @@ TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::s //Quests if (quests) { - for (auto& d : sTravelMgr->getQuestTravelDestinations(bot, 0, true, true)) + for (auto& d : TravelMgr::instance().getQuestTravelDestinations(bot, 0, true, true)) { if (strstri(d->getTitle().c_str(), name.c_str())) dests.push_back(d); @@ -842,7 +842,7 @@ TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::s //Zones if (zones) { - for (auto& d : sTravelMgr->getExploreTravelDestinations(bot, true, true)) + for (auto& d : TravelMgr::instance().getExploreTravelDestinations(bot, true, true)) { if (strstri(d->getTitle().c_str(), name.c_str())) dests.push_back(d); @@ -852,7 +852,7 @@ TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::s //Npcs if (npcs) { - for (auto& d : sTravelMgr->getRpgTravelDestinations(bot, true, true)) + for (auto& d : TravelMgr::instance().getRpgTravelDestinations(bot, true, true)) { if (strstri(d->getTitle().c_str(), name.c_str())) dests.push_back(d); @@ -862,7 +862,7 @@ TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::s //Mobs if (mobs) { - for (auto& d : sTravelMgr->getGrindTravelDestinations(bot, true, true, 5000.0f)) + for (auto& d : TravelMgr::instance().getGrindTravelDestinations(bot, true, true, 5000.0f)) { if (strstri(d->getTitle().c_str(), name.c_str())) dests.push_back(d); @@ -872,7 +872,7 @@ TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::s //Bosses if (bosses) { - for (auto& d : sTravelMgr->getBossTravelDestinations(bot, true, true)) + for (auto& d : TravelMgr::instance().getBossTravelDestinations(bot, true, true)) { if (strstri(d->getTitle().c_str(), name.c_str())) dests.push_back(d); diff --git a/src/Ai/Base/Actions/CombatActions.cpp b/src/Ai/Base/Actions/CombatActions.cpp index fe29a11b4f..2f687d5e03 100644 --- a/src/Ai/Base/Actions/CombatActions.cpp +++ b/src/Ai/Base/Actions/CombatActions.cpp @@ -25,7 +25,7 @@ bool SwitchToMeleeAction::isUseful() return botAI->HasStrategy("ranged", BOT_STATE_COMBAT) && ((bot->IsInCombat() && target && (target->GetVictim() == bot && (!bot->GetGroup() || lastFlee) && - sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "current target"), 8.0f))) || + ServerFacade::instance().IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "current target"), 8.0f))) || (!bot->IsInCombat())); } @@ -47,7 +47,7 @@ bool SwitchToRangedAction::isUseful() return botAI->HasStrategy("close", BOT_STATE_COMBAT) && hasAmmo && ((bot->IsInCombat() && target && ((target->GetVictim() != bot || target->GetTarget() != bot->GetGUID()) || - sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "current target"), 8.0f))) || + ServerFacade::instance().IsDistanceGreaterThan(AI_VALUE2(float, "distance", "current target"), 8.0f))) || (!bot->IsInCombat())); } diff --git a/src/Ai/Base/Actions/DebugAction.cpp b/src/Ai/Base/Actions/DebugAction.cpp index 11a0bf26a0..578ece17c4 100644 --- a/src/Ai/Base/Actions/DebugAction.cpp +++ b/src/Ai/Base/Actions/DebugAction.cpp @@ -19,7 +19,7 @@ bool DebugAction::Execute(Event event) if (text == "scan") { - sPlayerbotAIConfig->openLog("scan.csv", "w"); + sPlayerbotAIConfig.openLog("scan.csv", "w"); uint32 i = 0; for (auto p : WorldPosition().getCreaturesNear()) @@ -36,15 +36,15 @@ bool DebugAction::Execute(Event event) pos.printWKT(out); - sPlayerbotAIConfig->log("scan.csv", out.str().c_str()); + sPlayerbotAIConfig.log("scan.csv", out.str().c_str()); if (zoneId == 0 && areaId == 0) { - sPlayerbotAIConfig->log("x", out.str().c_str()); + sPlayerbotAIConfig.log("x", out.str().c_str()); } else { - sPlayerbotAIConfig->log("y", out.str().c_str()); + sPlayerbotAIConfig.log("y", out.str().c_str()); } i = zoneId; @@ -53,8 +53,8 @@ bool DebugAction::Execute(Event event) } else if (text.find("printmap") != std::string::npos) { - sTravelNodeMap->printMap(); - sTravelNodeMap->printNodeStore(); + TravelNodeMap::instance().printMap(); + TravelNodeMap::instance().printNodeStore(); return true; } else if (text.find("travel ") != std::string::npos) @@ -72,7 +72,7 @@ bool DebugAction::Execute(Event event) return false; std::vector beginPath, endPath; - TravelNodeRoute route = sTravelNodeMap->getRoute(botPos, *points.front(), beginPath, bot); + TravelNodeRoute route = TravelNodeMap::instance().getRoute(botPos, *points.front(), beginPath, bot); std::ostringstream out; out << "Traveling to " << dest->getTitle() << ": "; @@ -108,7 +108,7 @@ bool DebugAction::Execute(Event event) out << quest->GetTitle() << ": "; - QuestContainer* cont = sTravelMgr->quests[questId]; + QuestContainer* cont = TravelMgr::instance().quests[questId]; for (auto g : cont->questGivers) { @@ -135,11 +135,11 @@ bool DebugAction::Execute(Event event) else if (text.find("quest") != std::string::npos) { std::ostringstream out; - out << sTravelMgr->quests.size() << " quests "; + out << TravelMgr::instance().quests.size() << " quests "; uint32 noT = 0, noG = 0, noO = 0; - for (auto q : sTravelMgr->quests) + for (auto q : TravelMgr::instance().quests) { if (q.second->questGivers.empty()) noG++; @@ -164,7 +164,7 @@ bool DebugAction::Execute(Event event) // uint32 noT = 0, noG = 0, noO = 0; //not used, line marked for removal. - for (auto q : sTravelMgr->quests) + for (auto q : TravelMgr::instance().quests) { Quest const* quest = sObjectMgr->GetQuestTemplate(q.first); @@ -194,16 +194,16 @@ bool DebugAction::Execute(Event event) std::string const name = "USER:" + text.substr(9); - /* TravelNode* startNode = */ sTravelNodeMap->addNode(pos, name, false, false); // startNode not used, but addNode as side effect, fragment marked for removal. + /* TravelNode* startNode = */ TravelNodeMap::instance().addNode(pos, name, false, false); // startNode not used, but addNode as side effect, fragment marked for removal. - for (auto& endNode : sTravelNodeMap->getNodes(pos, 2000)) + for (auto& endNode : TravelNodeMap::instance().getNodes(pos, 2000)) { endNode->setLinked(false); } botAI->TellMasterNoFacing("Node " + name + " created."); - sTravelNodeMap->setHasToGen(); + TravelNodeMap::instance().setHasToGen(); return true; } @@ -211,7 +211,7 @@ bool DebugAction::Execute(Event event) { WorldPosition pos(bot); - TravelNode* startNode = sTravelNodeMap->getNode(pos, nullptr, 50); + TravelNode* startNode = TravelNodeMap::instance().getNode(pos, nullptr, 50); if (!startNode) return false; @@ -221,24 +221,24 @@ bool DebugAction::Execute(Event event) botAI->TellMasterNoFacing("Node can not be removed."); } - sTravelNodeMap->m_nMapMtx.lock(); - sTravelNodeMap->removeNode(startNode); + TravelNodeMap::instance().m_nMapMtx.lock(); + TravelNodeMap::instance().removeNode(startNode); botAI->TellMasterNoFacing("Node removed."); - sTravelNodeMap->m_nMapMtx.unlock(); + TravelNodeMap::instance().m_nMapMtx.unlock(); - sTravelNodeMap->setHasToGen(); + TravelNodeMap::instance().setHasToGen(); return true; } else if (text.find("reset node") != std::string::npos) { - for (auto& node : sTravelNodeMap->getNodes()) + for (auto& node : TravelNodeMap::instance().getNodes()) node->setLinked(false); return true; } else if (text.find("reset path") != std::string::npos) { - for (auto& node : sTravelNodeMap->getNodes()) + for (auto& node : TravelNodeMap::instance().getNodes()) for (auto& path : *node->getLinks()) node->removeLinkTo(path.first, true); return true; @@ -246,23 +246,23 @@ bool DebugAction::Execute(Event event) else if (text.find("gen node") != std::string::npos) { // Pathfinder - sTravelNodeMap->generateNodes(); + TravelNodeMap::instance().generateNodes(); return true; } else if (text.find("gen path") != std::string::npos) { - sTravelNodeMap->generatePaths(); + TravelNodeMap::instance().generatePaths(); return true; } else if (text.find("crop path") != std::string::npos) { - sTravelNodeMap->removeUselessPaths(); + TravelNodeMap::instance().removeUselessPaths(); return true; } else if (text.find("save node") != std::string::npos) { - sTravelNodeMap->printNodeStore(); - sTravelNodeMap->saveNodeStore(); + TravelNodeMap::instance().printNodeStore(); + TravelNodeMap::instance().saveNodeStore(); return true; } else if (text.find("load node") != std::string::npos) @@ -270,8 +270,8 @@ bool DebugAction::Execute(Event event) std::thread t( [] { - sTravelNodeMap->removeNodes(); - sTravelNodeMap->loadNodeStore(); + TravelNodeMap::instance().removeNodes(); + TravelNodeMap::instance().loadNodeStore(); }); t.detach(); @@ -282,7 +282,7 @@ bool DebugAction::Execute(Event event) { WorldPosition pos(bot); - std::vector nodes = sTravelNodeMap->getNodes(pos, 500); + std::vector nodes = TravelNodeMap::instance().getNodes(pos, 500); for (auto& node : nodes) { diff --git a/src/Ai/Base/Actions/DelayAction.cpp b/src/Ai/Base/Actions/DelayAction.cpp index 8d47912fe4..b47b6898d1 100644 --- a/src/Ai/Base/Actions/DelayAction.cpp +++ b/src/Ai/Base/Actions/DelayAction.cpp @@ -10,7 +10,7 @@ bool DelayAction::Execute(Event event) { - uint32 delay = sPlayerbotAIConfig->passiveDelay + sPlayerbotAIConfig->globalCoolDown; + uint32 delay = sPlayerbotAIConfig.passiveDelay + sPlayerbotAIConfig.globalCoolDown; botAI->SetNextCheckDelay(delay); diff --git a/src/Ai/Base/Actions/DropQuestAction.cpp b/src/Ai/Base/Actions/DropQuestAction.cpp index 48e571eb3e..b3cba9c560 100644 --- a/src/Ai/Base/Actions/DropQuestAction.cpp +++ b/src/Ai/Base/Actions/DropQuestAction.cpp @@ -67,7 +67,7 @@ bool CleanQuestLogAction::Execute(Event event) return false; } - if (!sPlayerbotAIConfig->dropObsoleteQuests) + if (!sPlayerbotAIConfig.dropObsoleteQuests) { return false; } diff --git a/src/Ai/Base/Actions/EmoteAction.cpp b/src/Ai/Base/Actions/EmoteAction.cpp index 1770ca2b75..197cc436b1 100644 --- a/src/Ai/Base/Actions/EmoteAction.cpp +++ b/src/Ai/Base/Actions/EmoteAction.cpp @@ -88,7 +88,7 @@ void EmoteActionBase::InitEmotes() bool EmoteActionBase::Emote(Unit* target, uint32 type, bool textEmote) { - if (target && !bot->HasInArc(static_cast(M_PI), target, sPlayerbotAIConfig->sightDistance)) + if (target && !bot->HasInArc(static_cast(M_PI), target, sPlayerbotAIConfig.sightDistance)) bot->SetFacingToObject(target); ObjectGuid oldSelection = bot->GetTarget(); @@ -100,7 +100,7 @@ bool EmoteActionBase::Emote(Unit* target, uint32 type, bool textEmote) if (player) { PlayerbotAI* playerBotAI = GET_PLAYERBOT_AI(player); - if (playerBotAI && !player->HasInArc(static_cast(M_PI), bot, sPlayerbotAIConfig->sightDistance)) + if (playerBotAI && !player->HasInArc(static_cast(M_PI), bot, sPlayerbotAIConfig.sightDistance)) { player->SetFacingToObject(bot); } @@ -133,7 +133,7 @@ Unit* EmoteActionBase::GetTarget() for (GuidVector::iterator i = nfp.begin(); i != nfp.end(); ++i) { Unit* unit = botAI->GetUnit(*i); - if (unit && sServerFacade->GetDistance2d(bot, unit) < sPlayerbotAIConfig->tooCloseDistance) + if (unit && ServerFacade::instance().GetDistance2d(bot, unit) < sPlayerbotAIConfig.tooCloseDistance) targets.push_back(unit); } @@ -618,8 +618,8 @@ bool EmoteActionBase::ReceiveEmote(Player* source, uint32 emote, bool verbal) break; } - if (source && !bot->isMoving() && !bot->HasInArc(static_cast(M_PI), source, sPlayerbotAIConfig->farDistance)) - sServerFacade->SetFacingTo(bot, source); + if (source && !bot->isMoving() && !bot->HasInArc(static_cast(M_PI), source, sPlayerbotAIConfig.farDistance)) + ServerFacade::instance().SetFacingTo(bot, source); if (verbal) { @@ -689,7 +689,7 @@ bool EmoteAction::Execute(Event event) p >> emoteId >> source; pSource = ObjectAccessor::FindPlayer(source); - if (pSource && pSource != bot && sServerFacade->GetDistance2d(bot, pSource) < sPlayerbotAIConfig->farDistance && + if (pSource && pSource != bot && ServerFacade::instance().GetDistance2d(bot, pSource) < sPlayerbotAIConfig.farDistance && emoteId != EMOTE_ONESHOT_NONE) { if ((pSource->GetGUID() != bot->GetGUID()) && @@ -737,7 +737,7 @@ bool EmoteAction::Execute(Event event) // time_t lastEmote = AI_VALUE2(time_t, "last emote", qualifier); //not used, line marked for removal. botAI->GetAiObjectContext() ->GetValue("last emote", qualifier) - ->Set(time(nullptr) + urand(1000, sPlayerbotAIConfig->repeatDelay) / 1000); + ->Set(time(nullptr) + urand(1000, sPlayerbotAIConfig.repeatDelay) / 1000); param = qualifier; } diff --git a/src/Ai/Base/Actions/EquipAction.cpp b/src/Ai/Base/Actions/EquipAction.cpp index 9f4a67ca90..32508ef2e5 100644 --- a/src/Ai/Base/Actions/EquipAction.cpp +++ b/src/Ai/Base/Actions/EquipAction.cpp @@ -330,7 +330,7 @@ void EquipAction::EquipItem(Item* item) bool EquipUpgradesAction::Execute(Event event) { - if (!sPlayerbotAIConfig->autoEquipUpgradeLoot && !sRandomPlayerbotMgr->IsRandomBot(bot)) + if (!sPlayerbotAIConfig.autoEquipUpgradeLoot && !sRandomPlayerbotMgr.IsRandomBot(bot)) return false; if (event.GetSource() == "trade status") diff --git a/src/Ai/Base/Actions/FishingAction.cpp b/src/Ai/Base/Actions/FishingAction.cpp index dc431d3425..0fc09c3bce 100644 --- a/src/Ai/Base/Actions/FishingAction.cpp +++ b/src/Ai/Base/Actions/FishingAction.cpp @@ -272,9 +272,9 @@ bool MoveNearWaterAction::isPossible() float fishingSearchWindow; if (master) - fishingSearchWindow = sPlayerbotAIConfig->fishingDistanceFromMaster; + fishingSearchWindow = sPlayerbotAIConfig.fishingDistanceFromMaster; else - fishingSearchWindow = sPlayerbotAIConfig->fishingDistance; + fishingSearchWindow = sPlayerbotAIConfig.fishingDistance; WorldPosition fishingHole = FindFishingHole(botAI); @@ -385,7 +385,7 @@ bool EquipFishingPoleAction::isUseful() } } - if (sRandomPlayerbotMgr->IsRandomBot(bot)) + if (sRandomPlayerbotMgr.IsRandomBot(bot)) { bot->StoreNewItemInBestSlots(FISHING_POLE, 1); // Try to get a fishing pole return true; @@ -396,7 +396,7 @@ bool EquipFishingPoleAction::isUseful() return false; std::string masterName = master->GetName(); - std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( + std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault( "no_fishing_pole_error", "I don't have a Fishing Pole",{}); botAI->Whisper(text, masterName); @@ -499,7 +499,7 @@ bool EndMasterFishingAction::isUseful() return false; WorldPosition nearWater = FindWaterRadial(bot, bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), - bot->GetMap(), bot->GetPhaseMask(), MIN_DISTANCE_TO_WATER, sPlayerbotAIConfig->endFishingWithMaster, 10.0f); + bot->GetMap(), bot->GetPhaseMask(), MIN_DISTANCE_TO_WATER, sPlayerbotAIConfig.endFishingWithMaster, 10.0f); return !nearWater.IsValid(); } diff --git a/src/Ai/Base/Actions/FollowActions.cpp b/src/Ai/Base/Actions/FollowActions.cpp index 2593ea28e5..b9623233a9 100644 --- a/src/Ai/Base/Actions/FollowActions.cpp +++ b/src/Ai/Base/Actions/FollowActions.cpp @@ -44,7 +44,7 @@ bool FollowAction::Execute(Event event) // botAI->PetFollow(); // } // if (moved) - // botAI->SetNextCheckDelay(sPlayerbotAIConfig->reactDelay); + // botAI->SetNextCheckDelay(sPlayerbotAIConfig.reactDelay); return moved; } @@ -98,9 +98,9 @@ bool FollowAction::isUseful() distance = bot->GetDistance(loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ()); } if (botAI->HasStrategy("master fishing", BOT_STATE_NON_COMBAT)) - return sServerFacade->IsDistanceGreaterThan(distance, sPlayerbotAIConfig->fishingDistanceFromMaster); + return ServerFacade::instance().IsDistanceGreaterThan(distance, sPlayerbotAIConfig.fishingDistanceFromMaster); - return sServerFacade->IsDistanceGreaterThan(distance, formation->GetMaxDistance()); + return ServerFacade::instance().IsDistanceGreaterThan(distance, formation->GetMaxDistance()); } bool FollowAction::CanDeadFollow(Unit* target) @@ -130,7 +130,7 @@ bool FleeToGroupLeaderAction::Execute(Event event) WorldPosition bosPos(bot); float distance = bosPos.fDist(targetPos); - if (distance < sPlayerbotAIConfig->reactDistance * 3) + if (distance < sPlayerbotAIConfig.reactDistance * 3) { if (!urand(0, 3)) botAI->TellMaster("I am close, wait for me!"); diff --git a/src/Ai/Base/Actions/GenericActions.cpp b/src/Ai/Base/Actions/GenericActions.cpp index 184b17715d..453834c097 100644 --- a/src/Ai/Base/Actions/GenericActions.cpp +++ b/src/Ai/Base/Actions/GenericActions.cpp @@ -113,7 +113,7 @@ bool TogglePetSpellAutoCastAction::Execute(Event event) } // Debug message if pet spells have been toggled and debug is enabled - if (toggled && sPlayerbotAIConfig->petChatCommandDebug == 1) + if (toggled && sPlayerbotAIConfig.petChatCommandDebug == 1) botAI->TellMaster("Pet autocast spells have been toggled."); return toggled; @@ -185,7 +185,7 @@ bool SetPetStanceAction::Execute(Event /*event*/) } // Get the default pet stance from the configuration - int32 stance = sPlayerbotAIConfig->defaultPetStance; + int32 stance = sPlayerbotAIConfig.defaultPetStance; ReactStates react = REACT_DEFENSIVE; std::string stanceText = "defensive (from config, fallback)"; @@ -221,7 +221,7 @@ bool SetPetStanceAction::Execute(Event /*event*/) } // If debug is enabled in config, inform the master of the new stance - if (sPlayerbotAIConfig->petChatCommandDebug == 1) + if (sPlayerbotAIConfig.petChatCommandDebug == 1) botAI->TellMaster("Pet stance set to " + stanceText + " (applied to all pets/guardians)."); return true; diff --git a/src/Ai/Base/Actions/GenericBuffUtils.cpp b/src/Ai/Base/Actions/GenericBuffUtils.cpp index 1ac71bad4e..e33c12f180 100644 --- a/src/Ai/Base/Actions/GenericBuffUtils.cpp +++ b/src/Ai/Base/Actions/GenericBuffUtils.cpp @@ -87,7 +87,7 @@ namespace ai::buff { std::string castName = baseName; Group* g = bot->GetGroup(); - if (!g || g->GetMembersCount() < static_cast(sPlayerbotAIConfig->minBotsForGreaterBuff)) + if (!g || g->GetMembersCount() < static_cast(sPlayerbotAIConfig.minBotsForGreaterBuff)) return castName; // Group too small: stay in solo mode if (std::string const groupName = GroupVariantFor(baseName); !groupName.empty()) @@ -114,7 +114,7 @@ namespace ai::buff time_t now = std::time(nullptr); uint32 botLow = static_cast(bot->GetGUID().GetCounter()); time_t& last = s_lastWarn[ std::make_pair(botLow, groupName) ]; - if (!last || now - last >= sPlayerbotAIConfig->rpWarningCooldown) // Configurable anti-spam + if (!last || now - last >= sPlayerbotAIConfig.rpWarningCooldown) // Configurable anti-spam { // DB Key choice in regard of the buff std::string key; @@ -132,7 +132,7 @@ namespace ai::buff placeholders["%group_spell"] = groupName; placeholders["%base_spell"] = baseName; - std::string announceText = sPlayerbotTextMgr->GetBotTextOrDefault(key, + std::string announceText = PlayerbotTextMgr::instance().GetBotTextOrDefault(key, "Out of components for %group_spell. Using %base_spell!", placeholders); announce(announceText); diff --git a/src/Ai/Base/Actions/GenericSpellActions.cpp b/src/Ai/Base/Actions/GenericSpellActions.cpp index af06a457f0..819816f948 100644 --- a/src/Ai/Base/Actions/GenericSpellActions.cpp +++ b/src/Ai/Base/Actions/GenericSpellActions.cpp @@ -82,7 +82,7 @@ bool CastSpellAction::isPossible() { if (botAI->IsInVehicle() && !botAI->IsInVehicle(false, false, true)) { - if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && botAI->HasRealPlayerMaster())) + if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && botAI->HasRealPlayerMaster())) { LOG_DEBUG("playerbots", "Can cast spell failed. Vehicle. - bot name: {}", bot->GetName()); } @@ -94,7 +94,7 @@ bool CastSpellAction::isPossible() if (spell == "mount" && bot->IsInCombat()) { - if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && botAI->HasRealPlayerMaster())) + if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && botAI->HasRealPlayerMaster())) { LOG_DEBUG("playerbots", "Can cast spell failed. Mount. - bot name: {}", bot->GetName()); } @@ -133,7 +133,7 @@ bool CastSpellAction::isUseful() return spellTarget && AI_VALUE2(bool, "spell cast useful", - spell); // && sServerFacade->GetDistance2d(bot, spellTarget) <= (range + combatReach); + spell); // && ServerFacade::instance().GetDistance2d(bot, spellTarget) <= (range + combatReach); } CastMeleeSpellAction::CastMeleeSpellAction(PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell) diff --git a/src/Ai/Base/Actions/GiveItemAction.cpp b/src/Ai/Base/Actions/GiveItemAction.cpp index 6e2d6744ec..350b465b83 100644 --- a/src/Ai/Base/Actions/GiveItemAction.cpp +++ b/src/Ai/Base/Actions/GiveItemAction.cpp @@ -64,7 +64,7 @@ Unit* GiveItemAction::GetTarget() { return AI_VALUE2(Unit*, "party member withou bool GiveItemAction::isUseful() { - return GetTarget() && AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig->lowMana; + return GetTarget() && AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig.lowMana; } Unit* GiveFoodAction::GetTarget() { return AI_VALUE(Unit*, "party member without food"); } @@ -74,7 +74,7 @@ bool GiveFoodAction::isUseful() if (!GetTarget()) return false; - bool isRandomBot = GetTarget()->IsPlayer() && sRandomPlayerbotMgr->IsRandomBot((Player*)GetTarget()); + bool isRandomBot = GetTarget()->IsPlayer() && sRandomPlayerbotMgr.IsRandomBot((Player*)GetTarget()); return !isRandomBot || (isRandomBot && !botAI->HasCheat(BotCheatMask::food)); } @@ -86,7 +86,7 @@ bool GiveWaterAction::isUseful() if (!GetTarget()) return false; - bool isRandomBot = GetTarget()->IsPlayer() && sRandomPlayerbotMgr->IsRandomBot((Player*)GetTarget()); + bool isRandomBot = GetTarget()->IsPlayer() && sRandomPlayerbotMgr.IsRandomBot((Player*)GetTarget()); return !isRandomBot || (isRandomBot && !botAI->HasCheat(BotCheatMask::food)); } diff --git a/src/Ai/Base/Actions/GoAction.cpp b/src/Ai/Base/Actions/GoAction.cpp index 1b8cd62a2a..61a7550c2b 100644 --- a/src/Ai/Base/Actions/GoAction.cpp +++ b/src/Ai/Base/Actions/GoAction.cpp @@ -61,7 +61,7 @@ bool GoAction::Execute(Event event) else { botAI->TellMasterNoFacing("Clearing travel target"); - target->setTarget(sTravelMgr->nullTravelDestination, sTravelMgr->nullWorldPosition); + target->setTarget(TravelMgr::instance().nullTravelDestination, TravelMgr::instance().nullWorldPosition); target->setForced(false); return true; } @@ -75,8 +75,8 @@ bool GoAction::Execute(Event event) if (GameObject* go = botAI->GetGameObject(guid)) if (go->isSpawned()) { - if (sServerFacade->IsDistanceGreaterThan(sServerFacade->GetDistance2d(bot, go), - sPlayerbotAIConfig->reactDistance)) + if (ServerFacade::instance().IsDistanceGreaterThan(ServerFacade::instance().GetDistance2d(bot, go), + sPlayerbotAIConfig.reactDistance)) { botAI->TellError("It is too far away"); return false; @@ -86,7 +86,7 @@ bool GoAction::Execute(Event event) out << "Moving to " << ChatHelper::FormatGameobject(go); botAI->TellMasterNoFacing(out.str()); return MoveNear(bot->GetMapId(), go->GetPositionX(), go->GetPositionY(), go->GetPositionZ() + 0.5f, - sPlayerbotAIConfig->followDistance); + sPlayerbotAIConfig.followDistance); } } return false; @@ -106,7 +106,7 @@ bool GoAction::Execute(Event event) out << "Moving to " << unit->GetName(); botAI->TellMasterNoFacing(out.str()); return MoveNear(bot->GetMapId(), unit->GetPositionX(), unit->GetPositionY(), - unit->GetPositionZ() + 0.5f, sPlayerbotAIConfig->followDistance); + unit->GetPositionZ() + 0.5f, sPlayerbotAIConfig.followDistance); } } @@ -176,8 +176,8 @@ bool GoAction::Execute(Event event) float z = bot->GetPositionZ(); bot->UpdateAllowedPositionZ(x, y, z); - if (sServerFacade->IsDistanceGreaterThan(sServerFacade->GetDistance2d(bot, x, y), - sPlayerbotAIConfig->reactDistance)) + if (ServerFacade::instance().IsDistanceGreaterThan(ServerFacade::instance().GetDistance2d(bot, x, y), + sPlayerbotAIConfig.reactDistance)) { botAI->TellMaster("It is too far away"); return false; @@ -203,14 +203,14 @@ bool GoAction::Execute(Event event) out << "Moving to " << x1 << "," << y1; botAI->TellMasterNoFacing(out.str()); - return MoveNear(bot->GetMapId(), x, y, z + 0.5f, sPlayerbotAIConfig->followDistance); + return MoveNear(bot->GetMapId(), x, y, z + 0.5f, sPlayerbotAIConfig.followDistance); } PositionInfo pos = context->GetValue("position")->Get()[param]; if (pos.isSet()) { - if (sServerFacade->IsDistanceGreaterThan(sServerFacade->GetDistance2d(bot, pos.x, pos.y), - sPlayerbotAIConfig->reactDistance)) + if (ServerFacade::instance().IsDistanceGreaterThan(ServerFacade::instance().GetDistance2d(bot, pos.x, pos.y), + sPlayerbotAIConfig.reactDistance)) { botAI->TellError("It is too far away"); return false; @@ -219,7 +219,7 @@ bool GoAction::Execute(Event event) std::ostringstream out; out << "Moving to position " << param; botAI->TellMasterNoFacing(out.str()); - return MoveNear(bot->GetMapId(), pos.x, pos.y, pos.z + 0.5f, sPlayerbotAIConfig->followDistance); + return MoveNear(bot->GetMapId(), pos.x, pos.y, pos.z + 0.5f, sPlayerbotAIConfig.followDistance); } botAI->TellMaster("Whisper 'go x,y', 'go [game object]', 'go unit' or 'go position' and I will go there"); diff --git a/src/Ai/Base/Actions/GreetAction.cpp b/src/Ai/Base/Actions/GreetAction.cpp index 87bf2c5ffb..a9fda122ec 100644 --- a/src/Ai/Base/Actions/GreetAction.cpp +++ b/src/Ai/Base/Actions/GreetAction.cpp @@ -20,7 +20,7 @@ bool GreetAction::Execute(Event event) if (!player) return false; - if (!bot->HasInArc(CAST_ANGLE_IN_FRONT, player, sPlayerbotAIConfig->sightDistance)) + if (!bot->HasInArc(CAST_ANGLE_IN_FRONT, player, sPlayerbotAIConfig.sightDistance)) bot->SetFacingToObject(player); ObjectGuid oldSel = bot->GetTarget(); diff --git a/src/Ai/Base/Actions/GuildCreateActions.cpp b/src/Ai/Base/Actions/GuildCreateActions.cpp index 075b28cac3..c9f9e689eb 100644 --- a/src/Ai/Base/Actions/GuildCreateActions.cpp +++ b/src/Ai/Base/Actions/GuildCreateActions.cpp @@ -184,11 +184,11 @@ bool PetitionOfferNearbyAction::Execute(Event event) } else { - if (!sPlayerbotAIConfig->randomBotGroupNearby) + if (!sPlayerbotAIConfig.randomBotGroupNearby) return false; } - if (sServerFacade->GetDistance2d(bot, player) > sPlayerbotAIConfig->sightDistance) + if (ServerFacade::instance().GetDistance2d(bot, player) > sPlayerbotAIConfig.sightDistance) continue; // Parse rpg target to quest action. diff --git a/src/Ai/Base/Actions/GuildManagementActions.cpp b/src/Ai/Base/Actions/GuildManagementActions.cpp index f00a955e7c..be94b6ae62 100644 --- a/src/Ai/Base/Actions/GuildManagementActions.cpp +++ b/src/Ai/Base/Actions/GuildManagementActions.cpp @@ -171,7 +171,7 @@ bool GuildManageNearbyAction::Execute(Event event) continue; } - if (!sPlayerbotAIConfig->randomBotGuildNearby) + if (!sPlayerbotAIConfig.randomBotGuildNearby) return false; if (guild->GetMemberSize() > 1000) @@ -185,7 +185,7 @@ bool GuildManageNearbyAction::Execute(Event event) PlayerbotAI* botAi = GET_PLAYERBOT_AI(player); - if (!sPlayerbotAIConfig->randomBotInvitePlayer && botAi && botAi->IsRealPlayer()) + if (!sPlayerbotAIConfig.randomBotInvitePlayer && botAi && botAi->IsRealPlayer()) continue; if (botAi) @@ -193,16 +193,16 @@ bool GuildManageNearbyAction::Execute(Event event) if (botAi->GetGuilderType() == GuilderType::SOLO && !botAi->HasRealPlayerMaster()) //Do not invite solo players. continue; - if (botAi->HasActivePlayerMaster() && !sRandomPlayerbotMgr->IsRandomBot(player)) //Do not invite alts of active players. + if (botAi->HasActivePlayerMaster() && !sRandomPlayerbotMgr.IsRandomBot(player)) //Do not invite alts of active players. continue; } bool sameGroup = bot->GetGroup() && bot->GetGroup()->IsMember(player->GetGUID()); - if (!sameGroup && sServerFacade->GetDistance2d(bot, player) > sPlayerbotAIConfig->spellDistance) + if (!sameGroup && ServerFacade::instance().GetDistance2d(bot, player) > sPlayerbotAIConfig.spellDistance) continue; - if (sPlayerbotAIConfig->inviteChat && (sRandomPlayerbotMgr->IsRandomBot(bot) || !botAI->HasActivePlayerMaster())) + if (sPlayerbotAIConfig.inviteChat && (sRandomPlayerbotMgr.IsRandomBot(bot) || !botAI->HasActivePlayerMaster())) { /* std::map placeholders; placeholders["%name"] = player->GetName(); @@ -210,8 +210,8 @@ bool GuildManageNearbyAction::Execute(Event event) placeholders["%guildname"] = guild->GetName(); AreaTableEntry const* current_area = botAI->GetCurrentArea(); AreaTableEntry const* current_zone = botAI->GetCurrentZone(); - placeholders["%area_name"] = current_area ? current_area->area_name[BroadcastHelper::GetLocale()] : BOT_TEXT1("string_unknown_area"); - placeholders["%zone_name"] = current_zone ? current_zone->area_name[BroadcastHelper::GetLocale()] : BOT_TEXT1("string_unknown_area"); + placeholders["%area_name"] = current_area ? current_area->area_name[BroadcastHelper::GetLocale()] : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? current_zone->area_name[BroadcastHelper::GetLocale()] : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); std::vector lines; @@ -219,45 +219,45 @@ bool GuildManageNearbyAction::Execute(Event event) switch ((urand(0, 10) * urand(0, 10)) / 10) { case 0: - lines.push_back(BOT_TEXT2("Hey %name do you want to join my guild?", placeholders)); + lines.push_back(PlayerbotTextMgr::instance().GetBotText("Hey %name do you want to join my guild?", placeholders)); break; case 1: - lines.push_back(BOT_TEXT2("Hey man you wanna join my guild %name?", placeholders)); + lines.push_back(PlayerbotTextMgr::instance().GetBotText("Hey man you wanna join my guild %name?", placeholders)); break; case 2: - lines.push_back(BOT_TEXT2("I think you would be a good contribution to %guildname. Would you like to join %name?", placeholders)); + lines.push_back(PlayerbotTextMgr::instance().GetBotText("I think you would be a good contribution to %guildname. Would you like to join %name?", placeholders)); break; case 3: - lines.push_back(BOT_TEXT2("My guild %guildname has %members quality members. Would you like to make it 1 more %name?", placeholders)); + lines.push_back(PlayerbotTextMgr::instance().GetBotText("My guild %guildname has %members quality members. Would you like to make it 1 more %name?", placeholders)); break; case 4: - lines.push_back(BOT_TEXT2("Hey %name do you want to join %guildname? We have %members members and looking to become number 1 of the server.", placeholders)); + lines.push_back(PlayerbotTextMgr::instance().GetBotText("Hey %name do you want to join %guildname? We have %members members and looking to become number 1 of the server.", placeholders)); break; case 5: - lines.push_back(BOT_TEXT2("I'm not really good at smalltalk. Do you wanna join my guild %name/r?", placeholders)); + lines.push_back(PlayerbotTextMgr::instance().GetBotText("I'm not really good at smalltalk. Do you wanna join my guild %name/r?", placeholders)); break; case 6: - lines.push_back(BOT_TEXT2("Welcome to %zone_name.... do you want to join my guild %name?", placeholders)); + lines.push_back(PlayerbotTextMgr::instance().GetBotText("Welcome to %zone_name.... do you want to join my guild %name?", placeholders)); break; case 7: - lines.push_back(BOT_TEXT2("%name, you should join my guild!", placeholders)); + lines.push_back(PlayerbotTextMgr::instance().GetBotText("%name, you should join my guild!", placeholders)); break; case 8: - lines.push_back(BOT_TEXT2("%name, I got this guild....", placeholders)); + lines.push_back(PlayerbotTextMgr::instance().GetBotText("%name, I got this guild....", placeholders)); break; case 9: - lines.push_back(BOT_TEXT2("You are actually going to join my guild %name?", placeholders)); - lines.push_back(BOT_TEXT2("Haha.. you are the man! We are going to raid Molten...", placeholders)); + lines.push_back(PlayerbotTextMgr::instance().GetBotText("You are actually going to join my guild %name?", placeholders)); + lines.push_back(PlayerbotTextMgr::instance().GetBotText("Haha.. you are the man! We are going to raid Molten...", placeholders)); break; case 10: - lines.push_back(BOT_TEXT2("Hey Hey! do you guys wanna join my gild????", placeholders)); - lines.push_back(BOT_TEXT2("We've got a bunch of high levels and we are really super friendly..", placeholders)); - lines.push_back(BOT_TEXT2("..and watch your dog and do your homework...", placeholders)); - lines.push_back(BOT_TEXT2("..and we raid once a week and are working on MC raids...", placeholders)); - lines.push_back(BOT_TEXT2("..and we have more members than just me...", placeholders)); - lines.push_back(BOT_TEXT2("..and please stop I'm lonenly and we can get a ride the whole time...", placeholders)); - lines.push_back(BOT_TEXT2("..and it's really beautifull and I feel like crying...", placeholders)); - lines.push_back(BOT_TEXT2("So what do you guys say are you going to join are you going to join?", placeholders)); + lines.push_back(PlayerbotTextMgr::instance().GetBotText("Hey Hey! do you guys wanna join my gild????", placeholders)); + lines.push_back(PlayerbotTextMgr::instance().GetBotText("We've got a bunch of high levels and we are really super friendly..", placeholders)); + lines.push_back(PlayerbotTextMgr::instance().GetBotText("..and watch your dog and do your homework...", placeholders)); + lines.push_back(PlayerbotTextMgr::instance().GetBotText("..and we raid once a week and are working on MC raids...", placeholders)); + lines.push_back(PlayerbotTextMgr::instance().GetBotText("..and we have more members than just me...", placeholders)); + lines.push_back(PlayerbotTextMgr::instance().GetBotText("..and please stop I'm lonenly and we can get a ride the whole time...", placeholders)); + lines.push_back(PlayerbotTextMgr::instance().GetBotText("..and it's really beautifull and I feel like crying...", placeholders)); + lines.push_back(PlayerbotTextMgr::instance().GetBotText("So what do you guys say are you going to join are you going to join?", placeholders)); break; } @@ -274,7 +274,7 @@ bool GuildManageNearbyAction::Execute(Event event) if (botAI->DoSpecificAction("guild invite", Event("guild management", guid), true)) { - if (sPlayerbotAIConfig->inviteChat) + if (sPlayerbotAIConfig.inviteChat) return true; found++; } diff --git a/src/Ai/Base/Actions/HireAction.cpp b/src/Ai/Base/Actions/HireAction.cpp index f8b3653964..eba607d2e5 100644 --- a/src/Ai/Base/Actions/HireAction.cpp +++ b/src/Ai/Base/Actions/HireAction.cpp @@ -14,7 +14,7 @@ bool HireAction::Execute(Event event) if (!master) return false; - if (!sRandomPlayerbotMgr->IsRandomBot(bot)) + if (!sRandomPlayerbotMgr.IsRandomBot(bot)) return false; uint32 account = master->GetSession()->GetAccountId(); @@ -39,7 +39,7 @@ bool HireAction::Execute(Event event) return false; } - uint32 discount = sRandomPlayerbotMgr->GetTradeDiscount(bot, master); + uint32 discount = sRandomPlayerbotMgr.GetTradeDiscount(bot, master); uint32 m = 1 + (bot->GetLevel() / 10); uint32 moneyReq = m * 5000 * bot->GetLevel(); if (discount < moneyReq) @@ -54,7 +54,7 @@ bool HireAction::Execute(Event event) botAI->TellMaster("I will join you at your next relogin"); bot->SetMoney(moneyReq); - sRandomPlayerbotMgr->Remove(bot); + sRandomPlayerbotMgr.Remove(bot); CharacterDatabase.Execute("UPDATE characters SET account = {} WHERE guid = {}", account, bot->GetGUID().GetCounter()); diff --git a/src/Ai/Base/Actions/InviteToGroupAction.cpp b/src/Ai/Base/Actions/InviteToGroupAction.cpp index bec515fefb..14f943f76c 100644 --- a/src/Ai/Base/Actions/InviteToGroupAction.cpp +++ b/src/Ai/Base/Actions/InviteToGroupAction.cpp @@ -31,7 +31,7 @@ bool InviteToGroupAction::Invite(Player* inviter, Player* player) if (!group->isRaidGroup() && group->GetMembersCount() > 4) { auto convertOp = std::make_unique(inviter->GetGUID()); - sPlayerbotWorldProcessor->QueueOperation(std::move(convertOp)); + PlayerbotWorldThreadProcessor::instance().QueueOperation(std::move(convertOp)); } } @@ -62,7 +62,7 @@ bool InviteNearbyToGroupAction::Execute(Event event) if (player->GetGroup()) continue; - if (!sPlayerbotAIConfig->randomBotInvitePlayer && GET_PLAYERBOT_AI(player)->IsRealPlayer()) + if (!sPlayerbotAIConfig.randomBotInvitePlayer && GET_PLAYERBOT_AI(player)->IsRealPlayer()) continue; Group* group = bot->GetGroup(); @@ -88,7 +88,7 @@ bool InviteNearbyToGroupAction::Execute(Event event) if (abs(int32(player->GetLevel() - bot->GetLevel())) > 2) continue; - if (sServerFacade->GetDistance2d(bot, player) > sPlayerbotAIConfig->sightDistance) + if (ServerFacade::instance().GetDistance2d(bot, player) > sPlayerbotAIConfig.sightDistance) continue; // When inviting the 5th member of the group convert to raid for future invites. @@ -96,19 +96,19 @@ bool InviteNearbyToGroupAction::Execute(Event event) bot->GetGroup()->GetMembersCount() > 3) { auto convertOp = std::make_unique(bot->GetGUID()); - sPlayerbotWorldProcessor->QueueOperation(std::move(convertOp)); + PlayerbotWorldThreadProcessor::instance().QueueOperation(std::move(convertOp)); } - if (sPlayerbotAIConfig->inviteChat && sRandomPlayerbotMgr->IsRandomBot(bot)) + if (sPlayerbotAIConfig.inviteChat && sRandomPlayerbotMgr.IsRandomBot(bot)) { std::map placeholders; placeholders["%player"] = player->GetName(); if (group && group->isRaidGroup()) - bot->Say(BOT_TEXT2("join_raid", placeholders), + bot->Say(PlayerbotTextMgr::instance().GetBotText("join_raid", placeholders), (bot->GetTeamId() == TEAM_ALLIANCE ? LANG_COMMON : LANG_ORCISH)); else - bot->Say(BOT_TEXT2("join_group", placeholders), + bot->Say(PlayerbotTextMgr::instance().GetBotText("join_group", placeholders), (bot->GetTeamId() == TEAM_ALLIANCE ? LANG_COMMON : LANG_ORCISH)); } @@ -120,7 +120,7 @@ bool InviteNearbyToGroupAction::Execute(Event event) bool InviteNearbyToGroupAction::isUseful() { - if (!sPlayerbotAIConfig->randomBotGroupNearby) + if (!sPlayerbotAIConfig.randomBotGroupNearby) return false; if (bot->InBattleground()) @@ -186,7 +186,7 @@ bool InviteGuildToGroupAction::Execute(Event event) if (player->isDND()) continue; - if (!sPlayerbotAIConfig->randomBotInvitePlayer && GET_PLAYERBOT_AI(player)->IsRealPlayer()) + if (!sPlayerbotAIConfig.randomBotInvitePlayer && GET_PLAYERBOT_AI(player)->IsRealPlayer()) continue; if (player->IsBeingTeleported()) @@ -221,7 +221,7 @@ bool InviteGuildToGroupAction::Execute(Event event) 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) + if (!playerAi && ServerFacade::instance().GetDistance2d(bot, player) > sPlayerbotAIConfig.sightDistance) continue; Group* group = bot->GetGroup(); @@ -230,11 +230,11 @@ bool InviteGuildToGroupAction::Execute(Event event) bot->GetGroup()->GetMembersCount() > 3) { auto convertOp = std::make_unique(bot->GetGUID()); - sPlayerbotWorldProcessor->QueueOperation(std::move(convertOp)); + PlayerbotWorldThreadProcessor::instance().QueueOperation(std::move(convertOp)); } - if (sPlayerbotAIConfig->inviteChat && - (sRandomPlayerbotMgr->IsRandomBot(bot) || !botAI->HasActivePlayerMaster())) + if (sPlayerbotAIConfig.inviteChat && + (sRandomPlayerbotMgr.IsRandomBot(bot) || !botAI->HasActivePlayerMaster())) { BroadcastHelper::BroadcastGuildGroupOrRaidInvite(botAI, bot, player, group); } @@ -373,7 +373,7 @@ bool LfgAction::Execute(Event event) else { auto convertOp = std::make_unique(requester->GetGUID()); - sPlayerbotWorldProcessor->QueueOperation(std::move(convertOp)); + PlayerbotWorldThreadProcessor::instance().QueueOperation(std::move(convertOp)); } } diff --git a/src/Ai/Base/Actions/LeaveGroupAction.cpp b/src/Ai/Base/Actions/LeaveGroupAction.cpp index a279c9426c..03a24bd199 100644 --- a/src/Ai/Base/Actions/LeaveGroupAction.cpp +++ b/src/Ai/Base/Actions/LeaveGroupAction.cpp @@ -33,7 +33,7 @@ bool PartyCommandAction::Execute(Event event) Player* master = GetMaster(); if (master && member == master->GetName()) { - if (sRandomPlayerbotMgr->IsRandomBot(bot)) + if (sRandomPlayerbotMgr.IsRandomBot(bot)) { Player* newMaster = botAI->FindNewMaster(); if (newMaster || bot->InBattleground()) @@ -150,7 +150,7 @@ bool LeaveFarAwayAction::isUseful() if (abs(int32(groupLeader->GetLevel() - bot->GetLevel())) > 4) return true; - if (bot->GetMapId() != groupLeader->GetMapId() || bot->GetDistance2d(groupLeader) >= 2 * sPlayerbotAIConfig->rpgDistance) + if (bot->GetMapId() != groupLeader->GetMapId() || bot->GetDistance2d(groupLeader) >= 2 * sPlayerbotAIConfig.rpgDistance) { return true; } diff --git a/src/Ai/Base/Actions/LfgActions.cpp b/src/Ai/Base/Actions/LfgActions.cpp index 15f8b92f25..a34c3efc63 100644 --- a/src/Ai/Base/Actions/LfgActions.cpp +++ b/src/Ai/Base/Actions/LfgActions.cpp @@ -20,7 +20,7 @@ bool LfgJoinAction::Execute(Event event) { return JoinLFG(); } uint32 LfgJoinAction::GetRoles() { - if (!sRandomPlayerbotMgr->IsRandomBot(bot)) + if (!sRandomPlayerbotMgr.IsRandomBot(bot)) { if (botAI->IsTank(bot)) return PLAYER_ROLE_TANK; @@ -101,7 +101,7 @@ bool LfgJoinAction::JoinLFG() LfgDungeonSet list; std::vector selected; - std::vector dungeons = sRandomPlayerbotMgr->LfgDungeons[bot->GetTeamId()]; + std::vector dungeons = sRandomPlayerbotMgr.LfgDungeons[bot->GetTeamId()]; if (!dungeons.size()) return false; @@ -216,9 +216,9 @@ bool LfgAcceptAction::Execute(Event event) *packet << id << true; bot->GetSession()->QueuePacket(packet); - if (sRandomPlayerbotMgr->IsRandomBot(bot) && !bot->GetGroup()) + if (sRandomPlayerbotMgr.IsRandomBot(bot) && !bot->GetGroup()) { - sRandomPlayerbotMgr->Refresh(bot); + sRandomPlayerbotMgr.Refresh(bot); botAI->ResetStrategies(); } @@ -251,9 +251,9 @@ bool LfgAcceptAction::Execute(Event event) *packet << id << true; bot->GetSession()->QueuePacket(packet); - if (sRandomPlayerbotMgr->IsRandomBot(bot) && !bot->GetGroup()) + if (sRandomPlayerbotMgr.IsRandomBot(bot) && !bot->GetGroup()) { - sRandomPlayerbotMgr->Refresh(bot); + sRandomPlayerbotMgr.Refresh(bot); botAI->ResetStrategies(); } @@ -306,7 +306,7 @@ bool LfgTeleportAction::Execute(Event event) bool LfgJoinAction::isUseful() { - if (!sPlayerbotAIConfig->randomBotJoinLfg) + if (!sPlayerbotAIConfig.randomBotJoinLfg) { // botAI->ChangeStrategy("-lfg", BOT_STATE_NON_COMBAT); return false; @@ -337,7 +337,7 @@ bool LfgJoinAction::isUseful() if (bot->isDead()) return false; - if (!sRandomPlayerbotMgr->IsRandomBot(bot)) + if (!sRandomPlayerbotMgr.IsRandomBot(bot)) return false; Map* map = bot->GetMap(); diff --git a/src/Ai/Base/Actions/ListQuestsActions.cpp b/src/Ai/Base/Actions/ListQuestsActions.cpp index 7968417059..0071b113fe 100644 --- a/src/Ai/Base/Actions/ListQuestsActions.cpp +++ b/src/Ai/Base/Actions/ListQuestsActions.cpp @@ -107,14 +107,14 @@ uint32 ListQuestsAction::ListQuests(bool completed, bool silent, QuestTravelDeta if (travelDetail == QUEST_TRAVEL_DETAIL_SUMMARY) { std::vector allDestinations = - sTravelMgr->getQuestTravelDestinations(bot, questId, true, true, -1); + TravelMgr::instance().getQuestTravelDestinations(bot, questId, true, true, -1); std::vector availDestinations = - sTravelMgr->getQuestTravelDestinations(bot, questId, botAI->GetMaster(), false, -1); + TravelMgr::instance().getQuestTravelDestinations(bot, questId, botAI->GetMaster(), false, -1); uint32 desTot = allDestinations.size(); uint32 desAvail = availDestinations.size(); - uint32 desFull = desAvail - sTravelMgr->getQuestTravelDestinations(bot, questId, false, false, -1).size(); - uint32 desRange = desAvail - sTravelMgr->getQuestTravelDestinations(bot, questId, false, false).size(); + uint32 desFull = desAvail - TravelMgr::instance().getQuestTravelDestinations(bot, questId, false, false, -1).size(); + uint32 desRange = desAvail - TravelMgr::instance().getQuestTravelDestinations(bot, questId, false, false).size(); uint32 tpoints = 0; uint32 apoints = 0; @@ -140,7 +140,7 @@ uint32 ListQuestsAction::ListQuests(bool completed, bool silent, QuestTravelDeta { uint32 limit = 0; std::vector allDestinations = - sTravelMgr->getQuestTravelDestinations(bot, questId, true, true, -1); + TravelMgr::instance().getQuestTravelDestinations(bot, questId, true, true, -1); std::sort(allDestinations.begin(), allDestinations.end(), [botPos](TravelDestination* i, TravelDestination* j) { diff --git a/src/Ai/Base/Actions/ListSpellsAction.cpp b/src/Ai/Base/Actions/ListSpellsAction.cpp index 6f67aef1aa..720e2f9835 100644 --- a/src/Ai/Base/Actions/ListSpellsAction.cpp +++ b/src/Ai/Base/Actions/ListSpellsAction.cpp @@ -136,7 +136,7 @@ std::vector> ListSpellsAction::GetSpellList(std:: if (spellInfo->IsPassive()) continue; - SkillLineAbilityEntry const* skillLine = sPlayerbotSpellRepository->GetSkillLine(itr->first); + SkillLineAbilityEntry const* skillLine = PlayerbotSpellRepository::Instance().GetSkillLine(itr->first); if (skill != SKILL_NONE && (!skillLine || skillLine->SkillLine != skill)) continue; @@ -175,7 +175,7 @@ std::vector> ListSpellsAction::GetSpellList(std:: FindItemByIdVisitor visitor(itemid); uint32 reagentsInInventory = InventoryAction::GetItemCount(&visitor); - bool buyable = sPlayerbotSpellRepository->IsItemBuyable(itemid); + bool buyable = PlayerbotSpellRepository::Instance().IsItemBuyable(itemid); if (!buyable) { uint32 craftable = reagentsInInventory / reagentsRequired; @@ -303,4 +303,4 @@ bool ListSpellsAction::Execute(Event event) botAI->TellMasterNoFacing(i->second); return true; -} \ No newline at end of file +} diff --git a/src/Ai/Base/Actions/LootAction.cpp b/src/Ai/Base/Actions/LootAction.cpp index 2e0656e711..93368f5244 100644 --- a/src/Ai/Base/Actions/LootAction.cpp +++ b/src/Ai/Base/Actions/LootAction.cpp @@ -25,7 +25,7 @@ bool LootAction::Execute(Event /*event*/) LootObject prevLoot = AI_VALUE(LootObject, "loot target"); LootObject const& lootObject = - AI_VALUE(LootObjectStack*, "available loot")->GetLoot(sPlayerbotAIConfig->lootDistance); + AI_VALUE(LootObjectStack*, "available loot")->GetLoot(sPlayerbotAIConfig.lootDistance); if (!prevLoot.IsEmpty() && prevLoot.guid != lootObject.guid) { @@ -37,7 +37,7 @@ bool LootAction::Execute(Event /*event*/) // Provide a system to check if the game object id is disallowed in the user configurable list or not. // Check if the game object id is disallowed in the user configurable list or not. - if (sPlayerbotAIConfig->disallowedGameObjects.find(lootObject.guid.GetEntry()) != sPlayerbotAIConfig->disallowedGameObjects.end()) + if (sPlayerbotAIConfig.disallowedGameObjects.find(lootObject.guid.GetEntry()) != sPlayerbotAIConfig.disallowedGameObjects.end()) { return false; // Game object ID is disallowed, so do not proceed } @@ -50,7 +50,7 @@ bool LootAction::Execute(Event /*event*/) bool LootAction::isUseful() { - return sPlayerbotAIConfig->freeMethodLoot || !bot->GetGroup() || bot->GetGroup()->GetLootMethod() != FREE_FOR_ALL; + return sPlayerbotAIConfig.freeMethodLoot || !bot->GetGroup() || bot->GetGroup()->GetLootMethod() != FREE_FOR_ALL; } enum ProfessionSpells @@ -95,7 +95,7 @@ bool OpenLootAction::DoLoot(LootObject& lootObject) if (bot->IsMounted()) { bot->Dismount(); - botAI->SetNextCheckDelay(sPlayerbotAIConfig->lootDelay); // Small delay to avoid animation issues + botAI->SetNextCheckDelay(sPlayerbotAIConfig.lootDelay); // Small delay to avoid animation issues } if (creature && creature->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE)) @@ -104,7 +104,7 @@ bool OpenLootAction::DoLoot(LootObject& lootObject) *packet << lootObject.guid; bot->GetSession()->QueuePacket(packet); // bot->GetSession()->HandleLootOpcode(packet); - botAI->SetNextCheckDelay(sPlayerbotAIConfig->lootDelay); + botAI->SetNextCheckDelay(sPlayerbotAIConfig.lootDelay); return true; } @@ -202,7 +202,7 @@ uint32 OpenLootAction::GetOpeningSpell(LootObject& lootObject, GameObject* go) return spellId; } - return sPlayerbotAIConfig->openGoSpell; + return sPlayerbotAIConfig.openGoSpell; } bool OpenLootAction::CanOpenLock(LootObject& /*lootObject*/, SpellInfo const* spellInfo, GameObject* go) @@ -294,7 +294,7 @@ bool StoreLootAction::AuctionItem(uint32 itemId) AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(ahEntry); - uint32 price = oldItem->GetCount() * proto->BuyPrice * sRandomPlayerbotMgr->GetBuyMultiplier(bot); + uint32 price = oldItem->GetCount() * proto->BuyPrice * sRandomPlayerbotMgr.GetBuyMultiplier(bot); uint32 stackCount = urand(1, proto->GetMaxStackSize()); if (!price || !stackCount) @@ -426,28 +426,28 @@ bool StoreLootAction::Execute(Event event) } Player* master = botAI->GetMaster(); - if (sRandomPlayerbotMgr->IsRandomBot(bot) && master) + if (sRandomPlayerbotMgr.IsRandomBot(bot) && master) { - uint32 price = itemcount * proto->BuyPrice * sRandomPlayerbotMgr->GetBuyMultiplier(bot) + gold; + uint32 price = itemcount * proto->BuyPrice * sRandomPlayerbotMgr.GetBuyMultiplier(bot) + gold; if (price) - sRandomPlayerbotMgr->AddTradeDiscount(bot, master, price); + sRandomPlayerbotMgr.AddTradeDiscount(bot, master, price); if (Group* group = bot->GetGroup()) for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) if (ref->GetSource() != bot) - sGuildTaskMgr->CheckItemTask(itemid, itemcount, ref->GetSource(), bot); + GuildTaskMgr::instance().CheckItemTask(itemid, itemcount, ref->GetSource(), bot); } WorldPacket* packet = new WorldPacket(CMSG_AUTOSTORE_LOOT_ITEM, 1); *packet << itemindex; bot->GetSession()->QueuePacket(packet); // bot->GetSession()->HandleAutostoreLootItemOpcode(packet); - botAI->SetNextCheckDelay(sPlayerbotAIConfig->lootDelay); + botAI->SetNextCheckDelay(sPlayerbotAIConfig.lootDelay); - if (proto->Quality > ITEM_QUALITY_NORMAL && !urand(0, 50) && botAI->HasStrategy("emote", BOT_STATE_NON_COMBAT) && sPlayerbotAIConfig->randomBotEmote) + if (proto->Quality > ITEM_QUALITY_NORMAL && !urand(0, 50) && botAI->HasStrategy("emote", BOT_STATE_NON_COMBAT) && sPlayerbotAIConfig.randomBotEmote) botAI->PlayEmote(TEXT_EMOTE_CHEER); - if (proto->Quality >= ITEM_QUALITY_RARE && !urand(0, 1) && botAI->HasStrategy("emote", BOT_STATE_NON_COMBAT) && sPlayerbotAIConfig->randomBotEmote) + if (proto->Quality >= ITEM_QUALITY_RARE && !urand(0, 1) && botAI->HasStrategy("emote", BOT_STATE_NON_COMBAT) && sPlayerbotAIConfig.randomBotEmote) botAI->PlayEmote(TEXT_EMOTE_CHEER); BroadcastHelper::BroadcastLootingItem(botAI, bot, proto); @@ -498,7 +498,7 @@ bool StoreLootAction::IsLootAllowed(uint32 itemid, PlayerbotAI* botAI) { // if (AI_VALUE2(uint32, "item count", proto->Name1) < quest->RequiredItemCount[i]) // { - // if (botAI->GetMaster() && sPlayerbotAIConfig->syncQuestWithPlayer) + // if (botAI->GetMaster() && sPlayerbotAIConfig.syncQuestWithPlayer) // return false; //Quest is autocomplete for the bot so no item needed. // } @@ -514,7 +514,7 @@ bool StoreLootAction::IsLootAllowed(uint32 itemid, PlayerbotAI* botAI) bool canLoot = lootStrategy->CanLoot(proto, context); // if (canLoot && proto->Bonding == BIND_WHEN_PICKED_UP && botAI->HasActivePlayerMaster()) - // canLoot = sPlayerbotAIConfig->IsInRandomAccountList(botAI->GetBot()->GetSession()->GetAccountId()); + // canLoot = sPlayerbotAIConfig.IsInRandomAccountList(botAI->GetBot()->GetSession()->GetAccountId()); return canLoot; } diff --git a/src/Ai/Base/Actions/LootRollAction.cpp b/src/Ai/Base/Actions/LootRollAction.cpp index 912f75fddf..e600f1f204 100644 --- a/src/Ai/Base/Actions/LootRollAction.cpp +++ b/src/Ai/Base/Actions/LootRollAction.cpp @@ -84,11 +84,11 @@ bool LootRollAction::Execute(Event event) break; } } - if (sPlayerbotAIConfig->lootRollLevel == 0) + if (sPlayerbotAIConfig.lootRollLevel == 0) { vote = PASS; } - else if (sPlayerbotAIConfig->lootRollLevel == 1) + else if (sPlayerbotAIConfig.lootRollLevel == 1) { if (vote == NEED) { diff --git a/src/Ai/Base/Actions/MoveToRpgTargetAction.cpp b/src/Ai/Base/Actions/MoveToRpgTargetAction.cpp index 618af10af1..4e898f30ef 100644 --- a/src/Ai/Base/Actions/MoveToRpgTargetAction.cpp +++ b/src/Ai/Base/Actions/MoveToRpgTargetAction.cpp @@ -61,7 +61,7 @@ bool MoveToRpgTargetAction::Execute(Event event) } if ((unit && unit->isMoving() && !urand(0, 20)) || !ChooseRpgTargetAction::isFollowValid(bot, wo) || - guidP.distance(bot) > sPlayerbotAIConfig->reactDistance * 2 || !urand(0, 50)) + guidP.distance(bot) > sPlayerbotAIConfig.reactDistance * 2 || !urand(0, 50)) { AI_VALUE(GuidSet&, "ignore rpg target").insert(AI_VALUE(GuidPosition, "rpg target")); RESET_AI_VALUE(GuidPosition, "rpg target"); @@ -73,7 +73,7 @@ bool MoveToRpgTargetAction::Execute(Event event) float z = wo->GetPositionZ(); float mapId = wo->GetMapId(); - if (sPlayerbotAIConfig->randombotsWalkingRPG) + if (sPlayerbotAIConfig.randombotsWalkingRPG) if (!bot->IsOutdoors()) bot->m_movementInfo.AddMovementFlag(MOVEMENTFLAG_WALKING); diff --git a/src/Ai/Base/Actions/MoveToTravelTargetAction.cpp b/src/Ai/Base/Actions/MoveToTravelTargetAction.cpp index ed60339b82..958dfe7391 100644 --- a/src/Ai/Base/Actions/MoveToTravelTargetAction.cpp +++ b/src/Ai/Base/Actions/MoveToTravelTargetAction.cpp @@ -43,7 +43,7 @@ bool MoveToTravelTargetAction::Execute(Event event) if (memberDistance < 50.0f) continue; - if (memberDistance > sPlayerbotAIConfig->reactDistance * 20) + if (memberDistance > sPlayerbotAIConfig.reactDistance * 20) continue; // float memberAngle = botLocation.getAngleBetween(targetPos, memberPos); @@ -65,9 +65,9 @@ bool MoveToTravelTargetAction::Execute(Event event) botAI->TellMasterNoFacing(out); } - target->setExpireIn(target->getTimeLeft() + sPlayerbotAIConfig->maxWaitForMove); + target->setExpireIn(target->getTimeLeft() + sPlayerbotAIConfig.maxWaitForMove); - botAI->SetNextCheckDelay(sPlayerbotAIConfig->maxWaitForMove); + botAI->SetNextCheckDelay(sPlayerbotAIConfig.maxWaitForMove); return true; } @@ -80,7 +80,7 @@ bool MoveToTravelTargetAction::Execute(Event event) if (target->getMaxTravelTime() > target->getTimeLeft()) // The bot is late. Speed it up. { - // distance = sPlayerbotAIConfig->fleeDistance; + // distance = sPlayerbotAIConfig.fleeDistance; // angle = bot->GetAngle(location.GetPositionX(), location.GetPositionY()); // location = botLocation.getLocation(); } diff --git a/src/Ai/Base/Actions/MovementActions.cpp b/src/Ai/Base/Actions/MovementActions.cpp index 69e5c278ba..c595dff6e4 100644 --- a/src/Ai/Base/Actions/MovementActions.cpp +++ b/src/Ai/Base/Actions/MovementActions.cpp @@ -51,7 +51,7 @@ MovementAction::MovementAction(PlayerbotAI* botAI, std::string const name) : Act void MovementAction::CreateWp(Player* wpOwner, float x, float y, float z, float o, uint32 entry, bool important) { float dist = wpOwner->GetDistance(x, y, z); - float delay = 1000.0f * dist / wpOwner->GetSpeed(MOVE_RUN) + sPlayerbotAIConfig->reactDelay; + float delay = 1000.0f * dist / wpOwner->GetSpeed(MOVE_RUN) + sPlayerbotAIConfig.reactDelay; // if (!important) // delay *= 0.25; @@ -195,8 +195,8 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, bool generatePath = !bot->IsFlying() && !bot->isSwimming(); bool disableMoveSplinePath = - sPlayerbotAIConfig->disableMoveSplinePath >= 2 || - (sPlayerbotAIConfig->disableMoveSplinePath == 1 && bot->InBattleground()); + sPlayerbotAIConfig.disableMoveSplinePath >= 2 || + (sPlayerbotAIConfig.disableMoveSplinePath == 1 && bot->InBattleground()); if (Vehicle* vehicle = bot->GetVehicle()) { VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(bot); @@ -216,7 +216,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, delay -= botAI->GetReactDelay(); } delay = std::max(.0f, delay); - delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, delay); + delay = std::min((float)sPlayerbotAIConfig.maxWaitForMove, delay); AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay, priority); return true; } @@ -241,7 +241,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, delay -= botAI->GetReactDelay(); } delay = std::max(.0f, delay); - delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, delay); + delay = std::min((float)sPlayerbotAIConfig.maxWaitForMove, delay); AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay, priority); return true; } @@ -250,7 +250,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, { float modifiedZ; Movement::PointsArray path = - SearchForBestPath(x, y, z, modifiedZ, sPlayerbotAIConfig->maxMovementSearchTime, normal_only); + SearchForBestPath(x, y, z, modifiedZ, sPlayerbotAIConfig.maxMovementSearchTime, normal_only); if (modifiedZ == INVALID_HEIGHT) return false; float distance = bot->GetExactDist(x, y, modifiedZ); @@ -272,7 +272,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, delay -= botAI->GetReactDelay(); } delay = std::max(.0f, delay); - delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, delay); + delay = std::min((float)sPlayerbotAIConfig.maxWaitForMove, delay); AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay, priority); return true; } @@ -308,8 +308,8 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, // } // } - // float minDist = sPlayerbotAIConfig->targetPosRecalcDistance; //Minium distance a bot should move. - // float maxDist = sPlayerbotAIConfig->reactDistance; //Maxium distance a bot can move in one single + // float minDist = sPlayerbotAIConfig.targetPosRecalcDistance; //Minium distance a bot should move. + // float maxDist = sPlayerbotAIConfig.reactDistance; //Maxium distance a bot can move in one single // action. float originalZ = z; // save original destination height to check // if bot needs to fly up @@ -372,9 +372,9 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, // if (startPosition.getMapId() != endPosition.getMapId() || totalDistance > maxDist) // { - // if (!sTravelNodeMap->getNodes().empty() && !bot->InBattleground()) + // if (!TravelNodeMap::instance().getNodes().empty() && !bot->InBattleground()) // { - // if (sPlayerbotAIConfig->tweakValue) + // if (sPlayerbotAIConfig.tweakValue) // { // if (lastMove.future.valid()) // { @@ -388,12 +388,12 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, // } // } // else - // movePath = sTravelNodeMap->getFullPath(startPosition, endPosition, bot); + // movePath = TravelNodeMap::instance().getFullPath(startPosition, endPosition, bot); // if (movePath.empty()) // { // //We have no path. Beyond 450yd the standard PathGenerator will probably move the wrong way. - // if (sServerFacade->IsDistanceGreaterThan(totalDistance, maxDist * 3)) + // if (ServerFacade::instance().IsDistanceGreaterThan(totalDistance, maxDist * 3)) // { // movePath.clear(); // movePath.addPoint(endPosition); @@ -402,7 +402,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, // bot->StopMoving(); // if (botAI->HasStrategy("debug move", BOT_STATE_NON_COMBAT)) // botAI->TellMasterNoFacing("I have no path"); - // LOG_DEBUG("playerbots", "sServerFacade->IsDistanceGreaterThan(totalDistance, maxDist * 3)"); + // LOG_DEBUG("playerbots", "ServerFacade::instance().IsDistanceGreaterThan(totalDistance, maxDist * 3)"); // return false; // } @@ -450,7 +450,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, // if (pathType == TravelNodePathType::portal) // && !botAI->isRealPlayer()) // { // //Log bot movement - // if (sPlayerbotAIConfig->hasLog("bot_movement.csv")) + // if (sPlayerbotAIConfig.hasLog("bot_movement.csv")) // { // WorldPosition telePos; // if (entry) @@ -463,7 +463,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, // telePos = movePosition; // std::ostringstream out; - // out << sPlayerbotAIConfig->GetTimestampStr() << "+00,"; + // out << sPlayerbotAIConfig.GetTimestampStr() << "+00,"; // out << bot->GetName() << ","; // if (telePos && telePos.GetExactDist(movePosition) > 0.001) // startPosition.printWKT({ startPosition, movePosition, telePos }, out, 1); @@ -475,7 +475,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, // out << bot->GetLevel() << ","; // out << (entry ? -1 : entry); - // sPlayerbotAIConfig->log("bot_movement.csv", out.str().c_str()); + // sPlayerbotAIConfig.log("bot_movement.csv", out.str().c_str()); // } // if (entry) @@ -621,10 +621,10 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, // } // //Log bot movement - // if (sPlayerbotAIConfig->hasLog("bot_movement.csv") && lastMove.lastMoveShort.GetExactDist(movePosition) > 0.001) + // if (sPlayerbotAIConfig.hasLog("bot_movement.csv") && lastMove.lastMoveShort.GetExactDist(movePosition) > 0.001) // { // std::ostringstream out; - // out << sPlayerbotAIConfig->GetTimestampStr() << "+00,"; + // out << sPlayerbotAIConfig.GetTimestampStr() << "+00,"; // out << bot->GetName() << ","; // startPosition.printWKT({ startPosition, movePosition }, out, 1); // out << std::to_string(bot->getRace()) << ","; @@ -632,7 +632,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, // out << bot->GetLevel(); // out << 0; - // sPlayerbotAIConfig->log("bot_movement.csv", out.str().c_str()); + // sPlayerbotAIConfig.log("bot_movement.csv", out.str().c_str()); // } // // LOG_DEBUG("playerbots", "({}, {}) -> ({}, {})", startPosition.getX(), startPosition.getY(), // movePosition.getX(), movePosition.getY()); if (!react) @@ -694,7 +694,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, // if (botAI->GetMaster()) // { // if (botAI->GetMaster()->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING) && - // sServerFacade->GetDistance2d(bot, botAI->GetMaster()) < 20.0f) + // ServerFacade::instance().GetDistance2d(bot, botAI->GetMaster()) < 20.0f) // masterWalking = true; // } @@ -787,7 +787,7 @@ bool MovementAction::MoveTo(WorldObject* target, float distance, MovementPriorit float angle = bot->GetAngle(target); float needToGo = distanceToTarget - distance; - float maxDistance = sPlayerbotAIConfig->spellDistance; + float maxDistance = sPlayerbotAIConfig.spellDistance; if (needToGo > 0 && needToGo > maxDistance) needToGo = maxDistance; else if (needToGo < 0 && needToGo < -maxDistance) @@ -898,8 +898,8 @@ bool MovementAction::IsMovingAllowed(WorldObject* target) if (bot->GetMapId() != target->GetMapId()) return false; - // float distance = sServerFacade->GetDistance2d(bot, target); - // if (!bot->InBattleground() && distance > sPlayerbotAIConfig->reactDistance) + // float distance = ServerFacade::instance().GetDistance2d(bot, target); + // if (!bot->InBattleground() && distance > sPlayerbotAIConfig.reactDistance) // return false; return IsMovingAllowed(); @@ -923,7 +923,7 @@ bool MovementAction::IsDuplicateMove(uint32 mapId, float x, float y, float z) LastMovement& lastMove = *context->GetValue("last movement"); // heuristic 5s - if (lastMove.msTime + sPlayerbotAIConfig->maxWaitForMove < getMSTime() || + if (lastMove.msTime + sPlayerbotAIConfig.maxWaitForMove < getMSTime() || lastMove.lastMoveShort.GetExactDist(x, y, z) > 0.01f) return false; @@ -1046,7 +1046,7 @@ void MovementAction::UpdateMovementState() // if (bot->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE && bot->CanNotReachTarget() && // !bot->InBattleground()) // { - // if (Unit* pTarget = sServerFacade->GetChaseTarget(bot)) + // if (Unit* pTarget = ServerFacade::instance().GetChaseTarget(bot)) // { // if (!bot->IsWithinMeleeRange(pTarget) && pTarget->IsCreature()) // { @@ -1080,7 +1080,7 @@ void MovementAction::UpdateMovementState() // bot->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE) && bot->CanNotReachTarget() // && !bot->InBattleground()) // { - // if (Unit* pTarget = sServerFacade->GetChaseTarget(bot)) + // if (Unit* pTarget = ServerFacade::instance().GetChaseTarget(bot)) // { // if (pTarget != botAI->GetGroupLeader()) // return; @@ -1117,8 +1117,8 @@ bool MovementAction::Follow(Unit* target, float distance, float angle) if (!target) return false; - if (!bot->InBattleground() && sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, target), - sPlayerbotAIConfig->followDistance)) + if (!bot->InBattleground() && ServerFacade::instance().IsDistanceLessOrEqualThan(ServerFacade::instance().GetDistance2d(bot, target), + sPlayerbotAIConfig.followDistance)) { // botAI->TellError("No need to follow"); return false; @@ -1126,9 +1126,9 @@ bool MovementAction::Follow(Unit* target, float distance, float angle) /* if (!bot->InBattleground() - && sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, target->GetPositionX(), - target->GetPositionY()), sPlayerbotAIConfig->sightDistance) - && abs(bot->GetPositionZ() - target->GetPositionZ()) >= sPlayerbotAIConfig->spellDistance && + && ServerFacade::instance().IsDistanceLessOrEqualThan(ServerFacade::instance().GetDistance2d(bot, target->GetPositionX(), + target->GetPositionY()), sPlayerbotAIConfig.sightDistance) + && abs(bot->GetPositionZ() - target->GetPositionZ()) >= sPlayerbotAIConfig.spellDistance && botAI->HasRealPlayerMaster() && (target->GetMapId() && bot->GetMapId() != target->GetMapId())) { @@ -1189,13 +1189,13 @@ bool MovementAction::Follow(Unit* target, float distance, float angle) WorldPosition botPos(bot); WorldPosition cPos(corpse); - if (botPos.fDist(cPos) > sPlayerbotAIConfig->spellDistance) + if (botPos.fDist(cPos) > sPlayerbotAIConfig.spellDistance) return MoveTo(cPos.getMapId(), cPos.getX(), cPos.getY(), cPos.getZ()); } } - if (sServerFacade->IsDistanceGreaterOrEqualThan(sServerFacade->GetDistance2d(bot, target), - sPlayerbotAIConfig->sightDistance)) + if (ServerFacade::instance().IsDistanceGreaterOrEqualThan(ServerFacade::instance().GetDistance2d(bot, target), + sPlayerbotAIConfig.sightDistance)) { if (target->GetGUID().IsPlayer()) { @@ -1238,11 +1238,11 @@ bool MovementAction::Follow(Unit* target, float distance, float angle) } if (!target->HasUnitState(UNIT_STATE_IN_FLIGHT)) - return MoveTo(target, sPlayerbotAIConfig->followDistance); + return MoveTo(target, sPlayerbotAIConfig.followDistance); } - if (sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, target), - sPlayerbotAIConfig->followDistance)) + if (ServerFacade::instance().IsDistanceLessOrEqualThan(ServerFacade::instance().GetDistance2d(bot, target), + sPlayerbotAIConfig.followDistance)) { // botAI->TellError("No need to follow"); return false; @@ -1251,8 +1251,8 @@ bool MovementAction::Follow(Unit* target, float distance, float angle) if (target->IsFriendlyTo(bot) && bot->IsMounted() && AI_VALUE(GuidVector, "all targets").empty()) distance += angle; - if (!bot->InBattleground() && sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, target), - sPlayerbotAIConfig->followDistance)) + if (!bot->InBattleground() && ServerFacade::instance().IsDistanceLessOrEqualThan(ServerFacade::instance().GetDistance2d(bot, target), + sPlayerbotAIConfig.followDistance)) { // botAI->TellError("No need to follow"); return false; @@ -1274,7 +1274,7 @@ bool MovementAction::Follow(Unit* target, float distance, float angle) if (bot->GetMotionMaster()->GetCurrentMovementGeneratorType() == FOLLOW_MOTION_TYPE) { - Unit* currentTarget = sServerFacade->GetChaseTarget(bot); + Unit* currentTarget = ServerFacade::instance().GetChaseTarget(bot); if (currentTarget && currentTarget->GetGUID() == target->GetGUID()) return false; } @@ -1347,13 +1347,13 @@ void MovementAction::WaitForReach(float distance) { float delay = 1000.0f * MoveDelay(distance); - if (delay > sPlayerbotAIConfig->maxWaitForMove) - delay = sPlayerbotAIConfig->maxWaitForMove; + if (delay > sPlayerbotAIConfig.maxWaitForMove) + delay = sPlayerbotAIConfig.maxWaitForMove; Unit* target = *botAI->GetAiObjectContext()->GetValue("current target"); Unit* player = *botAI->GetAiObjectContext()->GetValue("enemy player target"); - if ((player || target) && delay > sPlayerbotAIConfig->globalCoolDown) - delay = sPlayerbotAIConfig->globalCoolDown; + if ((player || target) && delay > sPlayerbotAIConfig.globalCoolDown) + delay = sPlayerbotAIConfig.globalCoolDown; if (delay < 0) delay = 0; @@ -1378,7 +1378,7 @@ bool MovementAction::Flee(Unit* target) if (!target) return false; - if (!sPlayerbotAIConfig->fleeingEnabled) + if (!sPlayerbotAIConfig.fleeingEnabled) return false; if (!IsMovingAllowed()) @@ -1390,7 +1390,7 @@ bool MovementAction::Flee(Unit* target) bool foundFlee = false; time_t lastFlee = AI_VALUE(LastMovement&, "last movement").lastFlee; time_t now = time(0); - uint32 fleeDelay = urand(2, sPlayerbotAIConfig->returnDelay / 1000); + uint32 fleeDelay = urand(2, sPlayerbotAIConfig.returnDelay / 1000); if (lastFlee) { @@ -1406,7 +1406,7 @@ bool MovementAction::Flee(Unit* target) if (Group* group = bot->GetGroup()) { Unit* fleeTarget = nullptr; - float fleeDistance = sPlayerbotAIConfig->sightDistance; + float fleeDistance = sPlayerbotAIConfig.sightDistance; for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) { @@ -1416,8 +1416,8 @@ bool MovementAction::Flee(Unit* target) if (botAI->IsTank(player)) { - float distanceToTank = sServerFacade->GetDistance2d(bot, player); - float distanceToTarget = sServerFacade->GetDistance2d(bot, target); + float distanceToTank = ServerFacade::instance().GetDistance2d(bot, player); + float distanceToTarget = ServerFacade::instance().GetDistance2d(bot, target); if (distanceToTank < fleeDistance) { fleeTarget = player; @@ -1460,10 +1460,10 @@ bool MovementAction::Flee(Unit* target) if ((isHealer && botAI->IsHeal(player)) || needHealer) { - float distanceToHealer = sServerFacade->GetDistance2d(bot, player); - float distanceToTarget = sServerFacade->GetDistance2d(player, target); + float distanceToHealer = ServerFacade::instance().GetDistance2d(bot, player); + float distanceToTarget = ServerFacade::instance().GetDistance2d(player, target); if (distanceToHealer < fleeDistance && - distanceToTarget > (botAI->GetRange("shoot") / 2 + sPlayerbotAIConfig->followDistance) && + distanceToTarget > (botAI->GetRange("shoot") / 2 + sPlayerbotAIConfig.followDistance) && (needHealer || player->IsWithinLOSInMap(target))) { fleeTarget = player; @@ -1473,10 +1473,10 @@ bool MovementAction::Flee(Unit* target) } else if (isRanged && botAI->IsRanged(player)) { - float distanceToRanged = sServerFacade->GetDistance2d(bot, player); - float distanceToTarget = sServerFacade->GetDistance2d(player, target); + float distanceToRanged = ServerFacade::instance().GetDistance2d(bot, player); + float distanceToTarget = ServerFacade::instance().GetDistance2d(player, target); if (distanceToRanged < fleeDistance && - distanceToTarget > (botAI->GetRange("shoot") / 2 + sPlayerbotAIConfig->followDistance) && + distanceToTarget > (botAI->GetRange("shoot") / 2 + sPlayerbotAIConfig.followDistance) && player->IsWithinLOSInMap(target)) { fleeTarget = player; @@ -1485,10 +1485,10 @@ bool MovementAction::Flee(Unit* target) } } // remember any group member in case no one else found - float distanceToFlee = sServerFacade->GetDistance2d(bot, player); - float distanceToTarget = sServerFacade->GetDistance2d(player, target); + float distanceToFlee = ServerFacade::instance().GetDistance2d(bot, player); + float distanceToTarget = ServerFacade::instance().GetDistance2d(player, target); if (distanceToFlee < spareDistance && - distanceToTarget > (botAI->GetRange("shoot") / 2 + sPlayerbotAIConfig->followDistance) && + distanceToTarget > (botAI->GetRange("shoot") / 2 + sPlayerbotAIConfig.followDistance) && player->IsWithinLOSInMap(target)) { spareTarget = player; @@ -1508,8 +1508,8 @@ bool MovementAction::Flee(Unit* target) if ((!fleeTarget || !foundFlee) && master && master->IsAlive() && master->IsWithinLOSInMap(target)) { - float distanceToTarget = sServerFacade->GetDistance2d(master, target); - if (distanceToTarget > (botAI->GetRange("shoot") / 2 + sPlayerbotAIConfig->followDistance)) + float distanceToTarget = ServerFacade::instance().GetDistance2d(master, target); + if (distanceToTarget > (botAI->GetRange("shoot") / 2 + sPlayerbotAIConfig.followDistance)) foundFlee = MoveNear(master); } } @@ -1846,7 +1846,7 @@ void MovementAction::DoMovePoint(Unit* unit, float x, float y, float z, bool gen bool FleeAction::Execute(Event event) { - return MoveAway(AI_VALUE(Unit*, "current target"), sPlayerbotAIConfig->fleeDistance, true); + return MoveAway(AI_VALUE(Unit*, "current target"), sPlayerbotAIConfig.fleeDistance, true); } bool FleeAction::isUseful() @@ -1924,8 +1924,8 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj() { return false; } - if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(spellInfo->Id) != - sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end()) + if (sPlayerbotAIConfig.aoeAvoidSpellWhitelist.find(spellInfo->Id) != + sPlayerbotAIConfig.aoeAvoidSpellWhitelist.end()) return false; DynamicObject* dynOwner = aura->GetDynobjOwner(); @@ -1934,7 +1934,7 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj() return false; } float radius = dynOwner->GetRadius(); - if (!radius || radius > sPlayerbotAIConfig->maxAoeAvoidRadius) + if (!radius || radius > sPlayerbotAIConfig.maxAoeAvoidRadius) return false; if (bot->GetDistance(dynOwner) > radius) { @@ -1944,7 +1944,7 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj() name << spellInfo->SpellName[LOCALE_enUS]; // << "] (aura)"; if (FleePosition(dynOwner->GetPosition(), radius)) { - if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) + if (sPlayerbotAIConfig.tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) { lastTellTimer = time(NULL); lastMoveTimer = getMSTime(); @@ -1990,8 +1990,8 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage() continue; } - if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(spellId) != - sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end()) + if (sPlayerbotAIConfig.aoeAvoidSpellWhitelist.find(spellId) != + sPlayerbotAIConfig.aoeAvoidSpellWhitelist.end()) continue; const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId); @@ -2001,7 +2001,7 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage() } float radius = (float)goInfo->trap.diameter / 2 + go->GetCombatReach(); - if (!radius || radius > sPlayerbotAIConfig->maxAoeAvoidRadius) + if (!radius || radius > sPlayerbotAIConfig.maxAoeAvoidRadius) continue; if (bot->GetDistance(go) > radius) @@ -2012,7 +2012,7 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage() name << spellInfo->SpellName[LOCALE_enUS]; // << "] (object)"; if (FleePosition(go->GetPosition(), radius)) { - if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) + if (sPlayerbotAIConfig.tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) { lastTellTimer = time(NULL); lastMoveTimer = getMSTime(); @@ -2061,8 +2061,8 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura() sSpellMgr->GetSpellInfo(spellInfo->Effects[aurEff->GetEffIndex()].TriggerSpell); if (!triggerSpellInfo) continue; - if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(triggerSpellInfo->Id) != - sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end()) + if (sPlayerbotAIConfig.aoeAvoidSpellWhitelist.find(triggerSpellInfo->Id) != + sPlayerbotAIConfig.aoeAvoidSpellWhitelist.end()) return false; for (int j = 0; j < MAX_SPELL_EFFECTS; j++) { @@ -2073,13 +2073,13 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura() { break; } - if (!radius || radius > sPlayerbotAIConfig->maxAoeAvoidRadius) + if (!radius || radius > sPlayerbotAIConfig.maxAoeAvoidRadius) continue; std::ostringstream name; name << triggerSpellInfo->SpellName[LOCALE_enUS]; //<< "] (unit)"; if (FleePosition(unit->GetPosition(), radius)) { - if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) + if (sPlayerbotAIConfig.tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) { lastTellTimer = time(NULL); lastMoveTimer = getMSTime(); @@ -2134,7 +2134,7 @@ Position MovementAction::BestPositionForMeleeToFlee(Position pos, float radius) continue; } bool strict = checkAngle.strict; - float fleeDis = std::min(radius + 1.0f, sPlayerbotAIConfig->fleeDistance); + float fleeDis = std::min(radius + 1.0f, sPlayerbotAIConfig.fleeDistance); float dx = bot->GetPositionX() + cos(angle) * fleeDis; float dy = bot->GetPositionY() + sin(angle) * fleeDis; float dz = bot->GetPositionZ(); @@ -2146,7 +2146,7 @@ Position MovementAction::BestPositionForMeleeToFlee(Position pos, float radius) Position fleePos{dx, dy, dz}; if (strict && currentTarget && fleePos.GetExactDist(currentTarget) - currentTarget->GetCombatReach() > - sPlayerbotAIConfig->tooCloseDistance && + sPlayerbotAIConfig.tooCloseDistance && bot->IsWithinMeleeRange(currentTarget)) { continue; @@ -2197,7 +2197,7 @@ Position MovementAction::BestPositionForRangedToFlee(Position pos, float radius) continue; } bool strict = checkAngle.strict; - float fleeDis = std::min(radius + 1.0f, sPlayerbotAIConfig->fleeDistance); + float fleeDis = std::min(radius + 1.0f, sPlayerbotAIConfig.fleeDistance); float dx = bot->GetPositionX() + cos(angle) * fleeDis; float dy = bot->GetPositionY() + sin(angle) * fleeDis; float dz = bot->GetPositionZ(); @@ -2208,13 +2208,13 @@ Position MovementAction::BestPositionForRangedToFlee(Position pos, float radius) } Position fleePos{dx, dy, dz}; if (strict && currentTarget && - fleePos.GetExactDist(currentTarget) - currentTarget->GetCombatReach() > sPlayerbotAIConfig->spellDistance) + fleePos.GetExactDist(currentTarget) - currentTarget->GetCombatReach() > sPlayerbotAIConfig.spellDistance) { continue; } if (strict && currentTarget && fleePos.GetExactDist(currentTarget) - currentTarget->GetCombatReach() < - (sPlayerbotAIConfig->tooCloseDistance)) + (sPlayerbotAIConfig.tooCloseDistance)) { continue; } @@ -2357,7 +2357,7 @@ Position CombatFormationMoveAction::AverageGroupPos(float dis, bool ranged, bool continue; if (!member->IsAlive() || member->GetMapId() != bot->GetMapId() || member->IsCharmed() || - sServerFacade->GetDistance2d(bot, member) > dis) + ServerFacade::instance().GetDistance2d(bot, member) > dis) continue; averageX += member->GetPositionX(); @@ -2395,7 +2395,7 @@ float CombatFormationMoveAction::AverageGroupAngle(Unit* from, bool ranged, bool continue; if (!member->IsAlive() || member->GetMapId() != bot->GetMapId() || member->IsCharmed() || - sServerFacade->GetDistance2d(bot, member) > sPlayerbotAIConfig->sightDistance) + ServerFacade::instance().GetDistance2d(bot, member) > sPlayerbotAIConfig.sightDistance) continue; cnt++; @@ -2437,7 +2437,7 @@ Player* CombatFormationMoveAction::NearestGroupMember(float dis) { Player* member = ObjectAccessor::FindPlayer(itr->guid); if (!member || !member->IsAlive() || member == bot || member->GetMapId() != bot->GetMapId() || - member->IsCharmed() || sServerFacade->GetDistance2d(bot, member) > dis) + member->IsCharmed() || ServerFacade::instance().GetDistance2d(bot, member) > dis) continue; if (nearestDis > bot->GetExactDist(member)) { @@ -2651,7 +2651,7 @@ bool MoveToLootAction::Execute(Event event) if (!loot.IsLootPossible(bot)) return false; - return MoveNear(loot.GetWorldObject(bot), sPlayerbotAIConfig->contactDistance); + return MoveNear(loot.GetWorldObject(bot), sPlayerbotAIConfig.contactDistance); } bool MoveOutOfEnemyContactAction::Execute(Event event) @@ -2660,7 +2660,7 @@ bool MoveOutOfEnemyContactAction::Execute(Event event) if (!target) return false; - return MoveTo(target, sPlayerbotAIConfig->contactDistance); + return MoveTo(target, sPlayerbotAIConfig.contactDistance); } bool MoveOutOfEnemyContactAction::isUseful() { return AI_VALUE2(bool, "inside target", "current target"); } @@ -2674,8 +2674,8 @@ bool SetFacingTargetAction::Execute(Event event) if (bot->HasUnitState(UNIT_STATE_IN_FLIGHT)) return true; - sServerFacade->SetFacingTo(bot, target); - botAI->SetNextCheckDelay(sPlayerbotAIConfig->reactDelay); + ServerFacade::instance().SetFacingTo(bot, target); + botAI->SetNextCheckDelay(sPlayerbotAIConfig.reactDelay); return true; } @@ -2754,7 +2754,7 @@ bool SetBehindTargetAction::Execute(Event event) bool MoveOutOfCollisionAction::Execute(Event event) { float angle = M_PI * 2000 / frand(1.f, 1000.f); - float distance = sPlayerbotAIConfig->followDistance; + float distance = sPlayerbotAIConfig.followDistance; return MoveTo(bot->GetMapId(), bot->GetPositionX() + cos(angle) * distance, bot->GetPositionY() + sin(angle) * distance, bot->GetPositionZ()); } @@ -2771,7 +2771,7 @@ bool MoveOutOfCollisionAction::isUseful() bool MoveRandomAction::Execute(Event event) { - float distance = sPlayerbotAIConfig->tooCloseDistance + urand(10, 30); + float distance = sPlayerbotAIConfig.tooCloseDistance + urand(10, 30); Map* map = bot->GetMap(); for (int i = 0; i < 3; ++i) diff --git a/src/Ai/Base/Actions/MovementActions.h b/src/Ai/Base/Actions/MovementActions.h index d12bcd555c..7db911baa4 100644 --- a/src/Ai/Base/Actions/MovementActions.h +++ b/src/Ai/Base/Actions/MovementActions.h @@ -29,7 +29,7 @@ class MovementAction : public Action protected: bool JumpTo(uint32 mapId, float x, float y, float z, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL); - bool MoveNear(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig->contactDistance, + bool MoveNear(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig.contactDistance, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL); bool MoveToLOS(WorldObject* target, bool ranged = false); bool MoveTo(uint32 mapId, float x, float y, float z, bool idle = false, bool react = false, @@ -38,10 +38,10 @@ class MovementAction : public Action bool backwards = false); bool MoveTo(WorldObject* target, float distance = 0.0f, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL); - bool MoveNear(WorldObject* target, float distance = sPlayerbotAIConfig->contactDistance, + bool MoveNear(WorldObject* target, float distance = sPlayerbotAIConfig.contactDistance, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL); float GetFollowAngle(); - bool Follow(Unit* target, float distance = sPlayerbotAIConfig->followDistance); + bool Follow(Unit* target, float distance = sPlayerbotAIConfig.followDistance); bool Follow(Unit* target, float distance, float angle); bool ChaseTo(WorldObject* obj, float distance = 0.0f, float angle = 0.0f); bool ReachCombatTo(Unit* target, float distance = 0.0f); @@ -56,10 +56,10 @@ class MovementAction : public Action bool Flee(Unit* target); void ClearIdleState(); void UpdateMovementState(); - bool MoveAway(Unit* target, float distance = sPlayerbotAIConfig->fleeDistance, bool backwards = false); + bool MoveAway(Unit* target, float distance = sPlayerbotAIConfig.fleeDistance, bool backwards = false); bool MoveFromGroup(float distance); bool Move(float angle, float distance); - bool MoveInside(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig->followDistance, + bool MoveInside(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig.followDistance, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL); void CreateWp(Player* wpOwner, float x, float y, float z, float o, uint32 entry, bool important = false); Position BestPositionForMeleeToFlee(Position pos, float radius); @@ -86,7 +86,7 @@ class MovementAction : public Action class FleeAction : public MovementAction { public: - FleeAction(PlayerbotAI* botAI, float distance = sPlayerbotAIConfig->spellDistance) + FleeAction(PlayerbotAI* botAI, float distance = sPlayerbotAIConfig.spellDistance) : MovementAction(botAI, "flee"), distance(distance) { } @@ -138,8 +138,8 @@ class CombatFormationMoveAction : public MovementAction bool Execute(Event event) override; protected: - Position AverageGroupPos(float dis = sPlayerbotAIConfig->sightDistance, bool ranged = false, bool self = false); - Player* NearestGroupMember(float dis = sPlayerbotAIConfig->sightDistance); + Position AverageGroupPos(float dis = sPlayerbotAIConfig.sightDistance, bool ranged = false, bool self = false); + Player* NearestGroupMember(float dis = sPlayerbotAIConfig.sightDistance); float AverageGroupAngle(Unit* from, bool ranged = false, bool self = false); Position GetNearestPosition(const std::vector& positions); int lastMoveTimer = 0; diff --git a/src/Ai/Base/Actions/NonCombatActions.cpp b/src/Ai/Base/Actions/NonCombatActions.cpp index f87aa891dd..492da8ae6b 100644 --- a/src/Ai/Base/Actions/NonCombatActions.cpp +++ b/src/Ai/Base/Actions/NonCombatActions.cpp @@ -76,7 +76,7 @@ bool EatAction::Execute(Event event) if (bot->isMoving()) { bot->StopMoving(); - // botAI->SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown); + // botAI->SetNextCheckDelay(sPlayerbotAIConfig.globalCoolDown); // return false; } diff --git a/src/Ai/Base/Actions/PassLeadershipToMasterAction.cpp b/src/Ai/Base/Actions/PassLeadershipToMasterAction.cpp index 87890c1c57..4ecfdc3bc1 100644 --- a/src/Ai/Base/Actions/PassLeadershipToMasterAction.cpp +++ b/src/Ai/Base/Actions/PassLeadershipToMasterAction.cpp @@ -16,12 +16,12 @@ bool PassLeadershipToMasterAction::Execute(Event event) if (master && master != bot && bot->GetGroup() && bot->GetGroup()->IsMember(master->GetGUID())) { auto setLeaderOp = std::make_unique(bot->GetGUID(), master->GetGUID()); - sPlayerbotWorldProcessor->QueueOperation(std::move(setLeaderOp)); + PlayerbotWorldThreadProcessor::instance().QueueOperation(std::move(setLeaderOp)); if (!message.empty()) botAI->TellMasterNoFacing(message); - if (sRandomPlayerbotMgr->IsRandomBot(bot)) + if (sRandomPlayerbotMgr.IsRandomBot(bot)) { botAI->ResetStrategies(); botAI->Reset(); diff --git a/src/Ai/Base/Actions/PetsAction.cpp b/src/Ai/Base/Actions/PetsAction.cpp index cb9dc93957..d98740ee0b 100644 --- a/src/Ai/Base/Actions/PetsAction.cpp +++ b/src/Ai/Base/Actions/PetsAction.cpp @@ -23,7 +23,7 @@ bool PetsAction::Execute(Event event) if (param.empty()) { // If no parameter is provided, show usage instructions and return. - std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( + std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_usage_error", "Usage: pet ", {}); botAI->TellError(text); return false; @@ -52,7 +52,7 @@ bool PetsAction::Execute(Event event) // If no pets or guardians are found, notify and return. if (targets.empty()) { - std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( + std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_no_pet_error", "You have no pet or guardian pet.", {}); botAI->TellError(text); return false; @@ -65,19 +65,19 @@ bool PetsAction::Execute(Event event) if (param == "aggressive") { react = REACT_AGGRESSIVE; - stanceText = sPlayerbotTextMgr->GetBotTextOrDefault( + stanceText = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_stance_aggressive", "aggressive", {}); } else if (param == "defensive") { react = REACT_DEFENSIVE; - stanceText = sPlayerbotTextMgr->GetBotTextOrDefault( + stanceText = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_stance_defensive", "defensive", {}); } else if (param == "passive") { react = REACT_PASSIVE; - stanceText = sPlayerbotTextMgr->GetBotTextOrDefault( + stanceText = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_stance_passive", "passive", {}); } // The "stance" command simply reports the current stance of each pet/guardian. @@ -86,30 +86,30 @@ bool PetsAction::Execute(Event event) for (Creature* target : targets) { std::string type = target->IsPet() ? - sPlayerbotTextMgr->GetBotTextOrDefault("pet_type_pet", "pet", {}) : - sPlayerbotTextMgr->GetBotTextOrDefault("pet_type_guardian", "guardian", {}); + PlayerbotTextMgr::instance().GetBotTextOrDefault("pet_type_pet", "pet", {}) : + PlayerbotTextMgr::instance().GetBotTextOrDefault("pet_type_guardian", "guardian", {}); std::string name = target->GetName(); std::string stance; switch (target->GetReactState()) { case REACT_AGGRESSIVE: - stance = sPlayerbotTextMgr->GetBotTextOrDefault( + stance = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_stance_aggressive", "aggressive", {}); break; case REACT_DEFENSIVE: - stance = sPlayerbotTextMgr->GetBotTextOrDefault( + stance = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_stance_defensive", "defensive", {}); break; case REACT_PASSIVE: - stance = sPlayerbotTextMgr->GetBotTextOrDefault( + stance = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_stance_passive", "passive", {}); break; default: - stance = sPlayerbotTextMgr->GetBotTextOrDefault( + stance = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_stance_unknown", "unknown", {}); break; } - std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( + std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_stance_report", "Current stance of %type \"%name\": %stance.", {{"type", type}, {"name", name}, {"stance", stance}}); botAI->TellMaster(text); @@ -133,30 +133,30 @@ bool PetsAction::Execute(Event event) // If no valid target is selected, show an error and return. if (!targetUnit) { - std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( + std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_no_target_error", "No valid target selected by master.", {}); botAI->TellError(text); return false; } if (!targetUnit->IsAlive()) { - std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( + std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_target_dead_error", "Target is not alive.", {}); botAI->TellError(text); return false; } if (!bot->IsValidAttackTarget(targetUnit)) { - std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( + std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_invalid_target_error", "Target is not a valid attack target for the bot.", {}); botAI->TellError(text); return false; } - if (sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()) && + if (sPlayerbotAIConfig.IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()) && (targetUnit->IsPlayer() || targetUnit->IsPet()) && (!bot->duel || bot->duel->Opponent != targetUnit)) { - std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( + std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_pvp_prohibited_error", "I cannot command my pet to attack players in PvP prohibited areas.", {}); botAI->TellError(text); return false; @@ -208,15 +208,15 @@ bool PetsAction::Execute(Event event) } } // Inform the master if the command succeeded or failed. - if (didAttack && sPlayerbotAIConfig->petChatCommandDebug == 1) + if (didAttack && sPlayerbotAIConfig.petChatCommandDebug == 1) { - std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( + std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_attack_success", "Pet commanded to attack your target.", {}); botAI->TellMaster(text); } else if (!didAttack) { - std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( + std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_attack_failed", "Pet did not attack. (Already attacking or unable to attack target)", {}); botAI->TellError(text); } @@ -226,9 +226,9 @@ bool PetsAction::Execute(Event event) else if (param == "follow") { botAI->PetFollow(); - if (sPlayerbotAIConfig->petChatCommandDebug == 1) + if (sPlayerbotAIConfig.petChatCommandDebug == 1) { - std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( + std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_follow_success", "Pet commanded to follow.", {}); botAI->TellMaster(text); } @@ -267,9 +267,9 @@ bool PetsAction::Execute(Event event) charmInfo->SetForcedTargetGUID(); } } - if (sPlayerbotAIConfig->petChatCommandDebug == 1) + if (sPlayerbotAIConfig.petChatCommandDebug == 1) { - std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( + std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_stay_success", "Pet commanded to stay.", {}); botAI->TellMaster(text); } @@ -278,7 +278,7 @@ bool PetsAction::Execute(Event event) // Unknown command: show usage instructions and return. else { - std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( + std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_unknown_command_error", "Unknown pet command: %param. Use: pet ", {{"param", param}}); botAI->TellError(text); @@ -295,13 +295,13 @@ bool PetsAction::Execute(Event event) } // Inform the master of the new stance if debug is enabled. - if (sPlayerbotAIConfig->petChatCommandDebug == 1) + if (sPlayerbotAIConfig.petChatCommandDebug == 1) { - std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( + std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault( "pet_stance_set_success", "Pet stance set to %stance.", {{"stance", stanceText}}); botAI->TellMaster(text); } return true; -} \ No newline at end of file +} diff --git a/src/Ai/Base/Actions/PositionAction.cpp b/src/Ai/Base/Actions/PositionAction.cpp index 2de27f0414..7d8f4264ca 100644 --- a/src/Ai/Base/Actions/PositionAction.cpp +++ b/src/Ai/Base/Actions/PositionAction.cpp @@ -120,7 +120,7 @@ bool MoveToPositionAction::isUseful() { PositionInfo pos = context->GetValue("position")->Get()[qualifier]; float distance = AI_VALUE2(float, "distance", std::string("position_") + qualifier); - return pos.isSet() && distance > sPlayerbotAIConfig->followDistance && distance < sPlayerbotAIConfig->reactDistance; + return pos.isSet() && distance > sPlayerbotAIConfig.followDistance && distance < sPlayerbotAIConfig.reactDistance; } bool SetReturnPositionAction::Execute(Event event) @@ -131,7 +131,7 @@ bool SetReturnPositionAction::Execute(Event event) if (returnPos.isSet() && !randomPos.isSet()) { float angle = 2 * M_PI * urand(0, 1000) / 100.0f; - float dist = sPlayerbotAIConfig->followDistance * urand(0, 1000) / 1000.0f; + float dist = sPlayerbotAIConfig.followDistance * urand(0, 1000) / 1000.0f; float x = returnPos.x + cos(angle) * dist; float y = returnPos.y + sin(angle) * dist; float z = bot->GetPositionZ(); @@ -157,7 +157,7 @@ bool SetReturnPositionAction::isUseful() bool ReturnAction::isUseful() { PositionInfo pos = context->GetValue("position")->Get()[qualifier]; - return pos.isSet() && AI_VALUE2(float, "distance", "position_random") > sPlayerbotAIConfig->followDistance; + return pos.isSet() && AI_VALUE2(float, "distance", "position_random") > sPlayerbotAIConfig.followDistance; } bool ReturnToStayPositionAction::isPossible() @@ -167,7 +167,7 @@ bool ReturnToStayPositionAction::isPossible() if (stayPosition.isSet()) { const float distance = bot->GetDistance(stayPosition.x, stayPosition.y, stayPosition.z); - if (distance > sPlayerbotAIConfig->reactDistance) + if (distance > sPlayerbotAIConfig.reactDistance) { botAI->TellMaster("The stay position is too far to return. I am going to stay where I am now"); diff --git a/src/Ai/Base/Actions/QueryItemUsageAction.cpp b/src/Ai/Base/Actions/QueryItemUsageAction.cpp index 2fbc75af8f..34e2cc831b 100644 --- a/src/Ai/Base/Actions/QueryItemUsageAction.cpp +++ b/src/Ai/Base/Actions/QueryItemUsageAction.cpp @@ -118,7 +118,7 @@ std::string const QueryItemUsageAction::QueryItemUsage(ItemTemplate const* item) std::string const QueryItemUsageAction::QueryItemPrice(ItemTemplate const* item) { - if (!sRandomPlayerbotMgr->IsRandomBot(bot)) + if (!sRandomPlayerbotMgr.IsRandomBot(bot)) return ""; if (item->Bonding == BIND_WHEN_PICKED_UP) @@ -133,7 +133,7 @@ std::string const QueryItemUsageAction::QueryItemPrice(ItemTemplate const* item) { Item* sell = *i; int32 price = - sell->GetCount() * sell->GetTemplate()->SellPrice * sRandomPlayerbotMgr->GetSellMultiplier(bot); + sell->GetCount() * sell->GetTemplate()->SellPrice * sRandomPlayerbotMgr.GetSellMultiplier(bot); if (!sellPrice || sellPrice > price) sellPrice = price; } @@ -147,7 +147,7 @@ std::string const QueryItemUsageAction::QueryItemPrice(ItemTemplate const* item) if (usage == ITEM_USAGE_NONE) return msg.str(); - int32 buyPrice = item->BuyPrice * sRandomPlayerbotMgr->GetBuyMultiplier(bot); + int32 buyPrice = item->BuyPrice * sRandomPlayerbotMgr.GetBuyMultiplier(bot); if (buyPrice) { if (sellPrice) diff --git a/src/Ai/Base/Actions/QueryQuestAction.cpp b/src/Ai/Base/Actions/QueryQuestAction.cpp index 6ceccad975..5f5d63e08c 100644 --- a/src/Ai/Base/Actions/QueryQuestAction.cpp +++ b/src/Ai/Base/Actions/QueryQuestAction.cpp @@ -73,7 +73,7 @@ bool QueryQuestAction::Execute(Event event) { uint32 limit = 0; std::vector allDestinations = - sTravelMgr->getQuestTravelDestinations(bot, questId, true, true, -1); + TravelMgr::instance().getQuestTravelDestinations(bot, questId, true, true, -1); std::sort(allDestinations.begin(), allDestinations.end(), [ptr_botpos](TravelDestination* i, TravelDestination* j) {return i->distanceTo(ptr_botpos) < j->distanceTo(ptr_botpos); }); for (auto dest : allDestinations) diff --git a/src/Ai/Base/Actions/QuestAction.cpp b/src/Ai/Base/Actions/QuestAction.cpp index b96c539475..dfe7bb9f1e 100644 --- a/src/Ai/Base/Actions/QuestAction.cpp +++ b/src/Ai/Base/Actions/QuestAction.cpp @@ -182,7 +182,7 @@ bool QuestAction::ProcessQuests(WorldObject* questGiver) { ObjectGuid guid = questGiver->GetGUID(); - if (bot->GetDistance(questGiver) > INTERACTION_DISTANCE && !sPlayerbotAIConfig->syncQuestWithPlayer) + if (bot->GetDistance(questGiver) > INTERACTION_DISTANCE && !sPlayerbotAIConfig.syncQuestWithPlayer) { //if (botAI->HasStrategy("debug", BotState::BOT_STATE_COMBAT) || botAI->HasStrategy("debug", BotState::BOT_STATE_NON_COMBAT)) @@ -190,7 +190,7 @@ bool QuestAction::ProcessQuests(WorldObject* questGiver) return false; } - if (!bot->HasInArc(CAST_ANGLE_IN_FRONT, questGiver, sPlayerbotAIConfig->sightDistance)) + if (!bot->HasInArc(CAST_ANGLE_IN_FRONT, questGiver, sPlayerbotAIConfig.sightDistance)) bot->SetFacingToObject(questGiver); bot->SetTarget(guid); @@ -238,7 +238,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); @@ -366,7 +366,7 @@ bool QuestUpdateAddItemAction::Execute(Event event) placeholders["%quest_obj_required"] = std::to_string(requiredItemsCount); if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_COMBAT) || botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT)) { - const auto text = BOT_TEXT2("%quest_link - %item_link %quest_obj_available/%quest_obj_required", placeholders); + const auto text = PlayerbotTextMgr::instance().GetBotText("%quest_link - %item_link %quest_obj_available/%quest_obj_required", placeholders); botAI->Say(text); LOG_INFO("playerbots", "{} => {}", bot->GetName(), text); } @@ -454,7 +454,7 @@ bool QuestUpdateFailedTimerAction::Execute(Event event) { std::map placeholders; placeholders["%quest_link"] = botAI->GetChatHelper()->FormatQuest(qInfo); - botAI->TellMaster(BOT_TEXT2("Failed timer for %quest_link, abandoning", placeholders)); + botAI->TellMaster(PlayerbotTextMgr::instance().GetBotText("Failed timer for %quest_link, abandoning", placeholders)); BroadcastHelper::BroadcastQuestUpdateFailedTimer(botAI, bot, qInfo); } else diff --git a/src/Ai/Base/Actions/QuestConfirmAcceptAction.cpp b/src/Ai/Base/Actions/QuestConfirmAcceptAction.cpp index cc23fdaf0a..9c47af37b2 100644 --- a/src/Ai/Base/Actions/QuestConfirmAcceptAction.cpp +++ b/src/Ai/Base/Actions/QuestConfirmAcceptAction.cpp @@ -20,4 +20,4 @@ bool QuestConfirmAcceptAction::Execute(Event event) botAI->TellMaster(out); bot->GetSession()->HandleQuestConfirmAccept(sendPacket); return true; -} \ No newline at end of file +} diff --git a/src/Ai/Base/Actions/QuestConfirmAcceptAction.h b/src/Ai/Base/Actions/QuestConfirmAcceptAction.h index 029c6eeff2..1f13a0abfa 100644 --- a/src/Ai/Base/Actions/QuestConfirmAcceptAction.h +++ b/src/Ai/Base/Actions/QuestConfirmAcceptAction.h @@ -24,4 +24,4 @@ class QuestConfirmAcceptAction : public Action bool Execute(Event event) override; }; -#endif \ No newline at end of file +#endif diff --git a/src/Ai/Base/Actions/RandomBotUpdateAction.cpp b/src/Ai/Base/Actions/RandomBotUpdateAction.cpp index 61a8360e59..76ed46c901 100644 --- a/src/Ai/Base/Actions/RandomBotUpdateAction.cpp +++ b/src/Ai/Base/Actions/RandomBotUpdateAction.cpp @@ -10,7 +10,7 @@ bool RandomBotUpdateAction::Execute(Event event) { - if (!sRandomPlayerbotMgr->IsRandomBot(bot)) + if (!sRandomPlayerbotMgr.IsRandomBot(bot)) return false; if (bot->GetGroup() && botAI->GetGroupLeader()) @@ -20,10 +20,10 @@ bool RandomBotUpdateAction::Execute(Event event) return true; } - if (botAI->HasPlayerNearby(sPlayerbotAIConfig->grindDistance)) + if (botAI->HasPlayerNearby(sPlayerbotAIConfig.grindDistance)) return true; - return sRandomPlayerbotMgr->ProcessBot(bot); + return sRandomPlayerbotMgr.ProcessBot(bot); } bool RandomBotUpdateAction::isUseful() { return AI_VALUE(bool, "random bot update"); } diff --git a/src/Ai/Base/Actions/ReachTargetActions.cpp b/src/Ai/Base/Actions/ReachTargetActions.cpp index 2be0da6beb..a58e9b96ea 100644 --- a/src/Ai/Base/Actions/ReachTargetActions.cpp +++ b/src/Ai/Base/Actions/ReachTargetActions.cpp @@ -28,7 +28,7 @@ bool ReachTargetAction::isUseful() Unit* target = GetTarget(); // float dis = distance + CONTACT_DISTANCE; return target && - !bot->IsWithinCombatRange(target, distance); // sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, + !bot->IsWithinCombatRange(target, distance); // ServerFacade::instance().IsDistanceGreaterThan(AI_VALUE2(float, // "distance", GetTargetName()), distance); } @@ -42,8 +42,8 @@ bool CastReachTargetSpellAction::isUseful() return false; } - return sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "current target"), - (distance + sPlayerbotAIConfig->contactDistance)); + return ServerFacade::instance().IsDistanceGreaterThan(AI_VALUE2(float, "distance", "current target"), + (distance + sPlayerbotAIConfig.contactDistance)); } ReachSpellAction::ReachSpellAction(PlayerbotAI* botAI) diff --git a/src/Ai/Base/Actions/ReachTargetActions.h b/src/Ai/Base/Actions/ReachTargetActions.h index 40559753f9..1a8ce0c9cc 100644 --- a/src/Ai/Base/Actions/ReachTargetActions.h +++ b/src/Ai/Base/Actions/ReachTargetActions.h @@ -44,7 +44,7 @@ class CastReachTargetSpellAction : public CastSpellAction class ReachMeleeAction : public ReachTargetAction { public: - ReachMeleeAction(PlayerbotAI* botAI) : ReachTargetAction(botAI, "reach melee", sPlayerbotAIConfig->meleeDistance) {} + ReachMeleeAction(PlayerbotAI* botAI) : ReachTargetAction(botAI, "reach melee", sPlayerbotAIConfig.meleeDistance) {} }; class ReachSpellAction : public ReachTargetAction diff --git a/src/Ai/Base/Actions/ReadyCheckAction.cpp b/src/Ai/Base/Actions/ReadyCheckAction.cpp index 2fc25e6dcc..1c510d69d4 100644 --- a/src/Ai/Base/Actions/ReadyCheckAction.cpp +++ b/src/Ai/Base/Actions/ReadyCheckAction.cpp @@ -47,7 +47,7 @@ class HealthChecker : public ReadyChecker public: bool Check(PlayerbotAI* botAI, AiObjectContext* context) override { - return AI_VALUE2(uint8, "health", "self target") > sPlayerbotAIConfig->almostFullHealth; + return AI_VALUE2(uint8, "health", "self target") > sPlayerbotAIConfig.almostFullHealth; } std::string const getName() override { return "HP"; } @@ -59,7 +59,7 @@ class ManaChecker : public ReadyChecker bool Check(PlayerbotAI* botAI, AiObjectContext* context) override { return !AI_VALUE2(bool, "has mana", "self target") || - AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig->mediumHealth; + AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig.mediumHealth; } std::string const getName() override { return "MP"; } @@ -73,7 +73,7 @@ class DistanceChecker : public ReadyChecker Player* bot = botAI->GetBot(); if (Player* master = botAI->GetMaster()) { - bool distance = bot->GetDistance(master) <= sPlayerbotAIConfig->sightDistance; + bool distance = bot->GetDistance(master) <= sPlayerbotAIConfig.sightDistance; if (!distance) { return false; diff --git a/src/Ai/Base/Actions/ReleaseSpiritAction.cpp b/src/Ai/Base/Actions/ReleaseSpiritAction.cpp index 17fcc42a0b..9e3ec445d2 100644 --- a/src/Ai/Base/Actions/ReleaseSpiritAction.cpp +++ b/src/Ai/Base/Actions/ReleaseSpiritAction.cpp @@ -183,9 +183,9 @@ bool AutoReleaseSpiritAction::ShouldAutoRelease() const return false; } - return sServerFacade->IsDistanceGreaterThan( + return ServerFacade::instance().IsDistanceGreaterThan( AI_VALUE2(float, "distance", "group leader"), - sPlayerbotAIConfig->sightDistance); + sPlayerbotAIConfig.sightDistance); } bool AutoReleaseSpiritAction::ShouldDelayBattlegroundRelease() const diff --git a/src/Ai/Base/Actions/ResetAiAction.cpp b/src/Ai/Base/Actions/ResetAiAction.cpp index 3df6bbcd2a..19017c9161 100644 --- a/src/Ai/Base/Actions/ResetAiAction.cpp +++ b/src/Ai/Base/Actions/ResetAiAction.cpp @@ -44,7 +44,7 @@ bool ResetAiAction::Execute(Event event) } } } - sPlayerbotRepository->Reset(botAI); + PlayerbotRepository::instance().Reset(botAI); botAI->ResetStrategies(false); botAI->TellMaster("AI was reset to defaults"); return true; diff --git a/src/Ai/Base/Actions/RevealGatheringItemAction.cpp b/src/Ai/Base/Actions/RevealGatheringItemAction.cpp index 9725dce5ce..35cd7f8f04 100644 --- a/src/Ai/Base/Actions/RevealGatheringItemAction.cpp +++ b/src/Ai/Base/Actions/RevealGatheringItemAction.cpp @@ -20,16 +20,16 @@ bool RevealGatheringItemAction::Execute(Event event) return false; std::list targets; - AnyGameObjectInObjectRangeCheck u_check(bot, sPlayerbotAIConfig->grindDistance); + AnyGameObjectInObjectRangeCheck u_check(bot, sPlayerbotAIConfig.grindDistance); Acore::GameObjectListSearcher searcher(bot, targets, u_check); - Cell::VisitObjects(bot, searcher, sPlayerbotAIConfig->reactDistance); + Cell::VisitObjects(bot, searcher, sPlayerbotAIConfig.reactDistance); std::vector result; for (GameObject* go : targets) { if (!go || !go->isSpawned() || - sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, go), - sPlayerbotAIConfig->lootDistance)) + ServerFacade::instance().IsDistanceLessOrEqualThan(ServerFacade::instance().GetDistance2d(bot, go), + sPlayerbotAIConfig.lootDistance)) continue; if (LockEntry const* lockInfo = sLockStore.LookupEntry(go->GetGOInfo()->GetLockId())) diff --git a/src/Ai/Base/Actions/ReviveFromCorpseAction.cpp b/src/Ai/Base/Actions/ReviveFromCorpseAction.cpp index ce0b1fa05d..4af96fc698 100644 --- a/src/Ai/Base/Actions/ReviveFromCorpseAction.cpp +++ b/src/Ai/Base/Actions/ReviveFromCorpseAction.cpp @@ -24,8 +24,8 @@ bool ReviveFromCorpseAction::Execute(Event event) WorldPacket& p = event.getPacket(); if (!p.empty() && p.GetOpcode() == CMSG_RECLAIM_CORPSE && groupLeader && !corpse && bot->IsAlive()) { - if (sServerFacade->IsDistanceLessThan(AI_VALUE2(float, "distance", "group leader"), - sPlayerbotAIConfig->farDistance)) + if (ServerFacade::instance().IsDistanceLessThan(AI_VALUE2(float, "distance", "group leader"), + sPlayerbotAIConfig.farDistance)) { if (!botAI->HasStrategy("follow", BOT_STATE_NON_COMBAT)) { @@ -46,8 +46,8 @@ bool ReviveFromCorpseAction::Execute(Event event) if (groupLeader) { if (!GET_PLAYERBOT_AI(groupLeader) && groupLeader->isDead() && groupLeader->GetCorpse() && - sServerFacade->IsDistanceLessThan(AI_VALUE2(float, "distance", "group leader"), - sPlayerbotAIConfig->farDistance)) + ServerFacade::instance().IsDistanceLessThan(AI_VALUE2(float, "distance", "group leader"), + sPlayerbotAIConfig.farDistance)) return false; } @@ -87,8 +87,8 @@ bool FindCorpseAction::Execute(Event event) // if (groupLeader) // { // if (!GET_PLAYERBOT_AI(groupLeader) && - // sServerFacade->IsDistanceLessThan(AI_VALUE2(float, "distance", "group leader"), - // sPlayerbotAIConfig->farDistance)) return false; + // ServerFacade::instance().IsDistanceLessThan(AI_VALUE2(float, "distance", "group leader"), + // sPlayerbotAIConfig.farDistance)) return false; // } uint32 dCount = AI_VALUE(uint32, "death count"); @@ -101,8 +101,8 @@ bool FindCorpseAction::Execute(Event event) // bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(), // bot->GetName().c_str()); context->GetValue("death count")->Set(0); - // sRandomPlayerbotMgr->RandomTeleportForLevel(bot); - sRandomPlayerbotMgr->Revive(bot); + // sRandomPlayerbotMgr.RandomTeleportForLevel(bot); + sRandomPlayerbotMgr.Revive(bot); return true; } } @@ -123,7 +123,7 @@ bool FindCorpseAction::Execute(Event event) { if (moveToLeader) // We are near group leader. { - if (botPos.fDist(leaderPos) < sPlayerbotAIConfig->spellDistance) + if (botPos.fDist(leaderPos) < sPlayerbotAIConfig.spellDistance) return false; } else if (deadTime > 8 * MINUTE) // We have walked too long already. @@ -138,7 +138,7 @@ bool FindCorpseAction::Execute(Event event) } // If we are getting close move to a save ressurrection spot instead of just the corpse. - if (corpseDist < sPlayerbotAIConfig->reactDistance) + if (corpseDist < sPlayerbotAIConfig.reactDistance) { if (moveToLeader) moveToPos = leaderPos; @@ -162,7 +162,7 @@ bool FindCorpseAction::Execute(Event event) if (!botAI->AllowActivity(ALL_ACTIVITY)) { - uint32 delay = sServerFacade->GetDistance2d(bot, corpse) / + uint32 delay = ServerFacade::instance().GetDistance2d(bot, corpse) / bot->GetSpeed(MOVE_RUN); // Time a bot would take to travel to it's corpse. delay = std::min(delay, uint32(10 * MINUTE)); // Cap time to get to corpse at 10 minutes. @@ -308,7 +308,7 @@ bool SpiritHealerAction::Execute(Event event) GraveyardStruct const* ClosestGrave = GetGrave(dCount > 10 || deadTime > 15 * MINUTE || AI_VALUE(uint8, "durability") < 10); - if (bot->GetDistance2d(ClosestGrave->x, ClosestGrave->y) < sPlayerbotAIConfig->sightDistance) + if (bot->GetDistance2d(ClosestGrave->x, ClosestGrave->y) < sPlayerbotAIConfig.sightDistance) { GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs"); for (GuidVector::iterator i = npcs.begin(); i != npcs.end(); i++) diff --git a/src/Ai/Base/Actions/RpgAction.cpp b/src/Ai/Base/Actions/RpgAction.cpp index 6002eaf63a..919e25c58e 100644 --- a/src/Ai/Base/Actions/RpgAction.cpp +++ b/src/Ai/Base/Actions/RpgAction.cpp @@ -130,7 +130,7 @@ bool RpgAction::SetNextRpgAction() std::mt19937 gen(time(0)); - sTravelMgr->weighted_shuffle(actions.begin(), actions.end(), relevances.begin(), relevances.end(), gen); + TravelMgr::instance().weighted_shuffle(actions.begin(), actions.end(), relevances.begin(), relevances.end(), gen); Action* action = actions.front(); diff --git a/src/Ai/Base/Actions/RpgSubActions.cpp b/src/Ai/Base/Actions/RpgSubActions.cpp index aa4269fa92..43bff6ab83 100644 --- a/src/Ai/Base/Actions/RpgSubActions.cpp +++ b/src/Ai/Base/Actions/RpgSubActions.cpp @@ -77,9 +77,9 @@ void RpgHelper::setFacing(GuidPosition guidPosition) void RpgHelper::setDelay(bool waitForGroup) { if (!botAI->HasRealPlayerMaster() || (waitForGroup && botAI->GetGroupLeader() == bot && bot->GetGroup())) - botAI->SetNextCheckDelay(sPlayerbotAIConfig->rpgDelay); + botAI->SetNextCheckDelay(sPlayerbotAIConfig.rpgDelay); else - botAI->SetNextCheckDelay(sPlayerbotAIConfig->rpgDelay / 5); + botAI->SetNextCheckDelay(sPlayerbotAIConfig.rpgDelay / 5); } bool RpgSubAction::isPossible() { return rpg->guidP() && rpg->guidP().GetWorldObject(); } @@ -392,7 +392,7 @@ bool RpgTradeUsefulAction::Execute(Event event) bot->Say("Start trade with" + chat->FormatWorldobject(player), (bot->GetTeamId() == TEAM_ALLIANCE ? LANG_COMMON : LANG_ORCISH)); - botAI->SetNextCheckDelay(sPlayerbotAIConfig->rpgDelay); + botAI->SetNextCheckDelay(sPlayerbotAIConfig.rpgDelay); return true; } @@ -402,7 +402,7 @@ bool RpgTradeUsefulAction::Execute(Event event) bool RpgDuelAction::isUseful() { // do not offer duel in non pvp areas - if (sPlayerbotAIConfig->IsInPvpProhibitedZone(bot->GetZoneId())) + if (sPlayerbotAIConfig.IsInPvpProhibitedZone(bot->GetZoneId())) return false; // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities) @@ -440,4 +440,4 @@ bool RpgMountAnimAction::Execute(Event event) bot->GetSession()->HandleMountSpecialAnimOpcode(p); return true; -} \ No newline at end of file +} diff --git a/src/Ai/Base/Actions/SayAction.cpp b/src/Ai/Base/Actions/SayAction.cpp index 00fae65293..050d7ddbba 100644 --- a/src/Ai/Base/Actions/SayAction.cpp +++ b/src/Ai/Base/Actions/SayAction.cpp @@ -134,7 +134,7 @@ bool SayAction::Execute(Event event) } // load text based on chance - if (!sPlayerbotTextMgr->GetBotText(qualifier, text, placeholders)) + if (!PlayerbotTextMgr::instance().GetBotText(qualifier, text, placeholders)) return false; if (text.find("/y ") == 0) @@ -206,7 +206,7 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32& type, uint32& guid1, uint } //toxic links - if (msg.starts_with(sPlayerbotAIConfig->toxicLinksPrefix) + if (msg.starts_with(sPlayerbotAIConfig.toxicLinksPrefix) && (GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllItemIds(msg).size() > 0 || GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllQuestIds(msg).size() > 0)) { HandleToxicLinksReply(bot, chatChannelSource, msg, name); @@ -230,7 +230,7 @@ bool ChatReplyAction::HandleThunderfuryReply(Player* bot, ChatChannelSource chat const auto thunderfury = sObjectMgr->GetItemTemplate(19019); placeholders["%thunderfury_link"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatItem(thunderfury); - std::string responseMessage = BOT_TEXT2("thunderfury_spam", placeholders); + std::string responseMessage = PlayerbotTextMgr::instance().GetBotText("thunderfury_spam", placeholders); switch (chatChannelSource) { @@ -271,8 +271,8 @@ bool ChatReplyAction::HandleToxicLinksReply(Player* bot, ChatChannelSource chatC std::vector botItems = GET_PLAYERBOT_AI(bot)->GetInventoryAndEquippedItems(); std::map placeholders; - placeholders["%random_inventory_item_link"] = botItems.size() > 0 ? GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatItem(botItems[rand() % botItems.size()]->GetTemplate()) : BOT_TEXT1("string_empty_link"); - placeholders["%prefix"] = sPlayerbotAIConfig->toxicLinksPrefix; + placeholders["%random_inventory_item_link"] = botItems.size() > 0 ? GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatItem(botItems[rand() % botItems.size()]->GetTemplate()) : PlayerbotTextMgr::instance().GetBotText("string_empty_link"); + placeholders["%prefix"] = sPlayerbotAIConfig.toxicLinksPrefix; if (incompleteQuests.size() > 0) { @@ -287,8 +287,8 @@ bool ChatReplyAction::HandleToxicLinksReply(Player* bot, ChatChannelSource chatC placeholders["%my_role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); AreaTableEntry const* current_area = GET_PLAYERBOT_AI(bot)->GetCurrentArea(); AreaTableEntry const* current_zone = GET_PLAYERBOT_AI(bot)->GetCurrentZone(); - placeholders["%area_name"] = current_area ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); - placeholders["%zone_name"] = current_zone ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%area_name"] = current_area ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_area) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_zone) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); placeholders["%my_class"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatClass(bot->getClass()); placeholders["%my_race"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatRace(bot->getRace()); placeholders["%my_level"] = std::to_string(bot->GetLevel()); @@ -297,17 +297,17 @@ bool ChatReplyAction::HandleToxicLinksReply(Player* bot, ChatChannelSource chatC { case ChatChannelSource::SRC_WORLD: { - GET_PLAYERBOT_AI(bot)->SayToWorld(BOT_TEXT2("suggest_toxic_links", placeholders)); + GET_PLAYERBOT_AI(bot)->SayToWorld(PlayerbotTextMgr::instance().GetBotText("suggest_toxic_links", placeholders)); break; } case ChatChannelSource::SRC_GENERAL: { - GET_PLAYERBOT_AI(bot)->SayToChannel(BOT_TEXT2("suggest_toxic_links", placeholders), ChatChannelId::GENERAL); + GET_PLAYERBOT_AI(bot)->SayToChannel(PlayerbotTextMgr::instance().GetBotText("suggest_toxic_links", placeholders), ChatChannelId::GENERAL); break; } case ChatChannelSource::SRC_GUILD: { - GET_PLAYERBOT_AI(bot)->SayToGuild(BOT_TEXT2("suggest_toxic_links", placeholders)); + GET_PLAYERBOT_AI(bot)->SayToGuild(PlayerbotTextMgr::instance().GetBotText("suggest_toxic_links", placeholders)); break; } default: @@ -343,8 +343,8 @@ bool ChatReplyAction::HandleWTBItemsReply(Player* bot, ChatChannelSource chatCha placeholders["%other_name"] = name; AreaTableEntry const* current_area = GET_PLAYERBOT_AI(bot)->GetCurrentArea(); AreaTableEntry const* current_zone = GET_PLAYERBOT_AI(bot)->GetCurrentZone(); - placeholders["%area_name"] = current_area ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); - placeholders["%zone_name"] = current_zone ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%area_name"] = current_area ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_area) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_zone) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); placeholders["%my_class"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatClass(bot->getClass()); placeholders["%my_race"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatRace(bot->getRace()); placeholders["%my_level"] = std::to_string(bot->GetLevel()); @@ -365,12 +365,12 @@ bool ChatReplyAction::HandleWTBItemsReply(Player* bot, ChatChannelSource chatCha //may reply to the same channel or whisper if (urand(0, 1)) { - std::string responseMessage = BOT_TEXT2("response_wtb_items_channel", placeholders); + std::string responseMessage = PlayerbotTextMgr::instance().GetBotText("response_wtb_items_channel", placeholders); GET_PLAYERBOT_AI(bot)->SayToWorld(responseMessage); } else { - std::string responseMessage = BOT_TEXT2("response_wtb_items_whisper", placeholders); + std::string responseMessage = PlayerbotTextMgr::instance().GetBotText("response_wtb_items_whisper", placeholders); GET_PLAYERBOT_AI(bot)->Whisper(responseMessage, name); } break; @@ -380,12 +380,12 @@ bool ChatReplyAction::HandleWTBItemsReply(Player* bot, ChatChannelSource chatCha //may reply to the same channel or whisper if (urand(0, 1)) { - std::string responseMessage = BOT_TEXT2("response_wtb_items_channel", placeholders); + std::string responseMessage = PlayerbotTextMgr::instance().GetBotText("response_wtb_items_channel", placeholders); GET_PLAYERBOT_AI(bot)->SayToChannel(responseMessage, ChatChannelId::GENERAL); } else { - std::string responseMessage = BOT_TEXT2("response_wtb_items_whisper", placeholders); + std::string responseMessage = PlayerbotTextMgr::instance().GetBotText("response_wtb_items_whisper", placeholders); GET_PLAYERBOT_AI(bot)->Whisper(responseMessage, name); } break; @@ -395,12 +395,12 @@ bool ChatReplyAction::HandleWTBItemsReply(Player* bot, ChatChannelSource chatCha //may reply to the same channel or whisper if (urand(0, 1)) { - std::string responseMessage = BOT_TEXT2("response_wtb_items_channel", placeholders); + std::string responseMessage = PlayerbotTextMgr::instance().GetBotText("response_wtb_items_channel", placeholders); GET_PLAYERBOT_AI(bot)->SayToChannel(responseMessage, ChatChannelId::TRADE); } else { - std::string responseMessage = BOT_TEXT2("response_wtb_items_whisper", placeholders); + std::string responseMessage = PlayerbotTextMgr::instance().GetBotText("response_wtb_items_whisper", placeholders); GET_PLAYERBOT_AI(bot)->Whisper(responseMessage, name); } break; @@ -438,8 +438,8 @@ bool ChatReplyAction::HandleLFGQuestsReply(Player* bot, ChatChannelSource chatCh placeholders["%other_name"] = name; AreaTableEntry const* current_area = GET_PLAYERBOT_AI(bot)->GetCurrentArea(); AreaTableEntry const* current_zone = GET_PLAYERBOT_AI(bot)->GetCurrentZone(); - placeholders["%area_name"] = current_area ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); - placeholders["%zone_name"] = current_zone ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%area_name"] = current_area ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_area) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_zone) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); placeholders["%my_class"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatClass(bot->getClass()); placeholders["%my_race"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatRace(bot->getRace()); placeholders["%my_level"] = std::to_string(bot->GetLevel()); @@ -458,12 +458,12 @@ bool ChatReplyAction::HandleLFGQuestsReply(Player* bot, ChatChannelSource chatCh //may reply to the same channel or whisper if (urand(0, 1)) { - std::string responseMessage = BOT_TEXT2("response_lfg_quests_channel", placeholders); + std::string responseMessage = PlayerbotTextMgr::instance().GetBotText("response_lfg_quests_channel", placeholders); GET_PLAYERBOT_AI(bot)->SayToWorld(responseMessage); } else { - std::string responseMessage = BOT_TEXT2("response_lfg_quests_whisper", placeholders); + std::string responseMessage = PlayerbotTextMgr::instance().GetBotText("response_lfg_quests_whisper", placeholders); GET_PLAYERBOT_AI(bot)->Whisper(responseMessage, name); } break; @@ -473,12 +473,12 @@ bool ChatReplyAction::HandleLFGQuestsReply(Player* bot, ChatChannelSource chatCh //may reply to the same channel or whisper if (urand(0, 1)) { - std::string responseMessage = BOT_TEXT2("response_lfg_quests_channel", placeholders); + std::string responseMessage = PlayerbotTextMgr::instance().GetBotText("response_lfg_quests_channel", placeholders); GET_PLAYERBOT_AI(bot)->SayToChannel(responseMessage, ChatChannelId::GENERAL); } else { - std::string responseMessage = BOT_TEXT2("response_lfg_quests_whisper", placeholders); + std::string responseMessage = PlayerbotTextMgr::instance().GetBotText("response_lfg_quests_whisper", placeholders); GET_PLAYERBOT_AI(bot)->Whisper(responseMessage, name); } break; @@ -487,7 +487,7 @@ bool ChatReplyAction::HandleLFGQuestsReply(Player* bot, ChatChannelSource chatCh { //do not reply to the chat //may whisper - std::string responseMessage = BOT_TEXT2("response_lfg_quests_whisper", placeholders); + std::string responseMessage = PlayerbotTextMgr::instance().GetBotText("response_lfg_quests_whisper", placeholders); GET_PLAYERBOT_AI(bot)->Whisper(responseMessage, name); break; } @@ -1042,7 +1042,7 @@ std::string ChatReplyAction::GenerateReplyMessage(Player* bot, std::string& inco // load text if needed if (respondsText.empty()) { - respondsText = BOT_TEXT2(replyType, name); + respondsText = PlayerbotTextMgr::instance().GetBotText(replyType, name); } if (respondsText.size() > 255) diff --git a/src/Ai/Base/Actions/SecurityCheckAction.cpp b/src/Ai/Base/Actions/SecurityCheckAction.cpp index c47a6e52cb..ede59440e3 100644 --- a/src/Ai/Base/Actions/SecurityCheckAction.cpp +++ b/src/Ai/Base/Actions/SecurityCheckAction.cpp @@ -10,7 +10,7 @@ bool SecurityCheckAction::isUseful() { - return sRandomPlayerbotMgr->IsRandomBot(bot) && botAI->GetMaster() && + return sRandomPlayerbotMgr.IsRandomBot(bot) && botAI->GetMaster() && botAI->GetMaster()->GetSession()->GetSecurity() < SEC_GAMEMASTER && !GET_PLAYERBOT_AI(botAI->GetMaster()); } diff --git a/src/Ai/Base/Actions/SeeSpellAction.cpp b/src/Ai/Base/Actions/SeeSpellAction.cpp index 88848ca81f..bec9577cf6 100644 --- a/src/Ai/Base/Actions/SeeSpellAction.cpp +++ b/src/Ai/Base/Actions/SeeSpellAction.cpp @@ -20,7 +20,7 @@ Creature* SeeSpellAction::CreateWps(Player* wpOwner, float x, float y, float z, bool important) { float dist = wpOwner->GetDistance(x, y, z); - float delay = 1000.0f * dist / wpOwner->GetSpeed(MOVE_RUN) + sPlayerbotAIConfig->reactDelay; + float delay = 1000.0f * dist / wpOwner->GetSpeed(MOVE_RUN) + sPlayerbotAIConfig.reactDelay; if (!important) delay *= 0.25; @@ -61,7 +61,7 @@ bool SeeSpellAction::Execute(Event event) if (FISHING_SPELLS.find(spellId) != FISHING_SPELLS.end()) { - if (AI_VALUE(bool, "can fish") && sPlayerbotAIConfig->enableFishingWithMaster) + if (AI_VALUE(bool, "can fish") && sPlayerbotAIConfig.enableFishingWithMaster) { botAI->ChangeStrategy("+master fishing", BOT_STATE_NON_COMBAT); return true; diff --git a/src/Ai/Base/Actions/SendMailAction.cpp b/src/Ai/Base/Actions/SendMailAction.cpp index c6184c4b98..9be9d553ab 100644 --- a/src/Ai/Base/Actions/SendMailAction.cpp +++ b/src/Ai/Base/Actions/SendMailAction.cpp @@ -14,7 +14,7 @@ bool SendMailAction::Execute(Event event) { uint32 account = bot->GetSession()->GetAccountId(); - bool randomBot = sPlayerbotAIConfig->IsInRandomAccountList(account); + bool randomBot = sPlayerbotAIConfig.IsInRandomAccountList(account); GuidVector gos = *context->GetValue("nearest game objects"); bool mailboxFound = false; diff --git a/src/Ai/Base/Actions/ShareQuestAction.cpp b/src/Ai/Base/Actions/ShareQuestAction.cpp index d4b470b4c1..a9fe32c973 100644 --- a/src/Ai/Base/Actions/ShareQuestAction.cpp +++ b/src/Ai/Base/Actions/ShareQuestAction.cpp @@ -109,4 +109,4 @@ bool AutoShareQuestAction::Execute(Event event) bool AutoShareQuestAction::isUseful() { return bot->GetGroup() && !botAI->HasActivePlayerMaster(); -} \ No newline at end of file +} diff --git a/src/Ai/Base/Actions/StayActions.cpp b/src/Ai/Base/Actions/StayActions.cpp index 525ff8d53e..dbc7abd090 100644 --- a/src/Ai/Base/Actions/StayActions.cpp +++ b/src/Ai/Base/Actions/StayActions.cpp @@ -19,7 +19,7 @@ bool StayActionBase::Stay() if (bot->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) return false; - uint32 sitDelay = sPlayerbotAIConfig->sitDelay / 1000; + uint32 sitDelay = sPlayerbotAIConfig.sitDelay / 1000; time_t stayTime = AI_VALUE(time_t, "stay time"); time_t now = time(nullptr); if (!stayTime) @@ -48,7 +48,7 @@ bool StayAction::isUseful() if (stayPosition.isSet()) { const float distance = bot->GetDistance(stayPosition.x, stayPosition.y, stayPosition.z); - if (sPlayerbotAIConfig->followDistance) + if (sPlayerbotAIConfig.followDistance) { return false; } diff --git a/src/Ai/Base/Actions/SuggestWhatToDoAction.cpp b/src/Ai/Base/Actions/SuggestWhatToDoAction.cpp index 159bfd4ebb..9012443beb 100644 --- a/src/Ai/Base/Actions/SuggestWhatToDoAction.cpp +++ b/src/Ai/Base/Actions/SuggestWhatToDoAction.cpp @@ -54,7 +54,7 @@ SuggestWhatToDoAction::SuggestWhatToDoAction(PlayerbotAI* botAI, std::string con bool SuggestWhatToDoAction::isUseful() { - if (!sRandomPlayerbotMgr->IsRandomBot(bot) || bot->GetGroup() || bot->GetInstanceId() || bot->GetBattleground()) + if (!sRandomPlayerbotMgr.IsRandomBot(bot) || bot->GetGroup() || bot->GetInstanceId() || bot->GetBattleground()) return false; std::string qualifier = "suggest what to do"; @@ -140,7 +140,7 @@ void SuggestWhatToDoAction::grindMaterials() placeholders["%role"] = chat->formatClass(bot, AiFactory::GetPlayerSpecTab(bot)); placeholders["%category"] = item; - spam(BOT_TEXT2("suggest_trade", placeholders), urand(0, 1) ? 0x3C : 0x18, !urand(0, 2), !urand(0, + spam(PlayerbotTextMgr::instance().GetBotText("suggest_trade", placeholders), urand(0, 1) ? 0x3C : 0x18, !urand(0, 2), !urand(0, 3)); return; } } @@ -260,9 +260,9 @@ SuggestDungeonAction::SuggestDungeonAction(PlayerbotAI* botAI) : SuggestWhatToDo bool SuggestDungeonAction::Execute(Event event) { - // TODO: use sPlayerbotDungeonRepository + // TODO: use PlayerbotDungeonRepository::instance() - if (!sPlayerbotAIConfig->randomBotSuggestDungeons || bot->GetGroup()) + if (!sPlayerbotAIConfig.randomBotSuggestDungeons || bot->GetGroup()) return false; if (instances.empty()) @@ -373,7 +373,7 @@ bool SuggestTradeAction::Execute(Event event) if (!proto) return false; - uint32 price = proto->SellPrice * sRandomPlayerbotMgr->GetSellMultiplier(bot) * count; + uint32 price = proto->SellPrice * sRandomPlayerbotMgr.GetSellMultiplier(bot) * count; if (!price) return false; diff --git a/src/Ai/Base/Actions/TalkToQuestGiverAction.cpp b/src/Ai/Base/Actions/TalkToQuestGiverAction.cpp index 7f791d0d63..8fd120d605 100644 --- a/src/Ai/Base/Actions/TalkToQuestGiverAction.cpp +++ b/src/Ai/Base/Actions/TalkToQuestGiverAction.cpp @@ -24,7 +24,7 @@ bool TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver QuestStatus status = bot->GetQuestStatus(quest->GetQuestId()); Player* master = GetMaster(); - if (sPlayerbotAIConfig->syncQuestForPlayer && master) + if (sPlayerbotAIConfig.syncQuestForPlayer && master) { PlayerbotAI* masterBotAI = GET_PLAYERBOT_AI(master); if (!masterBotAI || masterBotAI->IsRealPlayer()) @@ -35,7 +35,7 @@ bool TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver } } - if (sPlayerbotAIConfig->syncQuestWithPlayer) + if (sPlayerbotAIConfig.syncQuestWithPlayer) { if (master && master->GetQuestStatus(quest->GetQuestId()) == QUEST_STATUS_COMPLETE && (status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_FAILED)) @@ -105,14 +105,14 @@ void TalkToQuestGiverAction::RewardNoItem(Quest const* quest, Object* questGiver if (bot->CanRewardQuest(quest, false)) { - out << BOT_TEXT2("quest_status_completed", args); + out << PlayerbotTextMgr::instance().GetBotText("quest_status_completed", args); BroadcastHelper::BroadcastQuestTurnedIn(botAI, bot, quest); bot->RewardQuest(quest, 0, questGiver, false); } else { - out << BOT_TEXT2("quest_status_unable_to_complete", args); + out << PlayerbotTextMgr::instance().GetBotText("quest_status_unable_to_complete", args); } } @@ -126,13 +126,13 @@ void TalkToQuestGiverAction::RewardSingleItem(Quest const* quest, Object* questG if (bot->CanRewardQuest(quest, index, false)) { - out << BOT_TEXT2("quest_status_complete_single_reward", args); + out << PlayerbotTextMgr::instance().GetBotText("quest_status_complete_single_reward", args); BroadcastHelper::BroadcastQuestTurnedIn(botAI, bot, quest); bot->RewardQuest(quest, index, questGiver, true); } else { - out << BOT_TEXT2("quest_status_unable_to_complete", args); + out << PlayerbotTextMgr::instance().GetBotText("quest_status_unable_to_complete", args); } } @@ -171,7 +171,7 @@ void TalkToQuestGiverAction::RewardMultipleItem(Quest const* quest, Object* ques std::set bestIds; std::ostringstream outid; - if (!botAI->IsAlt() || sPlayerbotAIConfig->autoPickReward == "yes") + if (!botAI->IsAlt() || sPlayerbotAIConfig.autoPickReward == "yes") { bestIds = BestRewards(quest); if (!bestIds.empty()) @@ -198,7 +198,7 @@ void TalkToQuestGiverAction::RewardMultipleItem(Quest const* quest, Object* ques AskToSelectReward(quest, out, true); } } - else if (sPlayerbotAIConfig->autoPickReward == "no") + else if (sPlayerbotAIConfig.autoPickReward == "no") { // Old functionality, list rewards. AskToSelectReward(quest, out, false); @@ -260,7 +260,7 @@ bool TurnInQueryQuestAction::Execute(Event event) QuestStatus status = bot->GetQuestStatus(quest->GetQuestId()); Player* master = GetMaster(); - if (sPlayerbotAIConfig->syncQuestForPlayer && master) + if (sPlayerbotAIConfig.syncQuestForPlayer && master) { PlayerbotAI* masterBotAI = GET_PLAYERBOT_AI(master); if (!masterBotAI || masterBotAI->IsRealPlayer()) @@ -271,7 +271,7 @@ bool TurnInQueryQuestAction::Execute(Event event) } } - if (sPlayerbotAIConfig->syncQuestWithPlayer) + if (sPlayerbotAIConfig.syncQuestWithPlayer) { if (status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_FAILED) { diff --git a/src/Ai/Base/Actions/TellLosAction.cpp b/src/Ai/Base/Actions/TellLosAction.cpp index 9cd12b02e3..13852bdc0a 100644 --- a/src/Ai/Base/Actions/TellLosAction.cpp +++ b/src/Ai/Base/Actions/TellLosAction.cpp @@ -152,4 +152,4 @@ bool TellCalculateItemAction::Execute(Event event) out << "Calculated score of " << chat->FormatItem(proto) << " : " << score; botAI->TellMasterNoFacing(out.str()); return true; -} \ No newline at end of file +} diff --git a/src/Ai/Base/Actions/TellPvpStatsAction.cpp b/src/Ai/Base/Actions/TellPvpStatsAction.cpp new file mode 100644 index 0000000000..943cf415c0 --- /dev/null +++ b/src/Ai/Base/Actions/TellPvpStatsAction.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license, you may redistribute it + * and/or modify it under version 3 of the License, or (at your option), any later version. + */ + +#include "TellPvpStatsAction.h" + +#include + +#include "ArenaTeam.h" +#include "ArenaTeamMgr.h" +#include "Event.h" +#include "Player.h" +#include "PlayerbotAI.h" +#include "PlayerbotTextMgr.h" +#include "Playerbots.h" +#include "SharedDefines.h" +#include "Language.h" + +namespace +{ + inline char const* BracketName(uint8 slot) + { + switch (slot) + { + case ARENA_SLOT_2v2: return "2v2"; + case ARENA_SLOT_3v3: return "3v3"; + default: return "5v5"; // ARENA_SLOT_5v5 + } + } +} + +bool TellPvpStatsAction::Execute(Event event) +{ + if (!bot) + return false; + + // Prefer the actual chat sender (whisper / say / etc.) if available. + Player* requester = nullptr; + + if (Unit* owner = event.getOwner()) + requester = owner->ToPlayer(); + + // Fallback to master if event owner is not available. + if (!requester) + requester = GetMaster(); + + // If we still do not have a valid player to answer to, bail out. + if (!requester) + return false; + + // PVP currencies + std::map currencyPlaceholders; + currencyPlaceholders["%arena_points"] = std::to_string(bot->GetArenaPoints()); + currencyPlaceholders["%honor_points"] = std::to_string(bot->GetHonorPoints()); + + std::string const currencyText = PlayerbotTextMgr::instance().GetBotTextOrDefault( + "pvp_currency", + "[PVP] Arena points: %arena_points | Honor Points: %honor_points", + currencyPlaceholders); + + bot->Whisper(currencyText, LANG_UNIVERSAL, requester); + + // Arena Teams by slot + bool anyTeam = false; + for (uint8 slot = 0; slot < MAX_ARENA_SLOT; ++slot) + { + uint32 const teamId = bot->GetArenaTeamId(slot); + if (!teamId) + continue; + + if (ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(teamId)) + { + anyTeam = true; + std::map placeholders; + placeholders["%bracket"] = BracketName(slot); + placeholders["%team_name"] = team->GetName(); + placeholders["%team_rating"] = std::to_string(team->GetRating()); + + std::string const teamText = PlayerbotTextMgr::instance().GetBotTextOrDefault( + "pvp_arena_team", + "[PVP] %bracket: <%team_name> (rating %team_rating)", + placeholders); + + bot->Whisper(teamText, LANG_UNIVERSAL, requester); + } + } + + if (!anyTeam) + { + std::string const noTeamText = PlayerbotTextMgr::instance().GetBotTextOrDefault( + "pvp_no_arena_team", + "[PVP] I have no Arena Team.", + std::map()); + + bot->Whisper(noTeamText, LANG_UNIVERSAL, requester); + } + + return true; +} diff --git a/src/Ai/Base/Actions/TellPvpStatsAction.h b/src/Ai/Base/Actions/TellPvpStatsAction.h new file mode 100644 index 0000000000..025cbd0d85 --- /dev/null +++ b/src/Ai/Base/Actions/TellPvpStatsAction.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license, you may redistribute it + * and/or modify it under version 3 of the License, or (at your option), any later version. + */ + +#ifndef _PLAYERBOT_TELLPVPSTATSACTION_H +#define _PLAYERBOT_TELLPVPSTATSACTION_H + +#include "Action.h" + +class PlayerbotAI; + +class TellPvpStatsAction : public Action +{ +public: + TellPvpStatsAction(PlayerbotAI* botAI) : Action(botAI, "tell pvp stats") {} + + bool Execute(Event event) override; +}; +#endif \ No newline at end of file diff --git a/src/Ai/Base/Actions/TradeAction.cpp b/src/Ai/Base/Actions/TradeAction.cpp index ad81d9f93b..b6f6912be2 100644 --- a/src/Ai/Base/Actions/TradeAction.cpp +++ b/src/Ai/Base/Actions/TradeAction.cpp @@ -15,7 +15,7 @@ bool TradeAction::Execute(Event event) std::string const text = event.getParam(); // If text starts with any excluded prefix, don't process it further. - for (auto const& prefix : sPlayerbotAIConfig->tradeActionExcludedPrefixes) + for (auto const& prefix : sPlayerbotAIConfig.tradeActionExcludedPrefixes) { if (text.find(prefix) == 0) return false; diff --git a/src/Ai/Base/Actions/TradeStatusAction.cpp b/src/Ai/Base/Actions/TradeStatusAction.cpp index 16ad2ca79d..3057fff097 100644 --- a/src/Ai/Base/Actions/TradeStatusAction.cpp +++ b/src/Ai/Base/Actions/TradeStatusAction.cpp @@ -32,7 +32,7 @@ bool TradeStatusAction::Execute(Event event) return false; } - if (sPlayerbotAIConfig->enableRandomBotTrading == 0 && (sRandomPlayerbotMgr->IsRandomBot(bot)|| sRandomPlayerbotMgr->IsAddclassBot(bot))) + if (sPlayerbotAIConfig.enableRandomBotTrading == 0 && (sRandomPlayerbotMgr.IsRandomBot(bot)|| sRandomPlayerbotMgr.IsAddclassBot(bot))) { bot->Whisper("Trading is disabled", LANG_UNIVERSAL, trader); return false; @@ -61,7 +61,7 @@ bool TradeStatusAction::Execute(Event event) uint32 status = 0; p << status; - uint32 discount = sRandomPlayerbotMgr->GetTradeDiscount(bot, trader); + uint32 discount = sRandomPlayerbotMgr.GetTradeDiscount(bot, trader); if (CheckTrade()) { int32 botMoney = CalculateCost(bot, true); @@ -81,7 +81,7 @@ bool TradeStatusAction::Execute(Event event) bot->GetSession()->HandleAcceptTradeOpcode(p); if (bot->GetTradeData()) { - sRandomPlayerbotMgr->SetTradeDiscount(bot, trader, discount); + sRandomPlayerbotMgr.SetTradeDiscount(bot, trader, discount); return false; } @@ -96,7 +96,7 @@ bool TradeStatusAction::Execute(Event event) craftData.AddObtained(itemId, count); } - sGuildTaskMgr->CheckItemTask(itemId, count, trader, bot); + GuildTaskMgr::instance().CheckItemTask(itemId, count, trader, bot); } for (std::map::iterator i = takenItemIds.begin(); i != takenItemIds.end(); ++i) @@ -116,7 +116,7 @@ bool TradeStatusAction::Execute(Event event) } else if (status == TRADE_STATUS_BEGIN_TRADE) { - if (!bot->HasInArc(CAST_ANGLE_IN_FRONT, trader, sPlayerbotAIConfig->sightDistance)) + if (!bot->HasInArc(CAST_ANGLE_IN_FRONT, trader, sPlayerbotAIConfig.sightDistance)) bot->SetFacingToObject(trader); BeginTrade(); @@ -141,9 +141,9 @@ void TradeStatusAction::BeginTrade() botAI->TellMaster("=== Inventory ==="); TellItems(visitor.items, visitor.soulbound); - if (sRandomPlayerbotMgr->IsRandomBot(bot)) + if (sRandomPlayerbotMgr.IsRandomBot(bot)) { - uint32 discount = sRandomPlayerbotMgr->GetTradeDiscount(bot, botAI->GetMaster()); + uint32 discount = sRandomPlayerbotMgr.GetTradeDiscount(bot, botAI->GetMaster()); if (discount) { std::ostringstream out; @@ -198,7 +198,7 @@ bool TradeStatusAction::CheckTrade() return false; } uint32 accountId = bot->GetSession()->GetAccountId(); - if (!sPlayerbotAIConfig->IsInRandomAccountList(accountId)) + if (!sPlayerbotAIConfig.IsInRandomAccountList(accountId)) { int32 botItemsMoney = CalculateCost(bot, true); int32 botMoney = bot->GetTradeData()->GetMoney() + botItemsMoney; @@ -214,12 +214,12 @@ bool TradeStatusAction::CheckTrade() int32 botMoney = bot->GetTradeData()->GetMoney() + botItemsMoney; int32 playerItemsMoney = CalculateCost(trader, false); int32 playerMoney = trader->GetTradeData()->GetMoney() + playerItemsMoney; - if (botItemsMoney > 0 && sPlayerbotAIConfig->enableRandomBotTrading == 2 && (sRandomPlayerbotMgr->IsRandomBot(bot)|| sRandomPlayerbotMgr->IsAddclassBot(bot))) + if (botItemsMoney > 0 && sPlayerbotAIConfig.enableRandomBotTrading == 2 && (sRandomPlayerbotMgr.IsRandomBot(bot)|| sRandomPlayerbotMgr.IsAddclassBot(bot))) { bot->Whisper("Selling is disabled.", LANG_UNIVERSAL, trader); return false; } - if (playerItemsMoney && sPlayerbotAIConfig->enableRandomBotTrading == 3 && (sRandomPlayerbotMgr->IsRandomBot(bot)|| sRandomPlayerbotMgr->IsAddclassBot(bot))) + if (playerItemsMoney && sPlayerbotAIConfig.enableRandomBotTrading == 3 && (sRandomPlayerbotMgr.IsRandomBot(bot)|| sRandomPlayerbotMgr.IsAddclassBot(bot))) { bot->Whisper("Buying is disabled.", LANG_UNIVERSAL, trader); return false; @@ -262,7 +262,7 @@ bool TradeStatusAction::CheckTrade() return false; } - int32 discount = (int32)sRandomPlayerbotMgr->GetTradeDiscount(bot, trader); + int32 discount = (int32)sRandomPlayerbotMgr.GetTradeDiscount(bot, trader); int32 delta = playerMoney - botMoney; int32 moneyDelta = (int32)trader->GetTradeData()->GetMoney() - (int32)bot->GetTradeData()->GetMoney(); bool success = false; @@ -287,7 +287,7 @@ bool TradeStatusAction::CheckTrade() if (success) { - sRandomPlayerbotMgr->AddTradeDiscount(bot, trader, delta); + sRandomPlayerbotMgr.AddTradeDiscount(bot, trader, delta); switch (urand(0, 4)) { case 0: @@ -353,11 +353,11 @@ int32 TradeStatusAction::CalculateCost(Player* player, bool sell) if (sell) { - sum += item->GetCount() * proto->SellPrice * sRandomPlayerbotMgr->GetSellMultiplier(bot); + sum += item->GetCount() * proto->SellPrice * sRandomPlayerbotMgr.GetSellMultiplier(bot); } else { - sum += item->GetCount() * proto->BuyPrice * sRandomPlayerbotMgr->GetBuyMultiplier(bot); + sum += item->GetCount() * proto->BuyPrice * sRandomPlayerbotMgr.GetBuyMultiplier(bot); } } diff --git a/src/Ai/Base/Actions/TrainerAction.cpp b/src/Ai/Base/Actions/TrainerAction.cpp index bca7406012..e377fa3eb2 100644 --- a/src/Ai/Base/Actions/TrainerAction.cpp +++ b/src/Ai/Base/Actions/TrainerAction.cpp @@ -12,7 +12,7 @@ void TrainerAction::Learn(uint32 cost, const Trainer::Spell tSpell, std::ostringstream& msg) { - if (sPlayerbotAIConfig->autoTrainSpells != "free" && !botAI->HasCheat(BotCheatMask::gold)) + if (sPlayerbotAIConfig.autoTrainSpells != "free" && !botAI->HasCheat(BotCheatMask::gold)) { if (AI_VALUE2(uint32, "free money for", (uint32)NeedMoneyFor::spells) < cost) { @@ -126,8 +126,8 @@ bool TrainerAction::Execute(Event event) if (spell) spells.insert(spell); - if (text.find("learn") != std::string::npos || sRandomPlayerbotMgr->IsRandomBot(bot) || - (sPlayerbotAIConfig->autoTrainSpells != "no" && + if (text.find("learn") != std::string::npos || sRandomPlayerbotMgr.IsRandomBot(bot) || + (sPlayerbotAIConfig.autoTrainSpells != "no" && (trainer->GetTrainerType() != Trainer::Type::Tradeskill || !botAI->HasActivePlayerMaster()))) // Todo rewrite to only exclude start primary profession skills and make // config dependent. @@ -157,7 +157,7 @@ void TrainerAction::TellFooter(uint32 totalCost) bool MaintenanceAction::Execute(Event event) { - if (!sPlayerbotAIConfig->maintenanceCommand) + if (!sPlayerbotAIConfig.maintenanceCommand) { botAI->TellError("maintenance command is not allowed, please check the configuration."); return false; @@ -186,66 +186,66 @@ bool MaintenanceAction::Execute(Event event) factory.InitMounts(); factory.InitGlyphs(false); factory.InitKeyring(); - if (bot->GetLevel() >= sPlayerbotAIConfig->minEnchantingBotLevel) + if (bot->GetLevel() >= sPlayerbotAIConfig.minEnchantingBotLevel) factory.ApplyEnchantAndGemsNew(); } else { - if (sPlayerbotAIConfig->altMaintenanceAttunementQs) + if (sPlayerbotAIConfig.altMaintenanceAttunementQs) factory.InitAttunementQuests(); - if (sPlayerbotAIConfig->altMaintenanceBags) + if (sPlayerbotAIConfig.altMaintenanceBags) factory.InitBags(false); - if (sPlayerbotAIConfig->altMaintenanceAmmo) + if (sPlayerbotAIConfig.altMaintenanceAmmo) factory.InitAmmo(); - if (sPlayerbotAIConfig->altMaintenanceFood) + if (sPlayerbotAIConfig.altMaintenanceFood) factory.InitFood(); - if (sPlayerbotAIConfig->altMaintenanceReagents) + if (sPlayerbotAIConfig.altMaintenanceReagents) factory.InitReagents(); - if (sPlayerbotAIConfig->altMaintenanceConsumables) + if (sPlayerbotAIConfig.altMaintenanceConsumables) factory.InitConsumables(); - if (sPlayerbotAIConfig->altMaintenancePotions) + if (sPlayerbotAIConfig.altMaintenancePotions) factory.InitPotions(); - if (sPlayerbotAIConfig->altMaintenanceTalentTree) + if (sPlayerbotAIConfig.altMaintenanceTalentTree) factory.InitTalentsTree(true); - if (sPlayerbotAIConfig->altMaintenancePet) + if (sPlayerbotAIConfig.altMaintenancePet) factory.InitPet(); - if (sPlayerbotAIConfig->altMaintenancePetTalents) + if (sPlayerbotAIConfig.altMaintenancePetTalents) factory.InitPetTalents(); - if (sPlayerbotAIConfig->altMaintenanceSkills) + if (sPlayerbotAIConfig.altMaintenanceSkills) factory.InitSkills(); - if (sPlayerbotAIConfig->altMaintenanceClassSpells) + if (sPlayerbotAIConfig.altMaintenanceClassSpells) factory.InitClassSpells(); - if (sPlayerbotAIConfig->altMaintenanceAvailableSpells) + if (sPlayerbotAIConfig.altMaintenanceAvailableSpells) factory.InitAvailableSpells(); - if (sPlayerbotAIConfig->altMaintenanceReputation) + if (sPlayerbotAIConfig.altMaintenanceReputation) factory.InitReputation(); - if (sPlayerbotAIConfig->altMaintenanceSpecialSpells) + if (sPlayerbotAIConfig.altMaintenanceSpecialSpells) factory.InitSpecialSpells(); - if (sPlayerbotAIConfig->altMaintenanceMounts) + if (sPlayerbotAIConfig.altMaintenanceMounts) factory.InitMounts(); - if (sPlayerbotAIConfig->altMaintenanceGlyphs) + if (sPlayerbotAIConfig.altMaintenanceGlyphs) factory.InitGlyphs(false); - if (sPlayerbotAIConfig->altMaintenanceKeyring) + if (sPlayerbotAIConfig.altMaintenanceKeyring) factory.InitKeyring(); - if (sPlayerbotAIConfig->altMaintenanceGemsEnchants && bot->GetLevel() >= sPlayerbotAIConfig->minEnchantingBotLevel) + if (sPlayerbotAIConfig.altMaintenanceGemsEnchants && bot->GetLevel() >= sPlayerbotAIConfig.minEnchantingBotLevel) factory.ApplyEnchantAndGemsNew(); } @@ -267,28 +267,28 @@ bool RemoveGlyphAction::Execute(Event event) bool AutoGearAction::Execute(Event event) { - if (!sPlayerbotAIConfig->autoGearCommand) + if (!sPlayerbotAIConfig.autoGearCommand) { botAI->TellError("autogear command is not allowed, please check the configuration."); return false; } - if (!sPlayerbotAIConfig->autoGearCommandAltBots && - !sPlayerbotAIConfig->IsInRandomAccountList(bot->GetSession()->GetAccountId())) + if (!sPlayerbotAIConfig.autoGearCommandAltBots && + !sPlayerbotAIConfig.IsInRandomAccountList(bot->GetSession()->GetAccountId())) { botAI->TellError("You cannot use autogear on alt bots."); return false; } botAI->TellMaster("I'm auto gearing"); - uint32 gs = sPlayerbotAIConfig->autoGearScoreLimit == 0 + uint32 gs = sPlayerbotAIConfig.autoGearScoreLimit == 0 ? 0 - : PlayerbotFactory::CalcMixedGearScore(sPlayerbotAIConfig->autoGearScoreLimit, - sPlayerbotAIConfig->autoGearQualityLimit); - PlayerbotFactory factory(bot, bot->GetLevel(), sPlayerbotAIConfig->autoGearQualityLimit, gs); + : PlayerbotFactory::CalcMixedGearScore(sPlayerbotAIConfig.autoGearScoreLimit, + sPlayerbotAIConfig.autoGearQualityLimit); + PlayerbotFactory factory(bot, bot->GetLevel(), sPlayerbotAIConfig.autoGearQualityLimit, gs); factory.InitEquipment(true); factory.InitAmmo(); - if (bot->GetLevel() >= sPlayerbotAIConfig->minEnchantingBotLevel) + if (bot->GetLevel() >= sPlayerbotAIConfig.minEnchantingBotLevel) { factory.ApplyEnchantAndGemsNew(); } diff --git a/src/Ai/Base/Actions/TravelAction.cpp b/src/Ai/Base/Actions/TravelAction.cpp index f99f8b29d3..f0afef01bf 100644 --- a/src/Ai/Base/Actions/TravelAction.cpp +++ b/src/Ai/Base/Actions/TravelAction.cpp @@ -21,14 +21,14 @@ bool TravelAction::Execute(Event event) Unit* newTarget = nullptr; std::list targets; - Acore::AnyUnitInObjectRangeCheck u_check(bot, sPlayerbotAIConfig->sightDistance * 2); + Acore::AnyUnitInObjectRangeCheck u_check(bot, sPlayerbotAIConfig.sightDistance * 2); Acore::UnitListSearcher searcher(bot, targets, u_check); - Cell::VisitObjects(bot, searcher, sPlayerbotAIConfig->sightDistance); + Cell::VisitObjects(bot, searcher, sPlayerbotAIConfig.sightDistance); for (Unit* unit : targets) { newTarget = unit; - if (!newTarget) + if (!newTarget || !newTarget->IsInWorld() || newTarget->IsDuringRemoveFromWorld()) continue; if (newTarget->GetMapId() != bot->GetMapId()) @@ -77,7 +77,7 @@ bool MoveToDarkPortalAction::Execute(Event event) if (bot->GetTeamId() == TEAM_ALLIANCE) { Quest const* quest = sObjectMgr->GetQuestTemplate(10119); - CreatureData const* creatureData = sRandomPlayerbotMgr->GetCreatureDataByEntry(16841); + CreatureData const* creatureData = sRandomPlayerbotMgr.GetCreatureDataByEntry(16841); if (quest && creatureData) { auto creatureBounds = @@ -89,7 +89,7 @@ bool MoveToDarkPortalAction::Execute(Event event) else { Quest const* quest = sObjectMgr->GetQuestTemplate(9407); - CreatureData const* creatureData = sRandomPlayerbotMgr->GetCreatureDataByEntry(19254); + CreatureData const* creatureData = sRandomPlayerbotMgr.GetCreatureDataByEntry(19254); if (quest && creatureData) { auto creatureBounds = diff --git a/src/Ai/Base/Actions/UseItemAction.cpp b/src/Ai/Base/Actions/UseItemAction.cpp index 690d2d4b77..473816e3ec 100644 --- a/src/Ai/Base/Actions/UseItemAction.cpp +++ b/src/Ai/Base/Actions/UseItemAction.cpp @@ -187,7 +187,7 @@ bool UseItemAction::UseItem(Item* item, ObjectGuid goGuid, Item* itemTarget, Uni if (bot->isMoving()) { bot->StopMoving(); - botAI->SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown); + botAI->SetNextCheckDelay(sPlayerbotAIConfig.globalCoolDown); return false; } @@ -229,7 +229,7 @@ bool UseItemAction::UseItem(Item* item, ObjectGuid goGuid, Item* itemTarget, Uni out << " on " << chat->FormatItem(itemForSpell->GetTemplate()); } uint32 castTime = spellInfo->CalcCastTime(); - botAI->SetNextCheckDelay(castTime + sPlayerbotAIConfig->reactDelay); + botAI->SetNextCheckDelay(castTime + sPlayerbotAIConfig.reactDelay); } break; @@ -245,8 +245,10 @@ bool UseItemAction::UseItem(Item* item, ObjectGuid goGuid, Item* itemTarget, Uni { packet << unitTarget->GetGUID(); targetSelected = true; - // If the target is bot or is an enemy, say "on self" - if (unitTarget == bot || (unitTarget->IsHostileTo(bot))) + + if (unitTarget == bot || !unitTarget->IsInWorld() || unitTarget->IsDuringRemoveFromWorld()) + out << " on self"; + else if (unitTarget->IsHostileTo(bot)) out << " on self"; else out << " on " << unitTarget->GetName(); @@ -305,7 +307,7 @@ bool UseItemAction::UseItem(Item* item, ObjectGuid goGuid, Item* itemTarget, Uni if (!spellId) return false; - // botAI->SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown); + // botAI->SetNextCheckDelay(sPlayerbotAIConfig.globalCoolDown); botAI->TellMasterNoFacing(out.str()); bot->GetSession()->HandleUseItemOpcode(packet); return true; @@ -484,7 +486,7 @@ bool UseRandomQuestItem::Execute(Event event) bool used = UseItem(item, goTarget, nullptr, unitTarget); if (used) - botAI->SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown); + botAI->SetNextCheckDelay(sPlayerbotAIConfig.globalCoolDown); return used; } diff --git a/src/Ai/Base/Actions/UseMeetingStoneAction.cpp b/src/Ai/Base/Actions/UseMeetingStoneAction.cpp index 323d9d5859..b334429189 100644 --- a/src/Ai/Base/Actions/UseMeetingStoneAction.cpp +++ b/src/Ai/Base/Actions/UseMeetingStoneAction.cpp @@ -91,9 +91,9 @@ bool SummonAction::Execute(Event event) bool SummonAction::SummonUsingGos(Player* summoner, Player* player, bool preserveAuras) { std::list targets; - AnyGameObjectInObjectRangeCheck u_check(summoner, sPlayerbotAIConfig->sightDistance); + AnyGameObjectInObjectRangeCheck u_check(summoner, sPlayerbotAIConfig.sightDistance); Acore::GameObjectListSearcher searcher(summoner, targets, u_check); - Cell::VisitObjects(summoner, searcher, sPlayerbotAIConfig->sightDistance); + Cell::VisitObjects(summoner, searcher, sPlayerbotAIConfig.sightDistance); for (GameObject* go : targets) { @@ -107,13 +107,13 @@ bool SummonAction::SummonUsingGos(Player* summoner, Player* player, bool preserv bool SummonAction::SummonUsingNpcs(Player* summoner, Player* player, bool preserveAuras) { - if (!sPlayerbotAIConfig->summonAtInnkeepersEnabled) + if (!sPlayerbotAIConfig.summonAtInnkeepersEnabled) return false; std::list targets; - Acore::AnyUnitInObjectRangeCheck u_check(summoner, sPlayerbotAIConfig->sightDistance); + Acore::AnyUnitInObjectRangeCheck u_check(summoner, sPlayerbotAIConfig.sightDistance); Acore::UnitListSearcher searcher(summoner, targets, u_check); - Cell::VisitObjects(summoner, searcher, sPlayerbotAIConfig->sightDistance); + Cell::VisitObjects(summoner, searcher, sPlayerbotAIConfig.sightDistance); for (Unit* unit : targets) { @@ -150,7 +150,7 @@ bool SummonAction::SummonUsingNpcs(Player* summoner, Player* player, bool preser bool SummonAction::Teleport(Player* summoner, Player* player, bool preserveAuras) { // Player* master = GetMaster(); - if (!summoner) + if (!summoner || summoner == player) return false; if (player->GetVehicle()) @@ -165,38 +165,37 @@ bool SummonAction::Teleport(Player* summoner, Player* player, bool preserveAuras for (float angle = followAngle - M_PI; angle <= followAngle + M_PI; angle += M_PI / 4) { uint32 mapId = summoner->GetMapId(); - float x = summoner->GetPositionX() + cos(angle) * sPlayerbotAIConfig->followDistance; - float y = summoner->GetPositionY() + sin(angle) * sPlayerbotAIConfig->followDistance; + float x = summoner->GetPositionX() + cos(angle) * sPlayerbotAIConfig.followDistance; + float y = summoner->GetPositionY() + sin(angle) * sPlayerbotAIConfig.followDistance; float z = summoner->GetPositionZ(); if (summoner->IsWithinLOS(x, y, z)) { - if (sPlayerbotAIConfig - ->botRepairWhenSummon) // .conf option to repair bot gear when summoned 0 = off, 1 = on + if (sPlayerbotAIConfig.botRepairWhenSummon) // .conf option to repair bot gear when summoned 0 = off, 1 = on bot->DurabilityRepairAll(false, 1.0f, false); - if (summoner->IsInCombat() && !sPlayerbotAIConfig->allowSummonInCombat) + if (summoner->IsInCombat() && !sPlayerbotAIConfig.allowSummonInCombat) { botAI->TellError("You cannot summon me while you're in combat"); return false; } - if (!summoner->IsAlive() && !sPlayerbotAIConfig->allowSummonWhenMasterIsDead) + if (!summoner->IsAlive() && !sPlayerbotAIConfig.allowSummonWhenMasterIsDead) { botAI->TellError("You cannot summon me while you're dead"); return false; } if (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST) && - !sPlayerbotAIConfig->allowSummonWhenBotIsDead) + !sPlayerbotAIConfig.allowSummonWhenBotIsDead) { botAI->TellError("You cannot summon me while I'm dead, you need to release my spirit first"); return false; } bool revive = - sPlayerbotAIConfig->reviveBotWhenSummoned == 2 || - (sPlayerbotAIConfig->reviveBotWhenSummoned == 1 && !summoner->IsInCombat() && summoner->IsAlive()); + sPlayerbotAIConfig.reviveBotWhenSummoned == 2 || + (sPlayerbotAIConfig.reviveBotWhenSummoned == 1 && !summoner->IsInCombat() && summoner->IsAlive()); if (bot->isDead() && revive) { @@ -212,9 +211,11 @@ bool SummonAction::Teleport(Player* summoner, Player* player, bool preserveAuras if (!preserveAuras) player->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TELEPORTED | AURA_INTERRUPT_FLAG_CHANGE_MAP); - player->TeleportTo(mapId, x, y, z, 0); - + if (player->GetPet()) + player->GetPet()->NearTeleportTo(x, y, z, player->GetOrientation()); + if (player->GetGuardianPet()) + player->GetGuardianPet()->NearTeleportTo(x, y, z, player->GetOrientation()); if (botAI->HasStrategy("stay", botAI->GetState())) { PositionMap& posMap = AI_VALUE(PositionMap&, "position"); diff --git a/src/Ai/Base/Actions/VehicleActions.cpp b/src/Ai/Base/Actions/VehicleActions.cpp index ee1c6e2dd8..ac925fbcb1 100644 --- a/src/Ai/Base/Actions/VehicleActions.cpp +++ b/src/Ai/Base/Actions/VehicleActions.cpp @@ -74,7 +74,7 @@ bool EnterVehicleAction::Execute(Event event) bool EnterVehicleAction::EnterVehicle(Unit* vehicleBase, bool moveIfFar) { - float dist = sServerFacade->GetDistance2d(bot, vehicleBase); + float dist = ServerFacade::instance().GetDistance2d(bot, vehicleBase); if (dist > 40.0f) return false; diff --git a/src/Ai/Base/Actions/WhoAction.cpp b/src/Ai/Base/Actions/WhoAction.cpp index edafdfcb27..8f83b6e489 100644 --- a/src/Ai/Base/Actions/WhoAction.cpp +++ b/src/Ai/Base/Actions/WhoAction.cpp @@ -33,7 +33,7 @@ bool WhoAction::Execute(Event event) { out << QuerySkill(text); - if (sRandomPlayerbotMgr->IsRandomBot(bot)) + if (sRandomPlayerbotMgr.IsRandomBot(bot)) out << QueryTrade(text); } else @@ -74,7 +74,7 @@ std::string const WhoAction::QueryTrade(std::string const text) for (Item* sell : items) { int32 sellPrice = - sell->GetTemplate()->SellPrice * sRandomPlayerbotMgr->GetSellMultiplier(bot) * sell->GetCount(); + sell->GetTemplate()->SellPrice * sRandomPlayerbotMgr.GetSellMultiplier(bot) * sell->GetCount(); if (!sellPrice) continue; diff --git a/src/Ai/Base/Actions/WorldBuffAction.cpp b/src/Ai/Base/Actions/WorldBuffAction.cpp index 3cd770e4d0..b2bf4e096f 100644 --- a/src/Ai/Base/Actions/WorldBuffAction.cpp +++ b/src/Ai/Base/Actions/WorldBuffAction.cpp @@ -25,7 +25,7 @@ std::vector WorldBuffAction::NeedWorldBuffs(Unit* unit) { std::vector retVec; - if (sPlayerbotAIConfig->worldBuffs.empty()) + if (sPlayerbotAIConfig.worldBuffs.empty()) return retVec; FactionTemplateEntry const* humanFaction = sFactionTemplateStore.LookupEntry(1); @@ -70,7 +70,7 @@ std::vector WorldBuffAction::NeedWorldBuffs(Unit* unit) // If tank, effectiveSpec remains unchanged } - for (auto const& wb : sPlayerbotAIConfig->worldBuffs) + for (auto const& wb : sPlayerbotAIConfig.worldBuffs) { // Faction check if (wb.factionId != 0 && wb.factionId != factionId) diff --git a/src/Ai/Base/Actions/WtsAction.cpp b/src/Ai/Base/Actions/WtsAction.cpp index a3c77c27f9..950ab7d05f 100644 --- a/src/Ai/Base/Actions/WtsAction.cpp +++ b/src/Ai/Base/Actions/WtsAction.cpp @@ -20,7 +20,7 @@ bool WtsAction::Execute(Event event) std::ostringstream out; std::string const text = event.getParam(); - if (!sRandomPlayerbotMgr->IsRandomBot(bot)) + if (!sRandomPlayerbotMgr.IsRandomBot(bot)) return false; std::string const link = event.getParam(); @@ -42,7 +42,7 @@ bool WtsAction::Execute(Event event) if (usage == ITEM_USAGE_NONE) continue; - int32 buyPrice = proto->BuyPrice * sRandomPlayerbotMgr->GetBuyMultiplier(bot); + int32 buyPrice = proto->BuyPrice * sRandomPlayerbotMgr.GetBuyMultiplier(bot); if (!buyPrice) continue; diff --git a/src/Ai/Base/Actions/XpGainAction.cpp b/src/Ai/Base/Actions/XpGainAction.cpp index 4048ce3af8..fba57180f2 100644 --- a/src/Ai/Base/Actions/XpGainAction.cpp +++ b/src/Ai/Base/Actions/XpGainAction.cpp @@ -40,14 +40,14 @@ bool XpGainAction::Execute(Event event) } // randomBotXPRate is now implemented in OnPlayerGiveXP script - // if (!sRandomPlayerbotMgr->IsRandomBot(bot) || sPlayerbotAIConfig->randomBotXPRate == 1) + // if (!sRandomPlayerbotMgr.IsRandomBot(bot) || sPlayerbotAIConfig.randomBotXPRate == 1) // return true; // Unit* victim = nullptr; // if (guid) // victim = botAI->GetUnit(guid); - // xpgain = xpgain * (sPlayerbotAIConfig->randomBotXPRate - 1); + // xpgain = xpgain * (sPlayerbotAIConfig.randomBotXPRate - 1); // GiveXP(xpgain, victim); return true; diff --git a/src/Ai/Base/ChatActionContext.h b/src/Ai/Base/ChatActionContext.h index 4873f52005..33430b63e7 100644 --- a/src/Ai/Base/ChatActionContext.h +++ b/src/Ai/Base/ChatActionContext.h @@ -67,6 +67,7 @@ #include "TellItemCountAction.h" #include "TellLosAction.h" #include "TellReputationAction.h" +#include "TellPvpStatsAction.h" #include "TellTargetAction.h" #include "TradeAction.h" #include "TrainerAction.h" @@ -97,6 +98,7 @@ class ChatActionContext : public NamedObjectContext creators["quests"] = &ChatActionContext::quests; creators["leave"] = &ChatActionContext::leave; creators["reputation"] = &ChatActionContext::reputation; + creators["tell pvp stats"] = &ChatActionContext::tell_pvp_stats; creators["log"] = &ChatActionContext::log; creators["los"] = &ChatActionContext::los; creators["rpg status"] = &ChatActionContext::rpg_status; @@ -186,6 +188,7 @@ class ChatActionContext : public NamedObjectContext creators["guild leave"] = &ChatActionContext::guild_leave; creators["rtsc"] = &ChatActionContext::rtsc; creators["bwl chat shortcut"] = &ChatActionContext::bwl_chat_shortcut; + creators["naxx chat shortcut"] = &ChatActionContext::naxx_chat_shortcut; creators["tell estimated dps"] = &ChatActionContext::tell_estimated_dps; creators["join"] = &ChatActionContext::join; creators["lfg"] = &ChatActionContext::lfg; @@ -279,6 +282,7 @@ class ChatActionContext : public NamedObjectContext static Action* quests(PlayerbotAI* botAI) { return new ListQuestsAction(botAI); } static Action* leave(PlayerbotAI* botAI) { return new LeaveGroupAction(botAI); } static Action* reputation(PlayerbotAI* botAI) { return new TellReputationAction(botAI); } + static Action* tell_pvp_stats(PlayerbotAI* botAI) { return new TellPvpStatsAction(botAI); } static Action* log(PlayerbotAI* botAI) { return new LogLevelAction(botAI); } static Action* los(PlayerbotAI* botAI) { return new TellLosAction(botAI); } static Action* rpg_status(PlayerbotAI* botAI) { return new TellRpgStatusAction(botAI); } @@ -297,6 +301,7 @@ class ChatActionContext : public NamedObjectContext static Action* guild_remove(PlayerbotAI* botAI) { return new GuildRemoveAction(botAI); } static Action* guild_leave(PlayerbotAI* botAI) { return new GuildLeaveAction(botAI); } static Action* rtsc(PlayerbotAI* botAI) { return new RTSCAction(botAI); } + static Action* naxx_chat_shortcut(PlayerbotAI* ai) { return new NaxxChatShortcutAction(ai); } static Action* bwl_chat_shortcut(PlayerbotAI* ai) { return new BwlChatShortcutAction(ai); } static Action* tell_estimated_dps(PlayerbotAI* ai) { return new TellEstimatedDpsAction(ai); } static Action* join(PlayerbotAI* ai) { return new JoinGroupAction(ai); } diff --git a/src/Ai/Base/ChatTriggerContext.h b/src/Ai/Base/ChatTriggerContext.h index b3498ce301..60cbb7951c 100644 --- a/src/Ai/Base/ChatTriggerContext.h +++ b/src/Ai/Base/ChatTriggerContext.h @@ -24,6 +24,7 @@ class ChatTriggerContext : public NamedObjectContext creators["leave"] = &ChatTriggerContext::leave; creators["rep"] = &ChatTriggerContext::reputation; creators["reputation"] = &ChatTriggerContext::reputation; + creators["pvp stats"] = &ChatTriggerContext::pvp_stats; creators["log"] = &ChatTriggerContext::log; creators["los"] = &ChatTriggerContext::los; creators["rpg status"] = &ChatTriggerContext::rpg_status; @@ -126,6 +127,7 @@ class ChatTriggerContext : public NamedObjectContext creators["guild leave"] = &ChatTriggerContext::guild_leave; creators["rtsc"] = &ChatTriggerContext::rtsc; creators["drink"] = &ChatTriggerContext::drink; + // creators["naxx"] = &ChatTriggerContext::naxx; // creators["bwl"] = &ChatTriggerContext::bwl; creators["dps"] = &ChatTriggerContext::dps; creators["disperse"] = &ChatTriggerContext::disperse; @@ -224,6 +226,7 @@ class ChatTriggerContext : public NamedObjectContext static Trigger* stats(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "stats"); } static Trigger* leave(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "leave"); } static Trigger* reputation(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "reputation"); } + static Trigger* pvp_stats(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "pvp stats"); } static Trigger* log(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "log"); } static Trigger* los(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "los"); } static Trigger* rpg_status(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "rpg status"); } @@ -243,6 +246,7 @@ class ChatTriggerContext : public NamedObjectContext static Trigger* guild_leave(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "guild leave"); } static Trigger* rtsc(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "rtsc"); } static Trigger* drink(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "drink"); } + // static Trigger* naxx(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "naxx"); } // static Trigger* bwl(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "bwl"); } static Trigger* dps(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "dps"); } static Trigger* disperse(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "disperse"); } diff --git a/src/Ai/Base/SharedValueContext.h b/src/Ai/Base/SharedValueContext.h index 23b8266bdd..94653aeabf 100644 --- a/src/Ai/Base/SharedValueContext.h +++ b/src/Ai/Base/SharedValueContext.h @@ -12,39 +12,14 @@ #include "PvpValues.h" #include "QuestValues.h" -class PlayerbotAI; - class SharedValueContext : public NamedObjectContext { public: - SharedValueContext() : NamedObjectContext(true) - { - creators["bg masters"] = &SharedValueContext::bg_masters; - creators["drop map"] = &SharedValueContext::drop_map; - creators["item drop list"] = &SharedValueContext::item_drop_list; - creators["entry loot list"] = &SharedValueContext::entry_loot_list; - - creators["entry quest relation"] = &SharedValueContext::entry_quest_relation; - creators["quest guidp map"] = &SharedValueContext::quest_guidp_map; - creators["quest givers"] = &SharedValueContext::quest_givers; - } - -private: - static UntypedValue* bg_masters(PlayerbotAI* botAI) { return new BgMastersValue(botAI); } - static UntypedValue* drop_map(PlayerbotAI* botAI) { return new DropMapValue(botAI); } - static UntypedValue* item_drop_list(PlayerbotAI* botAI) { return new ItemDropListValue(botAI); } - static UntypedValue* entry_loot_list(PlayerbotAI* botAI) { return new EntryLootListValue(botAI); } - - static UntypedValue* entry_quest_relation(PlayerbotAI* botAI) { return new EntryQuestRelationMapValue(botAI); } - static UntypedValue* quest_guidp_map(PlayerbotAI* botAI) { return new QuestGuidpMapValue(botAI); } - static UntypedValue* quest_givers(PlayerbotAI* botAI) { return new QuestGiversValue(botAI); } - - // Global acess functions -public: - static SharedValueContext* instance() + static SharedValueContext& instance() { static SharedValueContext instance; - return &instance; + + return instance; } template @@ -74,6 +49,36 @@ class SharedValueContext : public NamedObjectContext out << param; return getGlobalValue(name, out.str()); } + +private: + SharedValueContext() : NamedObjectContext(true) + { + creators["bg masters"] = &SharedValueContext::bg_masters; + creators["drop map"] = &SharedValueContext::drop_map; + creators["item drop list"] = &SharedValueContext::item_drop_list; + creators["entry loot list"] = &SharedValueContext::entry_loot_list; + + creators["entry quest relation"] = &SharedValueContext::entry_quest_relation; + creators["quest guidp map"] = &SharedValueContext::quest_guidp_map; + creators["quest givers"] = &SharedValueContext::quest_givers; + } + ~SharedValueContext() = default; + + SharedValueContext(const SharedValueContext&) = delete; + SharedValueContext& operator=(const SharedValueContext&) = delete; + + SharedValueContext(SharedValueContext&&) = delete; + SharedValueContext& operator=(SharedValueContext&&) = delete; + + static UntypedValue* bg_masters(PlayerbotAI* botAI) { return new BgMastersValue(botAI); } + static UntypedValue* drop_map(PlayerbotAI* botAI) { return new DropMapValue(botAI); } + static UntypedValue* item_drop_list(PlayerbotAI* botAI) { return new ItemDropListValue(botAI); } + static UntypedValue* entry_loot_list(PlayerbotAI* botAI) { return new EntryLootListValue(botAI); } + + static UntypedValue* entry_quest_relation(PlayerbotAI* botAI) { return new EntryQuestRelationMapValue(botAI); } + static UntypedValue* quest_guidp_map(PlayerbotAI* botAI) { return new QuestGuidpMapValue(botAI); } + static UntypedValue* quest_givers(PlayerbotAI* botAI) { return new QuestGiversValue(botAI); } + }; #define sSharedValueContext SharedValueContext::instance() diff --git a/src/Ai/Base/Strategy/CastTimeStrategy.cpp b/src/Ai/Base/Strategy/CastTimeStrategy.cpp index 042d1c9e41..7c70923d40 100644 --- a/src/Ai/Base/Strategy/CastTimeStrategy.cpp +++ b/src/Ai/Base/Strategy/CastTimeStrategy.cpp @@ -16,7 +16,7 @@ float CastTimeMultiplier::GetValue(Action* action) if (!action->GetTarget() || action->GetTarget() != AI_VALUE(Unit*, "current target")) return 1.0f; - if (/*targetHealth < sPlayerbotAIConfig->criticalHealth && */ dynamic_cast(action)) + if (/*targetHealth < sPlayerbotAIConfig.criticalHealth && */ dynamic_cast(action)) { CastSpellAction* spellAction = dynamic_cast(action); uint32 spellId = AI_VALUE2(uint32, "spell id", spellAction->getSpell()); diff --git a/src/Ai/Base/Strategy/ChatCommandHandlerStrategy.cpp b/src/Ai/Base/Strategy/ChatCommandHandlerStrategy.cpp index 0a81686a9d..8e18c6bbb5 100644 --- a/src/Ai/Base/Strategy/ChatCommandHandlerStrategy.cpp +++ b/src/Ai/Base/Strategy/ChatCommandHandlerStrategy.cpp @@ -27,6 +27,7 @@ void ChatCommandHandlerStrategy::InitTriggers(std::vector& trigger PassTroughStrategy::InitTriggers(triggers); triggers.push_back(new TriggerNode("rep", { NextAction("reputation", relevance) })); + triggers.push_back(new TriggerNode("pvp stats", { NextAction("tell pvp stats", relevance) })); triggers.push_back(new TriggerNode("q", { NextAction("query quest", relevance), NextAction("query item usage", relevance) })); triggers.push_back(new TriggerNode("add all loot", { NextAction("add all loot", relevance), @@ -84,6 +85,8 @@ void ChatCommandHandlerStrategy::InitTriggers(std::vector& trigger new TriggerNode("target", { NextAction("tell target", relevance) })); triggers.push_back( new TriggerNode("ready", { NextAction("ready check", relevance) })); + triggers.push_back( + new TriggerNode("naxx", {NextAction("naxx chat shortcut", relevance)})); triggers.push_back( new TriggerNode("bwl", { NextAction("bwl chat shortcut", relevance) })); triggers.push_back( @@ -116,6 +119,7 @@ ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : Pas supported.push_back("stats"); supported.push_back("leave"); supported.push_back("reputation"); + supported.push_back("tell pvp stats"); supported.push_back("log"); supported.push_back("los"); supported.push_back("rpg status"); diff --git a/src/Ai/Base/Strategy/ConserveManaStrategy.cpp b/src/Ai/Base/Strategy/ConserveManaStrategy.cpp index adc3cec884..3acabcd4de 100644 --- a/src/Ai/Base/Strategy/ConserveManaStrategy.cpp +++ b/src/Ai/Base/Strategy/ConserveManaStrategy.cpp @@ -19,9 +19,9 @@ // uint8 targetHealth = AI_VALUE2(uint8, "health", "current target"); // uint8 mana = AI_VALUE2(uint8, "mana", "self target"); // bool hasMana = AI_VALUE2(bool, "has mana", "self target"); -// bool mediumMana = hasMana && mana < sPlayerbotAIConfig->mediumMana; +// bool mediumMana = hasMana && mana < sPlayerbotAIConfig.mediumMana; -// if (health < sPlayerbotAIConfig->lowHealth) +// if (health < sPlayerbotAIConfig.lowHealth) // return 1.0f; // Unit* target = AI_VALUE(Unit*, "current target"); @@ -92,7 +92,7 @@ float HealerAutoSaveManaMultiplier::GetValue(Action* action) { uint8 mana = bot->GetPowerPct(Powers::POWER_MANA); - if (mana > sPlayerbotAIConfig->saveManaThreshold) + if (mana > sPlayerbotAIConfig.saveManaThreshold) return 1.0f; CastHealingSpellAction* healingAction = dynamic_cast(action); @@ -110,16 +110,16 @@ float HealerAutoSaveManaMultiplier::GetValue(Action* action) if (isTank) { estAmount /= 1.5; // tanks have more health - if (health >= sPlayerbotAIConfig->mediumHealth && + if (health >= sPlayerbotAIConfig.mediumHealth && (lossAmount < estAmount || manaEfficiency <= HealingManaEfficiency::MEDIUM)) return 0.0f; - if (health >= sPlayerbotAIConfig->lowHealth && + if (health >= sPlayerbotAIConfig.lowHealth && (lossAmount < estAmount || manaEfficiency <= HealingManaEfficiency::LOW)) return 0.0f; } else { - if (health >= sPlayerbotAIConfig->mediumHealth && + if (health >= sPlayerbotAIConfig.mediumHealth && (lossAmount < estAmount || manaEfficiency <= HealingManaEfficiency::MEDIUM)) return 0.0f; if (lossAmount < estAmount || manaEfficiency <= HealingManaEfficiency::LOW) @@ -131,4 +131,4 @@ float HealerAutoSaveManaMultiplier::GetValue(Action* action) void HealerAutoSaveManaStrategy::InitMultipliers(std::vector& multipliers) { multipliers.push_back(new HealerAutoSaveManaMultiplier(botAI)); -} \ No newline at end of file +} diff --git a/src/Ai/Base/Strategy/EmoteStrategy.cpp b/src/Ai/Base/Strategy/EmoteStrategy.cpp index 9419e0c386..f2e002e8d7 100644 --- a/src/Ai/Base/Strategy/EmoteStrategy.cpp +++ b/src/Ai/Base/Strategy/EmoteStrategy.cpp @@ -9,7 +9,7 @@ void EmoteStrategy::InitTriggers(std::vector& triggers) { - if (sPlayerbotAIConfig->randomBotEmote) + if (sPlayerbotAIConfig.randomBotEmote) { triggers.push_back(new TriggerNode("often", { NextAction("talk", 1.0f) })); triggers.push_back(new TriggerNode("seldom", { NextAction("emote", 1.0f) })); @@ -19,7 +19,7 @@ void EmoteStrategy::InitTriggers(std::vector& triggers) new TriggerNode("receive emote", { NextAction("emote", 10.0f) })); } - if (sPlayerbotAIConfig->randomBotTalk) + if (sPlayerbotAIConfig.randomBotTalk) { triggers.push_back(new TriggerNode( "often", @@ -27,7 +27,7 @@ void EmoteStrategy::InitTriggers(std::vector& triggers) NextAction("suggest trade", 3.0f) })); } - if (sPlayerbotAIConfig->enableGreet) + if (sPlayerbotAIConfig.enableGreet) triggers.push_back( new TriggerNode("new player nearby", { NextAction("greet", 1.0f) })); diff --git a/src/Ai/Base/Trigger/GenericTriggers.cpp b/src/Ai/Base/Trigger/GenericTriggers.cpp index 988413b2f3..a933bc232d 100644 --- a/src/Ai/Base/Trigger/GenericTriggers.cpp +++ b/src/Ai/Base/Trigger/GenericTriggers.cpp @@ -22,17 +22,18 @@ #include "Timer.h" #include "PlayerbotAI.h" #include "Player.h" +#include "Corpse.h" bool LowManaTrigger::IsActive() { return AI_VALUE2(bool, "has mana", "self target") && - AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig->lowMana; + AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig.lowMana; } bool MediumManaTrigger::IsActive() { return AI_VALUE2(bool, "has mana", "self target") && - AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig->mediumMana; + AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig.mediumMana; } bool NoPetTrigger::IsActive() @@ -72,7 +73,7 @@ bool PetAttackTrigger::IsActive() bool HighManaTrigger::IsActive() { - return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig->highMana; + return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig.highMana; } bool AlmostFullManaTrigger::IsActive() @@ -82,7 +83,7 @@ bool AlmostFullManaTrigger::IsActive() bool EnoughManaTrigger::IsActive() { - return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig->highMana; + return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig.highMana; } bool RageAvailable::IsActive() { return AI_VALUE2(uint8, "rage", "self target") >= amount; } @@ -110,9 +111,9 @@ bool HasAggroTrigger::IsActive() { return AI_VALUE2(bool, "has aggro", "current bool PanicTrigger::IsActive() { - return AI_VALUE2(uint8, "health", "self target") < sPlayerbotAIConfig->criticalHealth && + return AI_VALUE2(uint8, "health", "self target") < sPlayerbotAIConfig.criticalHealth && (!AI_VALUE2(bool, "has mana", "self target") || - AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig->lowMana); + AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig.lowMana); } bool OutNumberedTrigger::IsActive() @@ -248,7 +249,7 @@ bool AoeTrigger::IsActive() bool NoFoodTrigger::IsActive() { - bool isRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot); + bool isRandomBot = sRandomPlayerbotMgr.IsRandomBot(bot); if (isRandomBot && botAI->HasCheat(BotCheatMask::food)) return false; @@ -257,7 +258,7 @@ bool NoFoodTrigger::IsActive() bool NoDrinkTrigger::IsActive() { - bool isRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot); + bool isRandomBot = sRandomPlayerbotMgr.IsRandomBot(bot); if (isRandomBot && botAI->HasCheat(BotCheatMask::food)) return false; @@ -319,11 +320,11 @@ RandomTrigger::RandomTrigger(PlayerbotAI* botAI, std::string const name, int32 p bool RandomTrigger::IsActive() { - if (getMSTime() - lastCheck < sPlayerbotAIConfig->repeatDelay) + if (getMSTime() - lastCheck < sPlayerbotAIConfig.repeatDelay) return false; lastCheck = getMSTime(); - int32 k = (int32)(probability / sPlayerbotAIConfig->randomChangeMultiplier); + int32 k = (int32)(probability / sPlayerbotAIConfig.randomChangeMultiplier); if (k < 1) k = 1; return (rand() % k) == 0; @@ -381,10 +382,10 @@ bool GenericBoostTrigger::IsActive() bool HealerShouldAttackTrigger::IsActive() { // nobody can help me - if (botAI->GetNearGroupMemberCount(sPlayerbotAIConfig->sightDistance) <= 1) + if (botAI->GetNearGroupMemberCount(sPlayerbotAIConfig.sightDistance) <= 1) return true; - if (AI_VALUE2(uint8, "health", "party member to heal") < sPlayerbotAIConfig->almostFullHealth) + if (AI_VALUE2(uint8, "health", "party member to heal") < sPlayerbotAIConfig.almostFullHealth) return false; // special check for resto druid (dont remove tree of life frequently) @@ -401,9 +402,9 @@ bool HealerShouldAttackTrigger::IsActive() if (balance <= 50) manaThreshold = 85; else if (balance <= 100) - manaThreshold = sPlayerbotAIConfig->highMana; + manaThreshold = sPlayerbotAIConfig.highMana; else - manaThreshold = sPlayerbotAIConfig->mediumMana; + manaThreshold = sPlayerbotAIConfig.mediumMana; if (AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") < manaThreshold) return false; @@ -632,7 +633,7 @@ bool ReturnToStayPositionTrigger::IsActive() if (stayPosition.isSet()) { const float distance = bot->GetDistance(stayPosition.x, stayPosition.y, stayPosition.z); - return distance > sPlayerbotAIConfig->followDistance; + return distance > sPlayerbotAIConfig.followDistance; } return false; diff --git a/src/Ai/Base/Trigger/GenericTriggers.h b/src/Ai/Base/Trigger/GenericTriggers.h index 943e80b742..7b884fbf08 100644 --- a/src/Ai/Base/Trigger/GenericTriggers.h +++ b/src/Ai/Base/Trigger/GenericTriggers.h @@ -216,7 +216,7 @@ class DeflectSpellTrigger : public SpellTrigger class AttackerCountTrigger : public Trigger { public: - AttackerCountTrigger(PlayerbotAI* botAI, int32 amount, float distance = sPlayerbotAIConfig->sightDistance) + AttackerCountTrigger(PlayerbotAI* botAI, int32 amount, float distance = sPlayerbotAIConfig.sightDistance) : Trigger(botAI), amount(amount), distance(distance) { } @@ -836,7 +836,7 @@ class StayTimeTrigger : public Trigger class SitTrigger : public StayTimeTrigger { public: - SitTrigger(PlayerbotAI* botAI) : StayTimeTrigger(botAI, sPlayerbotAIConfig->sitDelay, "sit") {} + SitTrigger(PlayerbotAI* botAI) : StayTimeTrigger(botAI, sPlayerbotAIConfig.sitDelay, "sit") {} }; class ReturnToStayPositionTrigger : public Trigger @@ -850,7 +850,7 @@ class ReturnToStayPositionTrigger : public Trigger class ReturnTrigger : public StayTimeTrigger { public: - ReturnTrigger(PlayerbotAI* botAI) : StayTimeTrigger(botAI, sPlayerbotAIConfig->returnDelay, "return") {} + ReturnTrigger(PlayerbotAI* botAI) : StayTimeTrigger(botAI, sPlayerbotAIConfig.returnDelay, "return") {} }; class GiveItemTrigger : public Trigger diff --git a/src/Ai/Base/Trigger/HealthTriggers.cpp b/src/Ai/Base/Trigger/HealthTriggers.cpp index 9f0485b779..a2b36962d5 100644 --- a/src/Ai/Base/Trigger/HealthTriggers.cpp +++ b/src/Ai/Base/Trigger/HealthTriggers.cpp @@ -38,4 +38,4 @@ bool AoeInGroupTrigger::IsActive() threshold = std::min(threshold, 15); return AI_VALUE2(uint8, "aoe heal", type) >= threshold; -} \ No newline at end of file +} diff --git a/src/Ai/Base/Trigger/HealthTriggers.h b/src/Ai/Base/Trigger/HealthTriggers.h index d8149bffdb..0fbd403d72 100644 --- a/src/Ai/Base/Trigger/HealthTriggers.h +++ b/src/Ai/Base/Trigger/HealthTriggers.h @@ -48,7 +48,7 @@ class LowHealthTrigger : public HealthInRangeTrigger { public: LowHealthTrigger(PlayerbotAI* botAI, std::string const name = "low health", - float value = sPlayerbotAIConfig->lowHealth, float minValue = 0) + float value = sPlayerbotAIConfig.lowHealth, float minValue = 0) : HealthInRangeTrigger(botAI, name, value, minValue) { } @@ -60,7 +60,7 @@ class CriticalHealthTrigger : public LowHealthTrigger { public: CriticalHealthTrigger(PlayerbotAI* botAI) - : LowHealthTrigger(botAI, "critical health", sPlayerbotAIConfig->criticalHealth, 0) + : LowHealthTrigger(botAI, "critical health", sPlayerbotAIConfig.criticalHealth, 0) { } }; @@ -69,7 +69,7 @@ class MediumHealthTrigger : public LowHealthTrigger { public: MediumHealthTrigger(PlayerbotAI* botAI) - : LowHealthTrigger(botAI, "medium health", sPlayerbotAIConfig->mediumHealth, 0) + : LowHealthTrigger(botAI, "medium health", sPlayerbotAIConfig.mediumHealth, 0) { } }; @@ -78,8 +78,8 @@ class AlmostFullHealthTrigger : public LowHealthTrigger { public: AlmostFullHealthTrigger(PlayerbotAI* botAI) - : LowHealthTrigger(botAI, "almost full health", sPlayerbotAIConfig->almostFullHealth, - sPlayerbotAIConfig->mediumHealth) + : LowHealthTrigger(botAI, "almost full health", sPlayerbotAIConfig.almostFullHealth, + sPlayerbotAIConfig.mediumHealth) { } }; @@ -88,7 +88,7 @@ class PartyMemberLowHealthTrigger : public HealthInRangeTrigger { public: PartyMemberLowHealthTrigger(PlayerbotAI* botAI, std::string const name = "party member low health", - float value = sPlayerbotAIConfig->lowHealth, + float value = sPlayerbotAIConfig.lowHealth, float minValue = 0) : HealthInRangeTrigger(botAI, name, value, minValue) { @@ -101,7 +101,7 @@ class PartyMemberCriticalHealthTrigger : public PartyMemberLowHealthTrigger { public: PartyMemberCriticalHealthTrigger(PlayerbotAI* botAI) - : PartyMemberLowHealthTrigger(botAI, "party member critical health", sPlayerbotAIConfig->criticalHealth, 0) + : PartyMemberLowHealthTrigger(botAI, "party member critical health", sPlayerbotAIConfig.criticalHealth, 0) { } }; @@ -110,7 +110,7 @@ class PartyMemberMediumHealthTrigger : public PartyMemberLowHealthTrigger { public: PartyMemberMediumHealthTrigger(PlayerbotAI* botAI) - : PartyMemberLowHealthTrigger(botAI, "party member medium health", sPlayerbotAIConfig->mediumHealth, + : PartyMemberLowHealthTrigger(botAI, "party member medium health", sPlayerbotAIConfig.mediumHealth, 0) { } @@ -120,7 +120,7 @@ class PartyMemberAlmostFullHealthTrigger : public PartyMemberLowHealthTrigger { public: PartyMemberAlmostFullHealthTrigger(PlayerbotAI* botAI) - : PartyMemberLowHealthTrigger(botAI, "party member almost full health", sPlayerbotAIConfig->almostFullHealth, + : PartyMemberLowHealthTrigger(botAI, "party member almost full health", sPlayerbotAIConfig.almostFullHealth, 0) { } diff --git a/src/Ai/Base/Trigger/LootTriggers.cpp b/src/Ai/Base/Trigger/LootTriggers.cpp index f422f386ee..0a4b7e4117 100644 --- a/src/Ai/Base/Trigger/LootTriggers.cpp +++ b/src/Ai/Base/Trigger/LootTriggers.cpp @@ -15,11 +15,11 @@ bool LootAvailableTrigger::IsActive() if (botAI->HasStrategy("stay", BOT_STATE_NON_COMBAT)) { distanceCheck = - sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "loot target"), CONTACT_DISTANCE); + ServerFacade::instance().IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "loot target"), CONTACT_DISTANCE); } else { - distanceCheck = sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "loot target"), + distanceCheck = ServerFacade::instance().IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "loot target"), INTERACTION_DISTANCE - 2.0f); } diff --git a/src/Ai/Base/Trigger/PvpTriggers.cpp b/src/Ai/Base/Trigger/PvpTriggers.cpp index c837d8b16c..31fcd0357e 100644 --- a/src/Ai/Base/Trigger/PvpTriggers.cpp +++ b/src/Ai/Base/Trigger/PvpTriggers.cpp @@ -247,7 +247,7 @@ bool EnemyFlagCarrierNear::IsActive() { Unit* carrier = AI_VALUE(Unit*, "enemy flag carrier"); - if (!carrier || !sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, carrier), 100.f)) + if (!carrier || !ServerFacade::instance().IsDistanceLessOrEqualThan(ServerFacade::instance().GetDistance2d(bot, carrier), 100.f)) return false; // Check if there is another enemy player target closer than the FC @@ -255,8 +255,8 @@ bool EnemyFlagCarrierNear::IsActive() if (nearbyEnemy) { - float distToFC = sServerFacade->GetDistance2d(bot, carrier); - float distToEnemy = sServerFacade->GetDistance2d(bot, nearbyEnemy); + float distToFC = ServerFacade::instance().GetDistance2d(bot, carrier); + float distToEnemy = ServerFacade::instance().GetDistance2d(bot, nearbyEnemy); // If the other enemy is significantly closer, don't pursue FC if (distToEnemy + 15.0f < distToFC) // Add small buffer @@ -283,7 +283,7 @@ bool TeamFlagCarrierNear::IsActive() } Unit* carrier = AI_VALUE(Unit*, "team flag carrier"); - return carrier && sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, carrier), 200.f); + return carrier && ServerFacade::instance().IsDistanceLessOrEqualThan(ServerFacade::instance().GetDistance2d(bot, carrier), 200.f); } bool PlayerWantsInBattlegroundTrigger::IsActive() diff --git a/src/Ai/Base/Trigger/RangeTriggers.cpp b/src/Ai/Base/Trigger/RangeTriggers.cpp index af29f984d1..2acc2aec85 100644 --- a/src/Ai/Base/Trigger/RangeTriggers.cpp +++ b/src/Ai/Base/Trigger/RangeTriggers.cpp @@ -34,7 +34,7 @@ bool EnemyTooCloseForSpellTrigger::IsActive() // bool isBoss = false; // bool isRaid = false; // float combatReach = bot->GetCombatReach() + target->GetCombatReach(); - // float targetDistance = sServerFacade->GetDistance2d(bot, target) + combatReach; + // float targetDistance = ServerFacade::instance().GetDistance2d(bot, target) + combatReach; // if (target->IsCreature()) // { // Creature* creature = botAI->GetCreature(target->GetGUID()); @@ -48,10 +48,10 @@ bool EnemyTooCloseForSpellTrigger::IsActive() // isRaid = true; // // if (isBoss || isRaid) - // // return sServerFacade->IsDistanceLessThan(targetDistance, (sPlayerbotAIConfig->tooCloseDistance + + // // return ServerFacade::instance().IsDistanceLessThan(targetDistance, (sPlayerbotAIConfig.tooCloseDistance + // combatReach) / 2); - // return sServerFacade->IsDistanceLessOrEqualThan(targetDistance, (sPlayerbotAIConfig->tooCloseDistance + + // return ServerFacade::instance().IsDistanceLessOrEqualThan(targetDistance, (sPlayerbotAIConfig.tooCloseDistance + // combatReach / 2)); } @@ -80,7 +80,7 @@ bool EnemyTooCloseForAutoShotTrigger::IsActive() // bool isBoss = false; // bool isRaid = false; // float combatReach = bot->GetCombatReach() + target->GetCombatReach(); - // float targetDistance = sServerFacade->GetDistance2d(bot, target) + combatReach; + // float targetDistance = ServerFacade::instance().GetDistance2d(bot, target) + combatReach; // if (target->IsCreature()) // { // Creature* creature = botAI->GetCreature(target->GetGUID()); @@ -93,7 +93,7 @@ bool EnemyTooCloseForAutoShotTrigger::IsActive() // if (bot->GetMap() && bot->GetMap()->IsRaid()) // isRaid = true; - // return sServerFacade->IsDistanceLessOrEqualThan(targetDistance, 5.0f); + // return ServerFacade::instance().IsDistanceLessOrEqualThan(targetDistance, 5.0f); } bool EnemyTooCloseForShootTrigger::IsActive() @@ -115,7 +115,7 @@ bool EnemyTooCloseForShootTrigger::IsActive() // bool isBoss = false; // bool isRaid = false; // float combatReach = bot->GetCombatReach() + target->GetCombatReach(); - // float targetDistance = sServerFacade->GetDistance2d(bot, target) + combatReach; + // float targetDistance = ServerFacade::instance().GetDistance2d(bot, target) + combatReach; // if (target->IsCreature()) // { // Creature* creature = botAI->GetCreature(target->GetGUID()); @@ -129,9 +129,9 @@ bool EnemyTooCloseForShootTrigger::IsActive() // isRaid = true; // // if (isBoss || isRaid) - // // return sServerFacade->IsDistanceLessThan(targetDistance, botAI->GetRange("shoot") + combatReach); + // // return ServerFacade::instance().IsDistanceLessThan(targetDistance, botAI->GetRange("shoot") + combatReach); - // return sServerFacade->IsDistanceLessOrEqualThan(targetDistance, (botAI->GetRange("shoot") + combatReach / + // return ServerFacade::instance().IsDistanceLessOrEqualThan(targetDistance, (botAI->GetRange("shoot") + combatReach / // 2)); } @@ -147,8 +147,8 @@ bool EnemyTooCloseForMeleeTrigger::IsActive() bool EnemyIsCloseTrigger::IsActive() { Unit* target = AI_VALUE(Unit*, "current target"); - return target && sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "current target"), - sPlayerbotAIConfig->tooCloseDistance); + return target && ServerFacade::instance().IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "current target"), + sPlayerbotAIConfig.tooCloseDistance); } bool EnemyWithinMeleeTrigger::IsActive() @@ -165,7 +165,7 @@ bool OutOfRangeTrigger::IsActive() return target && !bot->IsWithinCombatRange( target, - dis); // sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", GetTargetName()), distance); + dis); // ServerFacade::instance().IsDistanceGreaterThan(AI_VALUE2(float, "distance", GetTargetName()), distance); } EnemyOutOfSpellRangeTrigger::EnemyOutOfSpellRangeTrigger(PlayerbotAI* botAI) @@ -180,8 +180,8 @@ EnemyOutOfSpellRangeTrigger::EnemyOutOfSpellRangeTrigger(PlayerbotAI* botAI) // return false; // float combatReach = bot->GetCombatReach() + target->GetCombatReach(); -// return target && (sServerFacade->GetDistance2d(bot, target) > (distance + combatReach + -// sPlayerbotAIConfig->contactDistance) || !bot->IsWithinLOSInMap(target)); +// return target && (ServerFacade::instance().GetDistance2d(bot, target) > (distance + combatReach + +// sPlayerbotAIConfig.contactDistance) || !bot->IsWithinLOSInMap(target)); // } // bool EnemyOutOfMeleeTrigger::IsActive() @@ -190,7 +190,7 @@ EnemyOutOfSpellRangeTrigger::EnemyOutOfSpellRangeTrigger(PlayerbotAI* botAI) // if (!target) // return false; -// float targetDistance = sServerFacade->GetDistance2d(bot, target); +// float targetDistance = ServerFacade::instance().GetDistance2d(bot, target); // return target && (targetDistance > std::max(5.0f, bot->GetCombatReach() + target->GetCombatReach()) || // (!bot->IsWithinLOSInMap(target) && targetDistance > 5.0f)); // } @@ -202,7 +202,7 @@ bool PartyMemberToHealOutOfSpellRangeTrigger::IsActive() return false; float combatReach = bot->GetCombatReach() + target->GetCombatReach(); - return target && (sServerFacade->GetDistance2d(bot, target) > (distance + sPlayerbotAIConfig->contactDistance) || + return target && (ServerFacade::instance().GetDistance2d(bot, target) > (distance + sPlayerbotAIConfig.contactDistance) || !bot->IsWithinLOSInMap(target)); } @@ -213,7 +213,7 @@ PartyMemberToHealOutOfSpellRangeTrigger::PartyMemberToHealOutOfSpellRangeTrigger bool FarFromMasterTrigger::IsActive() { - return sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "group leader"), distance); + return ServerFacade::instance().IsDistanceGreaterThan(AI_VALUE2(float, "distance", "group leader"), distance); } bool TooCloseToCreatureTrigger::TooCloseToCreature(uint32 creatureId, float range, bool alive) diff --git a/src/Ai/Base/Trigger/RangeTriggers.h b/src/Ai/Base/Trigger/RangeTriggers.h index cc320ad027..62e1ae6e03 100644 --- a/src/Ai/Base/Trigger/RangeTriggers.h +++ b/src/Ai/Base/Trigger/RangeTriggers.h @@ -78,7 +78,7 @@ class EnemyOutOfMeleeTrigger : public OutOfRangeTrigger { public: EnemyOutOfMeleeTrigger(PlayerbotAI* botAI) - : OutOfRangeTrigger(botAI, "enemy out of melee range", sPlayerbotAIConfig->meleeDistance) + : OutOfRangeTrigger(botAI, "enemy out of melee range", sPlayerbotAIConfig.meleeDistance) { } diff --git a/src/Ai/Base/Trigger/TravelTriggers.cpp b/src/Ai/Base/Trigger/TravelTriggers.cpp index 88dfbb2b4b..ce036027c1 100644 --- a/src/Ai/Base/Trigger/TravelTriggers.cpp +++ b/src/Ai/Base/Trigger/TravelTriggers.cpp @@ -21,7 +21,7 @@ bool AtDarkPortalAzerothTrigger::IsActive() { if (bot->GetAreaId() == 72) { - if (sServerFacade->GetDistance2d(bot, -11906.9f, -3208.53f) < 20.0f) + if (ServerFacade::instance().GetDistance2d(bot, -11906.9f, -3208.53f) < 20.0f) { return true; } @@ -34,7 +34,7 @@ bool AtDarkPortalOutlandTrigger::IsActive() { if (bot->GetAreaId() == 3539) { - if (sServerFacade->GetDistance2d(bot, -248.1939f, 921.919f) < 10.0f) + if (ServerFacade::instance().GetDistance2d(bot, -248.1939f, 921.919f) < 10.0f) { return true; } diff --git a/src/Ai/Base/TriggerContext.h b/src/Ai/Base/TriggerContext.h index ceb7c001c1..1e8abf9461 100644 --- a/src/Ai/Base/TriggerContext.h +++ b/src/Ai/Base/TriggerContext.h @@ -16,6 +16,7 @@ #include "NewRpgStrategy.h" #include "NewRpgTriggers.h" #include "PvpTriggers.h" +#include "RaidNaxxTriggers.h" #include "RpgTriggers.h" #include "RtiTriggers.h" #include "StuckTriggers.h" diff --git a/src/Ai/Base/Value/AoeHealValues.cpp b/src/Ai/Base/Value/AoeHealValues.cpp index 06f0002056..2c56986678 100644 --- a/src/Ai/Base/Value/AoeHealValues.cpp +++ b/src/Ai/Base/Value/AoeHealValues.cpp @@ -16,13 +16,13 @@ uint8 AoeHealValue::Calculate() float range = 0; if (qualifier == "low") - range = sPlayerbotAIConfig->lowHealth; + range = sPlayerbotAIConfig.lowHealth; else if (qualifier == "medium") - range = sPlayerbotAIConfig->mediumHealth; + range = sPlayerbotAIConfig.mediumHealth; else if (qualifier == "critical") - range = sPlayerbotAIConfig->criticalHealth; + range = sPlayerbotAIConfig.criticalHealth; else if (qualifier == "almost full") - range = sPlayerbotAIConfig->almostFullHealth; + range = sPlayerbotAIConfig.almostFullHealth; uint8 count = 0; Group::MemberSlotList const& groupSlot = group->GetMemberSlots(); @@ -32,7 +32,7 @@ uint8 AoeHealValue::Calculate() if (!player || !player->IsAlive()) continue; - if (player->GetDistance(bot) >= sPlayerbotAIConfig->sightDistance) + if (player->GetDistance(bot) >= sPlayerbotAIConfig.sightDistance) continue; float percent = (static_cast(player->GetHealth()) / player->GetMaxHealth()) * 100; diff --git a/src/Ai/Base/Value/AoeValues.cpp b/src/Ai/Base/Value/AoeValues.cpp index d46dcb816f..a51a2f4d3b 100644 --- a/src/Ai/Base/Value/AoeValues.cpp +++ b/src/Ai/Base/Value/AoeValues.cpp @@ -29,8 +29,8 @@ GuidVector FindMaxDensity(Player* bot) if (!other) continue; - float d = sServerFacade->GetDistance2d(unit, other); - if (sServerFacade->IsDistanceLessOrEqualThan(d, sPlayerbotAIConfig->aoeRadius * 2)) + float d = ServerFacade::instance().GetDistance2d(unit, other); + if (ServerFacade::instance().IsDistanceLessOrEqualThan(d, sPlayerbotAIConfig.aoeRadius * 2)) groups[*i].push_back(*j); } @@ -157,4 +157,4 @@ Aura* AreaDebuffValue::Calculate() } } return nullptr; -} \ No newline at end of file +} diff --git a/src/Ai/Base/Value/Arrow.cpp b/src/Ai/Base/Value/Arrow.cpp index 15fc2e2959..5fd710220c 100644 --- a/src/Ai/Base/Value/Arrow.cpp +++ b/src/Ai/Base/Value/Arrow.cpp @@ -31,15 +31,15 @@ WorldLocation ArrowFormation::GetLocationInternal() tanks.PlaceUnits(&placer); tanks.Move(-cos(orientation) * offset, -sin(orientation) * offset); - offset += tankLines * sPlayerbotAIConfig->followDistance + sPlayerbotAIConfig->tooCloseDistance / 2; + offset += tankLines * sPlayerbotAIConfig.followDistance + sPlayerbotAIConfig.tooCloseDistance / 2; melee.PlaceUnits(&placer); melee.Move(-cos(orientation) * offset, -sin(orientation) * offset); - offset += meleeLines * sPlayerbotAIConfig->followDistance + sPlayerbotAIConfig->tooCloseDistance / 2; + offset += meleeLines * sPlayerbotAIConfig.followDistance + sPlayerbotAIConfig.tooCloseDistance / 2; ranged.PlaceUnits(&placer); ranged.Move(-cos(orientation) * offset, -sin(orientation) * offset); - offset += rangedLines * sPlayerbotAIConfig->followDistance; + offset += rangedLines * sPlayerbotAIConfig.followDistance; healers.PlaceUnits(&placer); healers.Move(-cos(orientation) * offset, -sin(orientation) * offset); @@ -143,16 +143,16 @@ UnitPosition MultiLineUnitPlacer::Place(FormationUnit* unit, uint32 index, uint3 uint32 lineNo = index / 6; uint32 indexInLine = index % 6; uint32 lineSize = std::max(count - lineNo * 6, uint32(6)); - float x = cos(orientation) * sPlayerbotAIConfig->followDistance * lineNo; - float y = sin(orientation) * sPlayerbotAIConfig->followDistance * lineNo; + float x = cos(orientation) * sPlayerbotAIConfig.followDistance * lineNo; + float y = sin(orientation) * sPlayerbotAIConfig.followDistance * lineNo; return placer.Place(unit, indexInLine, lineSize); } UnitPosition SingleLineUnitPlacer::Place(FormationUnit* unit, uint32 index, uint32 count) { float angle = orientation - M_PI / 2.0f; - float x = cos(angle) * sPlayerbotAIConfig->followDistance * ((float)index - (float)count / 2); - float y = sin(angle) * sPlayerbotAIConfig->followDistance * ((float)index - (float)count / 2); + float x = cos(angle) * sPlayerbotAIConfig.followDistance * ((float)index - (float)count / 2); + float y = sin(angle) * sPlayerbotAIConfig.followDistance * ((float)index - (float)count / 2); return UnitPosition(x, y); } diff --git a/src/Ai/Base/Value/AttackerCountValues.cpp b/src/Ai/Base/Value/AttackerCountValues.cpp index 637fd72864..88c3cd1fb6 100644 --- a/src/Ai/Base/Value/AttackerCountValues.cpp +++ b/src/Ai/Base/Value/AttackerCountValues.cpp @@ -34,7 +34,7 @@ bool HasAggroValue::Calculate() uint8 AttackerCountValue::Calculate() { uint32 count = 0; - float range = sPlayerbotAIConfig->sightDistance; + float range = sPlayerbotAIConfig.sightDistance; GuidVector attackers = context->GetValue("attackers")->Get(); for (ObjectGuid const guid : attackers) diff --git a/src/Ai/Base/Value/AttackersValue.cpp b/src/Ai/Base/Value/AttackersValue.cpp index 3c9685895a..dbde7ab8df 100644 --- a/src/Ai/Base/Value/AttackersValue.cpp +++ b/src/Ai/Base/Value/AttackersValue.cpp @@ -71,7 +71,7 @@ void AttackersValue::AddAttackersOf(Group* group, std::unordered_set& tar { Player* member = ObjectAccessor::FindPlayer(itr->guid); if (!member || !member->IsAlive() || member == bot || member->GetMapId() != bot->GetMapId() || - sServerFacade->GetDistance2d(bot, member) > sPlayerbotAIConfig->sightDistance) + ServerFacade::instance().GetDistance2d(bot, member) > sPlayerbotAIConfig.sightDistance) continue; AddAttackersOf(member, targets); @@ -103,7 +103,7 @@ void AttackersValue::AddAttackersOf(Player* player, std::unordered_set& t Unit* attacker = threatMgr->GetOwner(); if (player->IsValidAttackTarget(attacker) && - player->GetDistance2d(attacker) < sPlayerbotAIConfig->sightDistance) + player->GetDistance2d(attacker) < sPlayerbotAIConfig.sightDistance) targets.insert(attacker); ref = ref->next(); @@ -176,8 +176,8 @@ bool AttackersValue::IsPossibleTarget(Unit* attacker, Player* bot, float /*range // PvP prohibition checks (skip for duels) if ((attacker->GetGUID().IsPlayer() || attacker->GetGUID().IsPet()) && (!bot->duel || bot->duel->Opponent != attacker) && - (sPlayerbotAIConfig->IsPvpProhibited(attacker->GetZoneId(), attacker->GetAreaId()) || - sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()))) + (sPlayerbotAIConfig.IsPvpProhibited(attacker->GetZoneId(), attacker->GetAreaId()) || + sPlayerbotAIConfig.IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()))) { // This will stop aggresive pets from starting an attack. // This will stop currently attacking pets from continuing their attack. @@ -258,6 +258,9 @@ bool PossibleAddsValue::Calculate() if (Unit* add = botAI->GetUnit(guid)) { + if (!add->IsInWorld() || add->IsDuringRemoveFromWorld()) + continue; + if (!add->GetTarget() && !add->GetThreatMgr().getCurrentVictim() && add->IsHostileTo(bot)) { for (ObjectGuid const attackerGUID : attackers) @@ -266,11 +269,11 @@ bool PossibleAddsValue::Calculate() if (!attacker) continue; - float dist = sServerFacade->GetDistance2d(attacker, add); - if (sServerFacade->IsDistanceLessOrEqualThan(dist, sPlayerbotAIConfig->aoeRadius * 1.5f)) + float dist = ServerFacade::instance().GetDistance2d(attacker, add); + if (ServerFacade::instance().IsDistanceLessOrEqualThan(dist, sPlayerbotAIConfig.aoeRadius * 1.5f)) continue; - if (sServerFacade->IsDistanceLessOrEqualThan(dist, sPlayerbotAIConfig->aggroDistance)) + if (ServerFacade::instance().IsDistanceLessOrEqualThan(dist, sPlayerbotAIConfig.aggroDistance)) return true; } } diff --git a/src/Ai/Base/Value/AttackersValue.h b/src/Ai/Base/Value/AttackersValue.h index 906db92a88..7e9397c86c 100644 --- a/src/Ai/Base/Value/AttackersValue.h +++ b/src/Ai/Base/Value/AttackersValue.h @@ -20,7 +20,7 @@ class AttackersValue : public ObjectGuidListCalculatedValue AttackersValue(PlayerbotAI* botAI) : ObjectGuidListCalculatedValue(botAI, "attackers", 1 * 1000) {} GuidVector Calculate(); - static bool IsPossibleTarget(Unit* attacker, Player* bot, float range = sPlayerbotAIConfig->sightDistance); + static bool IsPossibleTarget(Unit* attacker, Player* bot, float range = sPlayerbotAIConfig.sightDistance); static bool IsValidTarget(Unit* attacker, Player* bot); private: diff --git a/src/Ai/Base/Value/AvailableLootValue.cpp b/src/Ai/Base/Value/AvailableLootValue.cpp index 7f945d7e1e..75b4b599a4 100644 --- a/src/Ai/Base/Value/AvailableLootValue.cpp +++ b/src/Ai/Base/Value/AvailableLootValue.cpp @@ -26,5 +26,5 @@ bool CanLootValue::Calculate() { LootObject loot = AI_VALUE(LootObject, "loot target"); return !loot.IsEmpty() && loot.GetWorldObject(bot) && loot.IsLootPossible(bot) && - sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "loot target"), INTERACTION_DISTANCE - 2); + ServerFacade::instance().IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "loot target"), INTERACTION_DISTANCE - 2); } diff --git a/src/Ai/Base/Value/CcTargetValue.cpp b/src/Ai/Base/Value/CcTargetValue.cpp index c47151ddfd..1c305aec3c 100644 --- a/src/Ai/Base/Value/CcTargetValue.cpp +++ b/src/Ai/Base/Value/CcTargetValue.cpp @@ -34,7 +34,7 @@ class FindTargetForCcStrategy : public FindTargetStrategy return; uint8 health = static_cast(creature->GetHealthPct()); - if (health < sPlayerbotAIConfig->mediumHealth) + if (health < sPlayerbotAIConfig.mediumHealth) return; float minDistance = botAI->GetRange("spell"); @@ -45,9 +45,9 @@ class FindTargetForCcStrategy : public FindTargetStrategy if (*botAI->GetAiObjectContext()->GetValue("aoe count") > 2) { WorldLocation aoe = *botAI->GetAiObjectContext()->GetValue("aoe position"); - if (sServerFacade->IsDistanceLessOrEqualThan( - sServerFacade->GetDistance2d(creature, aoe.GetPositionX(), aoe.GetPositionY()), - sPlayerbotAIConfig->aoeRadius)) + if (ServerFacade::instance().IsDistanceLessOrEqualThan( + ServerFacade::instance().GetDistance2d(creature, aoe.GetPositionX(), aoe.GetPositionY()), + sPlayerbotAIConfig.aoeRadius)) return; } @@ -70,7 +70,7 @@ class FindTargetForCcStrategy : public FindTargetStrategy if (!botAI->IsTank(member)) continue; - float distance = sServerFacade->GetDistance2d(member, creature); + float distance = ServerFacade::instance().GetDistance2d(member, creature); if (distance < minDistance) minDistance = distance; } diff --git a/src/Ai/Base/Value/CollisionValue.cpp b/src/Ai/Base/Value/CollisionValue.cpp index 7657742590..172a909b17 100644 --- a/src/Ai/Base/Value/CollisionValue.cpp +++ b/src/Ai/Base/Value/CollisionValue.cpp @@ -18,7 +18,7 @@ bool CollisionValue::Calculate() return false; std::list targets; - float range = sPlayerbotAIConfig->contactDistance; + float range = sPlayerbotAIConfig.contactDistance; Acore::AnyUnitInObjectRangeCheck u_check(bot, range); Acore::UnitListSearcher searcher(bot, targets, u_check); Cell::VisitObjects(bot, searcher, range); @@ -28,8 +28,8 @@ bool CollisionValue::Calculate() if (bot == target) continue; - float dist = sServerFacade->GetDistance2d(bot, target->GetPositionX(), target->GetPositionY()); - if (sServerFacade->IsDistanceLessThan(dist, target->GetCombatReach())) + float dist = ServerFacade::instance().GetDistance2d(bot, target->GetPositionX(), target->GetPositionY()); + if (ServerFacade::instance().IsDistanceLessThan(dist, target->GetCombatReach())) return true; } diff --git a/src/Ai/Base/Value/DistanceValue.cpp b/src/Ai/Base/Value/DistanceValue.cpp index 2c1e818b54..a5c6fe857a 100644 --- a/src/Ai/Base/Value/DistanceValue.cpp +++ b/src/Ai/Base/Value/DistanceValue.cpp @@ -24,7 +24,7 @@ float DistanceValue::Calculate() if (!obj || !obj->IsInWorld()) return 0.0f; - return sServerFacade->GetDistance2d(botAI->GetBot(), obj); + return ServerFacade::instance().GetDistance2d(botAI->GetBot(), obj); } if (qualifier.find("position_") == 0) @@ -37,7 +37,7 @@ float DistanceValue::Calculate() if (botAI->GetBot()->GetMapId() != pos.mapId) return 0.0f; - return sServerFacade->GetDistance2d(botAI->GetBot(), pos.x, pos.y); + return ServerFacade::instance().GetDistance2d(botAI->GetBot(), pos.x, pos.y); } Unit* target = nullptr; @@ -76,7 +76,7 @@ float DistanceValue::Calculate() { Formation* formation = AI_VALUE(Formation*, "formation"); WorldLocation loc = formation->GetLocation(); - return sServerFacade->GetDistance2d(botAI->GetBot(), loc.GetPositionX(), loc.GetPositionY()); + return ServerFacade::instance().GetDistance2d(botAI->GetBot(), loc.GetPositionX(), loc.GetPositionY()); } } @@ -86,7 +86,7 @@ float DistanceValue::Calculate() if (target == botAI->GetBot()) return 0.0f; - return sServerFacade->GetDistance2d(botAI->GetBot(), target); + return ServerFacade::instance().GetDistance2d(botAI->GetBot(), target); } bool InsideTargetValue::Calculate() @@ -95,6 +95,6 @@ bool InsideTargetValue::Calculate() if (!target || !target->IsInWorld() || target == botAI->GetBot()) return false; - float dist = sServerFacade->GetDistance2d(botAI->GetBot(), target->GetPositionX(), target->GetPositionY()); - return sServerFacade->IsDistanceLessThan(dist, target->GetCombatReach()); + float dist = ServerFacade::instance().GetDistance2d(botAI->GetBot(), target->GetPositionX(), target->GetPositionY()); + return ServerFacade::instance().IsDistanceLessThan(dist, target->GetCombatReach()); } diff --git a/src/Ai/Base/Value/DpsTargetValue.cpp b/src/Ai/Base/Value/DpsTargetValue.cpp index 55b47d7c01..1a813c9940 100644 --- a/src/Ai/Base/Value/DpsTargetValue.cpp +++ b/src/Ai/Base/Value/DpsTargetValue.cpp @@ -116,7 +116,7 @@ class CasterFindTargetSmartStrategy : public FindTargetStrategy float time = unit->GetHealth() / dps_; float dis = unit->GetDistance(botAI->GetBot()); float attackRange = - botAI->IsRanged(botAI->GetBot()) ? sPlayerbotAIConfig->spellDistance : sPlayerbotAIConfig->meleeDistance; + botAI->IsRanged(botAI->GetBot()) ? sPlayerbotAIConfig.spellDistance : sPlayerbotAIConfig.meleeDistance; attackRange += 5.0f; int level = dis < attackRange ? 10 : 0; if (time >= 5 && time <= 30) @@ -198,7 +198,7 @@ class GeneralFindTargetSmartStrategy : public FindTargetStrategy float time = unit->GetHealth() / dps_; float dis = unit->GetDistance(botAI->GetBot()); float attackRange = - botAI->IsRanged(botAI->GetBot()) ? sPlayerbotAIConfig->spellDistance : sPlayerbotAIConfig->meleeDistance; + botAI->IsRanged(botAI->GetBot()) ? sPlayerbotAIConfig.spellDistance : sPlayerbotAIConfig.meleeDistance; attackRange += 5.0f; int level = dis < attackRange ? 10 : 0; return level; @@ -279,7 +279,7 @@ class ComboFindTargetSmartStrategy : public FindTargetStrategy float time = unit->GetHealth() / dps_; float dis = unit->GetDistance(botAI->GetBot()); float attackRange = - botAI->IsRanged(botAI->GetBot()) ? sPlayerbotAIConfig->spellDistance : sPlayerbotAIConfig->meleeDistance; + botAI->IsRanged(botAI->GetBot()) ? sPlayerbotAIConfig.spellDistance : sPlayerbotAIConfig.meleeDistance; attackRange += 5.0f; int level = dis < attackRange ? 10 : 0; return level; diff --git a/src/Ai/Base/Value/EnemyHealerTargetValue.cpp b/src/Ai/Base/Value/EnemyHealerTargetValue.cpp index 6040c4fcb5..85559f7827 100644 --- a/src/Ai/Base/Value/EnemyHealerTargetValue.cpp +++ b/src/Ai/Base/Value/EnemyHealerTargetValue.cpp @@ -20,7 +20,7 @@ Unit* EnemyHealerTargetValue::Calculate() if (!unit || unit == target) continue; - if (sServerFacade->GetDistance2d(bot, unit) > botAI->GetRange("spell")) + if (ServerFacade::instance().GetDistance2d(bot, unit) > botAI->GetRange("spell")) continue; if (!botAI->IsInterruptableSpellCasting(unit, spell)) diff --git a/src/Ai/Base/Value/EnemyPlayerValue.cpp b/src/Ai/Base/Value/EnemyPlayerValue.cpp index 2325c9c09b..7de0cd670a 100644 --- a/src/Ai/Base/Value/EnemyPlayerValue.cpp +++ b/src/Ai/Base/Value/EnemyPlayerValue.cpp @@ -14,7 +14,7 @@ bool NearestEnemyPlayersValue::AcceptUnit(Unit* unit) bool inCannon = botAI->IsInVehicle(false, true); Player* enemy = dynamic_cast(unit); if (enemy && botAI->IsOpposing(enemy) && enemy->IsPvP() && - !sPlayerbotAIConfig->IsPvpProhibited(enemy->GetZoneId(), enemy->GetAreaId()) && + !sPlayerbotAIConfig.IsPvpProhibited(enemy->GetZoneId(), enemy->GetAreaId()) && !enemy->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NON_ATTACKABLE_2) && ((inCannon || !enemy->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))) && /*!enemy->HasStealthAura() && !enemy->HasInvisibilityAura()*/ enemy->CanSeeOrDetect(bot) && @@ -131,7 +131,7 @@ Unit* EnemyPlayerValue::Calculate() if (pMember == bot) continue; - if (sServerFacade->GetDistance2d(bot, pMember) > 30.0f) + if (ServerFacade::instance().GetDistance2d(bot, pMember) > 30.0f) continue; if (Unit* pAttacker = pMember->getAttackerForHelper()) diff --git a/src/Ai/Base/Value/EnemyPlayerValue.h b/src/Ai/Base/Value/EnemyPlayerValue.h index f94f20265f..2ff56f4eb2 100644 --- a/src/Ai/Base/Value/EnemyPlayerValue.h +++ b/src/Ai/Base/Value/EnemyPlayerValue.h @@ -16,7 +16,7 @@ class Unit; class NearestEnemyPlayersValue : public PossibleTargetsValue { public: - NearestEnemyPlayersValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig->grindDistance) + NearestEnemyPlayersValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig.grindDistance) : PossibleTargetsValue(botAI, "nearest enemy players", range) { } diff --git a/src/Ai/Base/Value/EstimatedLifetimeValue.cpp b/src/Ai/Base/Value/EstimatedLifetimeValue.cpp index dd79207130..8b7e5163c6 100644 --- a/src/Ai/Base/Value/EstimatedLifetimeValue.cpp +++ b/src/Ai/Base/Value/EstimatedLifetimeValue.cpp @@ -46,7 +46,7 @@ float EstimatedGroupDpsValue::Calculate() if (member->GetMapId() != bot->GetMapId()) continue; - if (member->GetExactDist(bot) > sPlayerbotAIConfig->sightDistance) + if (member->GetExactDist(bot) > sPlayerbotAIConfig.sightDistance) continue; groupPlayer.push_back(member); @@ -146,4 +146,4 @@ float EstimatedGroupDpsValue::GetBasicGs(uint32 level) basic_gs = PlayerbotFactory::CalcMixedGearScore(155 + (level - 70) * 4, ITEM_QUALITY_RARE); } return basic_gs; -} \ No newline at end of file +} diff --git a/src/Ai/Base/Value/Formations.cpp b/src/Ai/Base/Value/Formations.cpp index 69869889d7..1394b9fbe0 100644 --- a/src/Ai/Base/Value/Formations.cpp +++ b/src/Ai/Base/Value/Formations.cpp @@ -64,8 +64,8 @@ WorldLocation MoveAheadFormation::GetLocation() // if (master->isMoving()) // { // float ori = master->GetOrientation(); - // float x1 = x + sPlayerbotAIConfig->tooCloseDistance * cos(ori); - // float y1 = y + sPlayerbotAIConfig->tooCloseDistance * sin(ori); + // float x1 = x + sPlayerbotAIConfig.tooCloseDistance * cos(ori); + // float y1 = y + sPlayerbotAIConfig.tooCloseDistance * sin(ori); // float ground = map->GetHeight(x1, y1, z); // if (ground > INVALID_HEIGHT) // { @@ -111,7 +111,7 @@ class NearFormation : public MoveAheadFormation if (!ValidateTargetContext(master, bot, map)) return Formation::NullLocation; - float range = sPlayerbotAIConfig->followDistance; + float range = sPlayerbotAIConfig.followDistance; float angle = GetFollowAngle(); float x = master->GetPositionX() + cos(angle) * range; float y = master->GetPositionY() + sin(angle) * range; @@ -127,7 +127,7 @@ class NearFormation : public MoveAheadFormation return WorldLocation(master->GetMapId(), x, y, z); } - float GetMaxDistance() override { return sPlayerbotAIConfig->followDistance; } + float GetMaxDistance() override { return sPlayerbotAIConfig.followDistance; } }; class ChaosFormation : public MoveAheadFormation @@ -142,7 +142,7 @@ class ChaosFormation : public MoveAheadFormation if (!ValidateTargetContext(master, bot, map)) return Formation::NullLocation; - float range = sPlayerbotAIConfig->followDistance; + float range = sPlayerbotAIConfig.followDistance; float angle = GetFollowAngle(); time_t now = time(nullptr); @@ -150,8 +150,8 @@ class ChaosFormation : public MoveAheadFormation { lastChangeTime = now; - dx = (urand(0, 10) / 10.0f - 0.5f) * sPlayerbotAIConfig->tooCloseDistance; - dy = (urand(0, 10) / 10.0f - 0.5f) * sPlayerbotAIConfig->tooCloseDistance; + dx = (urand(0, 10) / 10.0f - 0.5f) * sPlayerbotAIConfig.tooCloseDistance; + dy = (urand(0, 10) / 10.0f - 0.5f) * sPlayerbotAIConfig.tooCloseDistance; dr = std::sqrt(dx * dx + dy * dy); } @@ -173,7 +173,7 @@ class ChaosFormation : public MoveAheadFormation return WorldLocation(master->GetMapId(), x, y, z); } - float GetMaxDistance() override { return sPlayerbotAIConfig->followDistance + dr; } + float GetMaxDistance() override { return sPlayerbotAIConfig.followDistance + dr; } private: time_t lastChangeTime; @@ -287,7 +287,7 @@ class ShieldFormation : public MoveFormation if (!group) return Formation::NullLocation; - float range = sPlayerbotAIConfig->followDistance; + float range = sPlayerbotAIConfig.followDistance; Player* master = GetMaster(); if (!master) @@ -326,14 +326,14 @@ class ShieldFormation : public MoveFormation if (botAI->IsTank(bot) && !botAI->IsTank(master)) { - float diff = (tanks.size() % 2 == 0) ? -sPlayerbotAIConfig->tooCloseDistance / 2.0f : 0.0f; + float diff = (tanks.size() % 2 == 0) ? -sPlayerbotAIConfig.tooCloseDistance / 2.0f : 0.0f; return MoveLine(tanks, diff, x + cos(orientation) * range, y + sin(orientation) * range, z, orientation, range); } if (!botAI->IsTank(bot) && botAI->IsTank(master)) { - float diff = (dps.size() % 2 == 0) ? -sPlayerbotAIConfig->tooCloseDistance / 2.0f : 0.0f; + float diff = (dps.size() % 2 == 0) ? -sPlayerbotAIConfig.tooCloseDistance / 2.0f : 0.0f; return MoveLine(dps, diff, x - cos(orientation) * range, y - sin(orientation) * range, z, orientation, range); } @@ -354,10 +354,10 @@ class FarFormation : public FollowFormation if (!ValidateTargetContext(master, bot, map)) return Formation::NullLocation; - float range = sPlayerbotAIConfig->farDistance; - float followRange = sPlayerbotAIConfig->followDistance; + float range = sPlayerbotAIConfig.farDistance; + float followRange = sPlayerbotAIConfig.followDistance; - if (sServerFacade->GetDistance2d(bot, master) <= range) + if (ServerFacade::instance().GetDistance2d(bot, master) <= range) return Formation::NullLocation; float angleToBot = master->GetAngle(bot); @@ -378,7 +378,7 @@ class FarFormation : public FollowFormation float tx = master->GetPositionX() + cos(a) * range + cos(followAngle) * followRange; float ty = master->GetPositionY() + sin(a) * range + sin(followAngle) * followRange; - float dist = sServerFacade->GetDistance2d(bot, tx, ty); + float dist = ServerFacade::instance().GetDistance2d(bot, tx, ty); float tg = master->GetMapHeight(tx, ty, z + 30.0f); if (tg > INVALID_HEIGHT && (!minDist || dist < minDist)) diff --git a/src/Ai/Base/Value/Formations.h b/src/Ai/Base/Value/Formations.h index c44e1d0f42..3e5decf7f1 100644 --- a/src/Ai/Base/Value/Formations.h +++ b/src/Ai/Base/Value/Formations.h @@ -21,7 +21,7 @@ class Formation : public AiNamedObject virtual ~Formation() = default; virtual std::string const GetTargetName() { return ""; } virtual WorldLocation GetLocation() { return NullLocation; } - virtual float GetMaxDistance() { return sPlayerbotAIConfig->followDistance; } + virtual float GetMaxDistance() { return sPlayerbotAIConfig.followDistance; } static WorldLocation NullLocation; static bool IsNullLocation(WorldLocation const& loc); diff --git a/src/Ai/Base/Value/GrindTargetValue.cpp b/src/Ai/Base/Value/GrindTargetValue.cpp index d1d7f912ca..ce021a2d9a 100644 --- a/src/Ai/Base/Value/GrindTargetValue.cpp +++ b/src/Ai/Base/Value/GrindTargetValue.cpp @@ -59,26 +59,22 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount) for (ObjectGuid const guid : targets) { Unit* unit = botAI->GetUnit(guid); - if (!unit) continue; + if (!unit->IsInWorld() || unit->IsDuringRemoveFromWorld()) + continue; + auto& rep = bot->ToPlayer()->GetReputationMgr(); if (unit->ToCreature() && !unit->ToCreature()->GetCreatureTemplate()->lootid && bot->GetReactionTo(unit) >= REP_NEUTRAL) - { continue; - } if (!bot->IsHostileTo(unit) && unit->GetNpcFlags() != UNIT_NPC_FLAG_NONE) - { continue; - } if (!bot->isHonorOrXPTarget(unit)) - { continue; - } if (abs(bot->GetPositionZ() - unit->GetPositionZ()) > INTERACTION_DISTANCE) continue; @@ -86,12 +82,12 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount) if (!bot->InBattleground() && GetTargetingPlayerCount(unit) > assistCount) continue; - // if (!bot->InBattleground() && master && master->GetDistance(unit) >= sPlayerbotAIConfig->grindDistance && - // !sRandomPlayerbotMgr->IsRandomBot(bot)) continue; + // if (!bot->InBattleground() && master && master->GetDistance(unit) >= sPlayerbotAIConfig.grindDistance && + // !sRandomPlayerbotMgr.IsRandomBot(bot)) continue; // Bots in bot-groups no have a more limited range to look for grind target if (!bot->InBattleground() && master && botAI->HasStrategy("follow", BotState::BOT_STATE_NON_COMBAT) && - sServerFacade->GetDistance2d(master, unit) > sPlayerbotAIConfig->lootDistance) + ServerFacade::instance().GetDistance2d(master, unit) > sPlayerbotAIConfig.lootDistance) { if (botAI->HasStrategy("debug grind", BotState::BOT_STATE_NON_COMBAT)) botAI->TellMaster(chat->FormatWorldobject(unit) + " ignored (far from master)."); diff --git a/src/Ai/Base/Value/GroupValues.cpp b/src/Ai/Base/Value/GroupValues.cpp index 01049a7969..460b9f334d 100644 --- a/src/Ai/Base/Value/GroupValues.cpp +++ b/src/Ai/Base/Value/GroupValues.cpp @@ -47,7 +47,7 @@ bool IsNearLeaderValue::Calculate() if (groupLeader == bot) return true; - return sServerFacade->GetDistance2d(bot, botAI->GetGroupLeader()) < sPlayerbotAIConfig->sightDistance; + return ServerFacade::instance().GetDistance2d(bot, botAI->GetGroupLeader()) < sPlayerbotAIConfig.sightDistance; } bool BoolANDValue::Calculate() @@ -155,10 +155,10 @@ bool GroupReadyValue::Calculate() // We only wait for members that are in range otherwise we might be waiting for bots stuck in dead loops // forever. if (botAI->GetGroupLeader() && - sServerFacade->GetDistance2d(member, botAI->GetGroupLeader()) > sPlayerbotAIConfig->sightDistance) + ServerFacade::instance().GetDistance2d(member, botAI->GetGroupLeader()) > sPlayerbotAIConfig.sightDistance) continue; - if (member->GetHealthPct() < sPlayerbotAIConfig->almostFullHealth) + if (member->GetHealthPct() < sPlayerbotAIConfig.almostFullHealth) return false; if (!member->GetPower(POWER_MANA)) @@ -166,7 +166,7 @@ bool GroupReadyValue::Calculate() float mana = (static_cast(member->GetPower(POWER_MANA)) / member->GetMaxPower(POWER_MANA)) * 100; - if (mana < sPlayerbotAIConfig->mediumMana) + if (mana < sPlayerbotAIConfig.mediumMana) return false; } diff --git a/src/Ai/Base/Value/HasAvailableLootValue.cpp b/src/Ai/Base/Value/HasAvailableLootValue.cpp index d687e1fc41..532e06afcd 100644 --- a/src/Ai/Base/Value/HasAvailableLootValue.cpp +++ b/src/Ai/Base/Value/HasAvailableLootValue.cpp @@ -11,5 +11,5 @@ bool HasAvailableLootValue::Calculate() { return !AI_VALUE(bool, "can loot") && - AI_VALUE(LootObjectStack*, "available loot")->CanLoot(sPlayerbotAIConfig->lootDistance); + AI_VALUE(LootObjectStack*, "available loot")->CanLoot(sPlayerbotAIConfig.lootDistance); } diff --git a/src/Ai/Base/Value/ItemUsageValue.cpp b/src/Ai/Base/Value/ItemUsageValue.cpp index 25866c8059..6f48fa9739 100644 --- a/src/Ai/Base/Value/ItemUsageValue.cpp +++ b/src/Ai/Base/Value/ItemUsageValue.cpp @@ -99,7 +99,7 @@ ItemUsage ItemUsageValue::Calculate() } } - if (bot->GetGuildId() && sGuildTaskMgr->IsGuildTaskItem(itemId, bot->GetGuildId())) + if (bot->GetGuildId() && GuildTaskMgr::instance().IsGuildTaskItem(itemId, bot->GetGuildId())) return ITEM_USAGE_GUILD_TASK; ItemUsage equip = QueryItemUsageForEquip(proto, randomPropertyId); @@ -129,7 +129,7 @@ ItemUsage ItemUsageValue::Calculate() Player* master = botAI->GetMaster(); bool isSelfBot = (master == bot); bool botNeedsItemForQuest = IsItemUsefulForQuest(bot, proto); - bool masterNeedsItemForQuest = master && sPlayerbotAIConfig->syncQuestWithPlayer && IsItemUsefulForQuest(master, proto); + bool masterNeedsItemForQuest = master && sPlayerbotAIConfig.syncQuestWithPlayer && IsItemUsefulForQuest(master, proto); // Identify the source of loot LootObject lootObject = AI_VALUE(LootObject, "loot target"); @@ -304,7 +304,7 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto, } bool shouldEquip = false; - // uint32 statWeight = sRandomItemMgr->GetLiveStatWeight(bot, itemProto->ItemId); + // uint32 statWeight = sRandomItemMgr.GetLiveStatWeight(bot, itemProto->ItemId); StatsWeightCalculator calculator(bot); calculator.SetItemSetBonus(false); calculator.SetOverflowPenalty(false); @@ -314,10 +314,10 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto, if (itemScore) shouldEquip = true; - if (itemProto->Class == ITEM_CLASS_WEAPON && !sRandomItemMgr->CanEquipWeapon(bot->getClass(), itemProto)) + if (itemProto->Class == ITEM_CLASS_WEAPON && !sRandomItemMgr.CanEquipWeapon(bot->getClass(), itemProto)) shouldEquip = false; if (itemProto->Class == ITEM_CLASS_ARMOR && - !sRandomItemMgr->CanEquipArmor(bot->getClass(), bot->GetLevel(), itemProto)) + !sRandomItemMgr.CanEquipArmor(bot->getClass(), bot->GetLevel(), itemProto)) shouldEquip = false; uint8 possibleSlots = 1; @@ -396,10 +396,10 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto, float oldScore = calculator.CalculateItem(oldItemProto->ItemId, oldItem->GetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID)); if (oldItem) { - // uint32 oldStatWeight = sRandomItemMgr->GetLiveStatWeight(bot, oldItemProto->ItemId); + // uint32 oldStatWeight = sRandomItemMgr.GetLiveStatWeight(bot, oldItemProto->ItemId); if (itemScore || oldScore) { - shouldEquipInSlot = itemScore > oldScore * sPlayerbotAIConfig->equipUpgradeThreshold; + shouldEquipInSlot = itemScore > oldScore * sPlayerbotAIConfig.equipUpgradeThreshold; } } @@ -417,15 +417,15 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto, } bool existingShouldEquip = true; - if (oldItemProto->Class == ITEM_CLASS_WEAPON && !sRandomItemMgr->CanEquipWeapon(bot->getClass(), oldItemProto)) + if (oldItemProto->Class == ITEM_CLASS_WEAPON && !sRandomItemMgr.CanEquipWeapon(bot->getClass(), oldItemProto)) existingShouldEquip = false; if (oldItemProto->Class == ITEM_CLASS_ARMOR && - !sRandomItemMgr->CanEquipArmor(bot->getClass(), bot->GetLevel(), oldItemProto)) + !sRandomItemMgr.CanEquipArmor(bot->getClass(), bot->GetLevel(), oldItemProto)) existingShouldEquip = false; - // uint32 oldItemPower = sRandomItemMgr->GetLiveStatWeight(bot, oldItemProto->ItemId); - // uint32 newItemPower = sRandomItemMgr->GetLiveStatWeight(bot, itemProto->ItemId); + // uint32 oldItemPower = sRandomItemMgr.GetLiveStatWeight(bot, oldItemProto->ItemId); + // uint32 newItemPower = sRandomItemMgr.GetLiveStatWeight(bot, itemProto->ItemId); // Compare items based on item level, quality or itemId. bool isBetter = false; diff --git a/src/Ai/Base/Value/NearestAdsValue.h b/src/Ai/Base/Value/NearestAdsValue.h index 312d5596eb..b9e3fbe316 100644 --- a/src/Ai/Base/Value/NearestAdsValue.h +++ b/src/Ai/Base/Value/NearestAdsValue.h @@ -14,7 +14,7 @@ class PlayerbotAI; class NearestAddsValue : public PossibleTargetsValue { public: - NearestAddsValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig->tooCloseDistance) + NearestAddsValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig.tooCloseDistance) : PossibleTargetsValue(botAI, "nearest adds", range, true) { } diff --git a/src/Ai/Base/Value/NearestCorpsesValue.h b/src/Ai/Base/Value/NearestCorpsesValue.h index 4c0716e299..f6a067c3fe 100644 --- a/src/Ai/Base/Value/NearestCorpsesValue.h +++ b/src/Ai/Base/Value/NearestCorpsesValue.h @@ -14,7 +14,7 @@ class PlayerbotAI; class NearestCorpsesValue : public NearestUnitsValue { public: - NearestCorpsesValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig->sightDistance) + NearestCorpsesValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig.sightDistance) : NearestUnitsValue(botAI, "nearest corpses", range, true) { } diff --git a/src/Ai/Base/Value/NearestFriendlyPlayersValue.h b/src/Ai/Base/Value/NearestFriendlyPlayersValue.h index 9876316929..2588409044 100644 --- a/src/Ai/Base/Value/NearestFriendlyPlayersValue.h +++ b/src/Ai/Base/Value/NearestFriendlyPlayersValue.h @@ -14,7 +14,7 @@ class PlayerbotAI; class NearestFriendlyPlayersValue : public NearestUnitsValue { public: - NearestFriendlyPlayersValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig->sightDistance) + NearestFriendlyPlayersValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig.sightDistance) : NearestUnitsValue(botAI, "nearest friendly players", range) { } diff --git a/src/Ai/Base/Value/NearestGameObjects.h b/src/Ai/Base/Value/NearestGameObjects.h index 2018e93eb1..9d1153aade 100644 --- a/src/Ai/Base/Value/NearestGameObjects.h +++ b/src/Ai/Base/Value/NearestGameObjects.h @@ -33,7 +33,7 @@ class AnyGameObjectInObjectRangeCheck class NearestGameObjects : public ObjectGuidListCalculatedValue { public: - NearestGameObjects(PlayerbotAI* botAI, float range = sPlayerbotAIConfig->sightDistance, bool ignoreLos = false, + NearestGameObjects(PlayerbotAI* botAI, float range = sPlayerbotAIConfig.sightDistance, bool ignoreLos = false, std::string const name = "nearest game objects") : ObjectGuidListCalculatedValue(botAI, name, 1 * 1000), range(range), ignoreLos(ignoreLos) { diff --git a/src/Ai/Base/Value/NearestNonBotPlayersValue.h b/src/Ai/Base/Value/NearestNonBotPlayersValue.h index 73d522c5fb..1980bcf2ba 100644 --- a/src/Ai/Base/Value/NearestNonBotPlayersValue.h +++ b/src/Ai/Base/Value/NearestNonBotPlayersValue.h @@ -14,7 +14,7 @@ class PlayerbotAI; class NearestNonBotPlayersValue : public NearestUnitsValue { public: - NearestNonBotPlayersValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig->grindDistance) + NearestNonBotPlayersValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig.grindDistance) : NearestUnitsValue(botAI, "nearest non bot players", range, true) { } diff --git a/src/Ai/Base/Value/NearestNpcsValue.cpp b/src/Ai/Base/Value/NearestNpcsValue.cpp index 1c188d2980..a32c007f10 100644 --- a/src/Ai/Base/Value/NearestNpcsValue.cpp +++ b/src/Ai/Base/Value/NearestNpcsValue.cpp @@ -27,7 +27,16 @@ void NearestHostileNpcsValue::FindUnits(std::list& targets) Cell::VisitObjects(bot, searcher, range); } -bool NearestHostileNpcsValue::AcceptUnit(Unit* unit) { return unit->IsHostileTo(bot) && !unit->IsPlayer(); } +bool NearestHostileNpcsValue::AcceptUnit(Unit* unit) +{ + if (!unit || !unit->IsInWorld() || unit->IsDuringRemoveFromWorld()) + return false; + + if (unit->IsPlayer()) + return false; + + return unit->IsHostileTo(bot); +} void NearestVehiclesValue::FindUnits(std::list& targets) { diff --git a/src/Ai/Base/Value/NearestNpcsValue.h b/src/Ai/Base/Value/NearestNpcsValue.h index 6935026147..71e1d9de45 100644 --- a/src/Ai/Base/Value/NearestNpcsValue.h +++ b/src/Ai/Base/Value/NearestNpcsValue.h @@ -14,7 +14,7 @@ class PlayerbotAI; class NearestNpcsValue : public NearestUnitsValue { public: - NearestNpcsValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig->sightDistance) + NearestNpcsValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig.sightDistance) : NearestUnitsValue(botAI, "nearest npcs", range) { } @@ -27,7 +27,7 @@ class NearestNpcsValue : public NearestUnitsValue class NearestHostileNpcsValue : public NearestUnitsValue { public: - NearestHostileNpcsValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig->sightDistance) + NearestHostileNpcsValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig.sightDistance) : NearestUnitsValue(botAI, "nearest hostile npcs", range) { } @@ -40,7 +40,7 @@ class NearestHostileNpcsValue : public NearestUnitsValue class NearestVehiclesValue : public NearestUnitsValue { public: - NearestVehiclesValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig->sightDistance) + NearestVehiclesValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig.sightDistance) : NearestUnitsValue(botAI, "nearest vehicles", range) { } @@ -53,7 +53,7 @@ class NearestVehiclesValue : public NearestUnitsValue class NearestTriggersValue : public NearestUnitsValue { public: - NearestTriggersValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig->sightDistance) + NearestTriggersValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig.sightDistance) : NearestUnitsValue(botAI, "nearest triggers", range) { } diff --git a/src/Ai/Base/Value/NearestUnitsValue.h b/src/Ai/Base/Value/NearestUnitsValue.h index 527925a0d7..5e00cb6d09 100644 --- a/src/Ai/Base/Value/NearestUnitsValue.h +++ b/src/Ai/Base/Value/NearestUnitsValue.h @@ -16,7 +16,7 @@ class NearestUnitsValue : public ObjectGuidListCalculatedValue { public: NearestUnitsValue(PlayerbotAI* botAI, std::string const name = "nearest units", - float range = sPlayerbotAIConfig->sightDistance, bool ignoreLos = false, uint32 checkInterval = 1) + float range = sPlayerbotAIConfig.sightDistance, bool ignoreLos = false, uint32 checkInterval = 1) : ObjectGuidListCalculatedValue(botAI, name, checkInterval), range(range), ignoreLos(ignoreLos) { } diff --git a/src/Ai/Base/Value/PartyMemberToHeal.cpp b/src/Ai/Base/Value/PartyMemberToHeal.cpp index 47554c7c2b..b49c1cd419 100644 --- a/src/Ai/Base/Value/PartyMemberToHeal.cpp +++ b/src/Ai/Base/Value/PartyMemberToHeal.cpp @@ -46,10 +46,10 @@ Unit* PartyMemberToHeal::Calculate() if (player && player->IsAlive()) { uint8 health = player->GetHealthPct(); - if (isRaid || health < sPlayerbotAIConfig->mediumHealth || !IsTargetOfSpellCast(player, predicate)) + if (isRaid || health < sPlayerbotAIConfig.mediumHealth || !IsTargetOfSpellCast(player, predicate)) { uint32 probeValue = 100; - if (player->GetDistance2d(bot) > sPlayerbotAIConfig->healDistance) + if (player->GetDistance2d(bot) > sPlayerbotAIConfig.healDistance) { probeValue = health + 30; } @@ -70,7 +70,7 @@ Unit* PartyMemberToHeal::Calculate() { uint8 health = ((Unit*)pet)->GetHealthPct(); uint32 probeValue = 100; - if (isRaid || health < sPlayerbotAIConfig->mediumHealth) + if (isRaid || health < sPlayerbotAIConfig.mediumHealth) probeValue = health + 30; // delay Check pet to here for better performance if (probeValue < calc.minValue && Check(pet)) @@ -84,7 +84,7 @@ Unit* PartyMemberToHeal::Calculate() { uint8 health = charm->GetHealthPct(); uint32 probeValue = 100; - if (isRaid || health < sPlayerbotAIConfig->mediumHealth) + if (isRaid || health < sPlayerbotAIConfig.mediumHealth) probeValue = health + 30; // delay Check charm to here for better performance if (probeValue < calc.minValue && Check(charm)) @@ -99,10 +99,10 @@ Unit* PartyMemberToHeal::Calculate() bool PartyMemberToHeal::Check(Unit* player) { // return player && player != bot && player->GetMapId() == bot->GetMapId() && player->IsInWorld() && - // sServerFacade->GetDistance2d(bot, player) < (player->IsPlayer() && botAI->IsTank((Player*)player) ? 50.0f + // ServerFacade::instance().GetDistance2d(bot, player) < (player->IsPlayer() && botAI->IsTank((Player*)player) ? 50.0f // : 40.0f); return player->GetMapId() == bot->GetMapId() && !player->IsCharmed() && - bot->GetDistance2d(player) < sPlayerbotAIConfig->healDistance * 2 && bot->IsWithinLOSInMap(player); + bot->GetDistance2d(player) < sPlayerbotAIConfig.healDistance * 2 && bot->IsWithinLOSInMap(player); } Unit* PartyMemberToProtect::Calculate() @@ -129,7 +129,7 @@ Unit* PartyMemberToProtect::Calculate() continue; float attackDistance = 30.0f; - if (sServerFacade->GetDistance2d(pVictim, unit) > attackDistance) + if (ServerFacade::instance().GetDistance2d(pVictim, unit) > attackDistance) continue; if (botAI->IsTank((Player*)pVictim) && pVictim->GetHealthPct() > 10) diff --git a/src/Ai/Base/Value/PartyMemberValue.cpp b/src/Ai/Base/Value/PartyMemberValue.cpp index 4ae9be08ad..7477429094 100644 --- a/src/Ai/Base/Value/PartyMemberValue.cpp +++ b/src/Ai/Base/Value/PartyMemberValue.cpp @@ -4,6 +4,7 @@ */ #include "PartyMemberValue.h" +#include "Corpse.h" #include "Playerbots.h" #include "ServerFacade.h" @@ -102,10 +103,10 @@ Unit* PartyMemberValue::FindPartyMember(FindPlayerPredicate& predicate, bool ign bool PartyMemberValue::Check(Unit* player) { // return player && player != bot && player->GetMapId() == bot->GetMapId() && bot->IsWithinDistInMap(player, - // sPlayerbotAIConfig->sightDistance, false); + // sPlayerbotAIConfig.sightDistance, false); bool isGM = player->ToPlayer() && player->ToPlayer()->IsGameMaster(); return player && player->GetMapId() == bot->GetMapId() && !isGM && - bot->GetDistance(player) < sPlayerbotAIConfig->spellDistance * 2 && + bot->GetDistance(player) < sPlayerbotAIConfig.spellDistance * 2 && bot->IsWithinLOS(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); } @@ -170,4 +171,4 @@ Unit* PartyMemberMainTankValue::Calculate() { FindMainTankPlayer findMainTankPlayer(botAI); return FindPartyMember(findMainTankPlayer); -} \ No newline at end of file +} diff --git a/src/Ai/Base/Value/PartyMemberWithoutAuraValue.h b/src/Ai/Base/Value/PartyMemberWithoutAuraValue.h index 57bb958c76..4ba9558ffe 100644 --- a/src/Ai/Base/Value/PartyMemberWithoutAuraValue.h +++ b/src/Ai/Base/Value/PartyMemberWithoutAuraValue.h @@ -17,7 +17,7 @@ class PartyMemberWithoutAuraValue : public PartyMemberValue, public Qualified { public: PartyMemberWithoutAuraValue(PlayerbotAI* botAI, std::string const name = "party member without aura", - float range = sPlayerbotAIConfig->sightDistance) + float range = sPlayerbotAIConfig.sightDistance) : PartyMemberValue(botAI, name) { } diff --git a/src/Ai/Base/Value/PartyMemberWithoutItemValue.h b/src/Ai/Base/Value/PartyMemberWithoutItemValue.h index 9ca128ff8d..2918ea4c57 100644 --- a/src/Ai/Base/Value/PartyMemberWithoutItemValue.h +++ b/src/Ai/Base/Value/PartyMemberWithoutItemValue.h @@ -17,7 +17,7 @@ class PartyMemberWithoutItemValue : public PartyMemberValue, public Qualified { public: PartyMemberWithoutItemValue(PlayerbotAI* botAI, std::string const name = "party member without item", - float range = sPlayerbotAIConfig->farDistance) + float range = sPlayerbotAIConfig.farDistance) : PartyMemberValue(botAI, name) { } diff --git a/src/Ai/Base/Value/PositionValue.h b/src/Ai/Base/Value/PositionValue.h index 69e8e35943..a0123dafc8 100644 --- a/src/Ai/Base/Value/PositionValue.h +++ b/src/Ai/Base/Value/PositionValue.h @@ -71,7 +71,7 @@ class CurrentPositionValue : public LogCalculatedValue bool EqualToLast(WorldPosition value) override { - return value.fDist(lastValue) < sPlayerbotAIConfig->tooCloseDistance; + return value.fDist(lastValue) < sPlayerbotAIConfig.tooCloseDistance; } WorldPosition Calculate() override; diff --git a/src/Ai/Base/Value/PossibleRpgTargetsValue.cpp b/src/Ai/Base/Value/PossibleRpgTargetsValue.cpp index 6e78f37f9a..f2b6aef105 100644 --- a/src/Ai/Base/Value/PossibleRpgTargetsValue.cpp +++ b/src/Ai/Base/Value/PossibleRpgTargetsValue.cpp @@ -54,10 +54,13 @@ void PossibleRpgTargetsValue::FindUnits(std::list& targets) bool PossibleRpgTargetsValue::AcceptUnit(Unit* unit) { + if (!unit || !unit->IsInWorld() || unit->IsDuringRemoveFromWorld()) + return false; + if (unit->IsHostileTo(bot) || unit->IsPlayer()) return false; - if (sServerFacade->GetDistance2d(bot, unit) <= sPlayerbotAIConfig->tooCloseDistance) + if (ServerFacade::instance().GetDistance2d(bot, unit) <= sPlayerbotAIConfig.tooCloseDistance) return false; if (unit->HasNpcFlag(UNIT_NPC_FLAG_SPIRITHEALER)) @@ -70,7 +73,8 @@ bool PossibleRpgTargetsValue::AcceptUnit(Unit* unit) } TravelTarget* travelTarget = context->GetValue("travel target")->Get(); - if (travelTarget->getDestination() && travelTarget->getDestination()->getEntry() == unit->GetEntry()) + if (travelTarget && travelTarget->getDestination() && + travelTarget->getDestination()->getEntry() == unit->GetEntry()) return true; if (urand(1, 100) < 25 && unit->IsFriendlyTo(bot)) @@ -145,6 +149,9 @@ void PossibleNewRpgTargetsValue::FindUnits(std::list& targets) bool PossibleNewRpgTargetsValue::AcceptUnit(Unit* unit) { + if (!unit || !unit->IsInWorld() || unit->IsDuringRemoveFromWorld()) + return false; + if (unit->IsHostileTo(bot) || unit->IsPlayer()) return false; diff --git a/src/Ai/Base/Value/PossibleTargetsValue.h b/src/Ai/Base/Value/PossibleTargetsValue.h index 13023b3bcb..c710c2676b 100644 --- a/src/Ai/Base/Value/PossibleTargetsValue.h +++ b/src/Ai/Base/Value/PossibleTargetsValue.h @@ -15,7 +15,7 @@ class PossibleTargetsValue : public NearestUnitsValue { public: PossibleTargetsValue(PlayerbotAI* botAI, std::string const name = "possible targets", - float range = sPlayerbotAIConfig->sightDistance, bool ignoreLos = false) + float range = sPlayerbotAIConfig.sightDistance, bool ignoreLos = false) : NearestUnitsValue(botAI, name, range, ignoreLos) { } @@ -28,7 +28,7 @@ class PossibleTargetsValue : public NearestUnitsValue class AllTargetsValue : public PossibleTargetsValue { public: - AllTargetsValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig->sightDistance) + AllTargetsValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig.sightDistance) : PossibleTargetsValue(botAI, "all targets", range, true) { } diff --git a/src/Ai/Base/Value/PvpValues.cpp b/src/Ai/Base/Value/PvpValues.cpp index e01b56ef2c..c8caf1441f 100644 --- a/src/Ai/Base/Value/PvpValues.cpp +++ b/src/Ai/Base/Value/PvpValues.cpp @@ -34,7 +34,7 @@ Unit* FlagCarrierValue::Calculate() if (carrier) { - if (ignoreRange || bot->IsWithinDistInMap(carrier, sPlayerbotAIConfig->sightDistance)) + if (ignoreRange || bot->IsWithinDistInMap(carrier, sPlayerbotAIConfig.sightDistance)) { return carrier; } @@ -65,7 +65,7 @@ Unit* FlagCarrierValue::Calculate() if (carrier) { - if (ignoreRange || bot->IsWithinDistInMap(carrier, sPlayerbotAIConfig->sightDistance)) + if (ignoreRange || bot->IsWithinDistInMap(carrier, sPlayerbotAIConfig.sightDistance)) { return carrier; } @@ -84,7 +84,7 @@ std::vector BgMastersValue::Calculate() std::vector entries; std::map>> battleMastersCache = - sRandomPlayerbotMgr->getBattleMastersCache(); + sRandomPlayerbotMgr.getBattleMastersCache(); entries.insert(entries.end(), battleMastersCache[TEAM_NEUTRAL][bgTypeId].begin(), battleMastersCache[TEAM_NEUTRAL][bgTypeId].end()); entries.insert(entries.end(), battleMastersCache[TEAM_ALLIANCE][bgTypeId].begin(), @@ -199,7 +199,7 @@ BattlegroundTypeId RpgBgTypeValue::Calculate() continue; std::map>> battleMastersCache = - sRandomPlayerbotMgr->getBattleMastersCache(); + sRandomPlayerbotMgr.getBattleMastersCache(); for (auto& entry : battleMastersCache[TEAM_NEUTRAL][bgTypeId]) if (entry == guidPosition.GetEntry()) diff --git a/src/Ai/Base/Value/RtiTargetValue.cpp b/src/Ai/Base/Value/RtiTargetValue.cpp index 205bcc3db0..4240e91c76 100644 --- a/src/Ai/Base/Value/RtiTargetValue.cpp +++ b/src/Ai/Base/Value/RtiTargetValue.cpp @@ -60,8 +60,8 @@ Unit* RtiTargetValue::Calculate() Unit* unit = botAI->GetUnit(guid); if (!unit || unit->isDead() || !bot->IsWithinLOSInMap(unit) || !AttackersValue::IsValidTarget(unit, bot) || - sServerFacade->IsDistanceGreaterThan(sServerFacade->GetDistance2d(bot, unit), - sPlayerbotAIConfig->sightDistance)) + ServerFacade::instance().IsDistanceGreaterThan(ServerFacade::instance().GetDistance2d(bot, unit), + sPlayerbotAIConfig.sightDistance)) return nullptr; // Also prevent chasing raid icon targets that are too far away from the master, @@ -69,8 +69,8 @@ Unit* RtiTargetValue::Calculate() if (Player* master = botAI->GetMaster()) { if (master->IsInWorld() && master->GetMapId() == unit->GetMapId() && - sServerFacade->IsDistanceGreaterThan(sServerFacade->GetDistance2d(master, unit), - sPlayerbotAIConfig->sightDistance)) + ServerFacade::instance().IsDistanceGreaterThan(ServerFacade::instance().GetDistance2d(master, unit), + sPlayerbotAIConfig.sightDistance)) return nullptr; } diff --git a/src/Ai/Base/Value/SnareTargetValue.cpp b/src/Ai/Base/Value/SnareTargetValue.cpp index 96e958c2d8..7965198aa4 100644 --- a/src/Ai/Base/Value/SnareTargetValue.cpp +++ b/src/Ai/Base/Value/SnareTargetValue.cpp @@ -30,7 +30,7 @@ Unit* SnareTargetValue::Calculate() return unit; case CHASE_MOTION_TYPE: { - chaseTarget = sServerFacade->GetChaseTarget(unit); + chaseTarget = ServerFacade::instance().GetChaseTarget(unit); if (!chaseTarget) continue; Player* chaseTargetPlayer = ObjectAccessor::FindPlayer(chaseTarget->GetGUID()); diff --git a/src/Ai/Base/Value/Stances.cpp b/src/Ai/Base/Value/Stances.cpp index 2e7a18d2b9..81d9b285c5 100644 --- a/src/Ai/Base/Value/Stances.cpp +++ b/src/Ai/Base/Value/Stances.cpp @@ -48,7 +48,7 @@ WorldLocation Stance::GetNearLocation(float angle, float distance) WorldLocation MoveStance::GetLocationInternal() { Unit* target = GetTarget(); - float distance = std::max(sPlayerbotAIConfig->meleeDistance, target->GetCombatReach()); + float distance = std::max(sPlayerbotAIConfig.meleeDistance, target->GetCombatReach()); float angle = GetAngle(); return GetNearLocation(angle, distance); @@ -56,7 +56,7 @@ WorldLocation MoveStance::GetLocationInternal() std::string const Stance::GetTargetName() { return "current target"; } -float Stance::GetMaxDistance() { return sPlayerbotAIConfig->contactDistance; } +float Stance::GetMaxDistance() { return sPlayerbotAIConfig.contactDistance; } StanceValue::~StanceValue() { diff --git a/src/Ai/Base/Value/StatsValues.cpp b/src/Ai/Base/Value/StatsValues.cpp index dc3499c683..615f39f019 100644 --- a/src/Ai/Base/Value/StatsValues.cpp +++ b/src/Ai/Base/Value/StatsValues.cpp @@ -183,8 +183,8 @@ bool IsInCombatValue::Calculate() continue; if (member->IsInCombat() && - sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(member, bot), - sPlayerbotAIConfig->reactDistance)) + ServerFacade::instance().IsDistanceLessOrEqualThan(ServerFacade::instance().GetDistance2d(member, bot), + sPlayerbotAIConfig.reactDistance)) return true; } } diff --git a/src/Ai/Base/Value/TargetValue.cpp b/src/Ai/Base/Value/TargetValue.cpp index 598b78441b..21621545ea 100644 --- a/src/Ai/Base/Value/TargetValue.cpp +++ b/src/Ai/Base/Value/TargetValue.cpp @@ -175,4 +175,4 @@ Unit* BossTargetValue::Calculate() { FindBossTargetStrategy strategy(botAI); return FindTarget(&strategy); -} \ No newline at end of file +} diff --git a/src/Ai/Base/ValueContext.h b/src/Ai/Base/ValueContext.h index 7349e9d614..ab93bcea47 100644 --- a/src/Ai/Base/ValueContext.h +++ b/src/Ai/Base/ValueContext.h @@ -396,7 +396,7 @@ class ValueContext : public NamedObjectContext static UntypedValue* nearest_game_objects(PlayerbotAI* botAI) { return new NearestGameObjects(botAI); } static UntypedValue* nearest_game_objects_no_los(PlayerbotAI* botAI) { - return new NearestGameObjects(botAI, sPlayerbotAIConfig->sightDistance, true); + return new NearestGameObjects(botAI, sPlayerbotAIConfig.sightDistance, true); } static UntypedValue* closest_game_objects(PlayerbotAI* botAI) { @@ -422,7 +422,7 @@ class ValueContext : public NamedObjectContext static UntypedValue* possible_triggers(PlayerbotAI* botAI) { return new PossibleTriggersValue(botAI); } static UntypedValue* possible_targets_no_los(PlayerbotAI* botAI) { - return new PossibleTargetsValue(botAI, "possible targets", sPlayerbotAIConfig->sightDistance, true); + return new PossibleTargetsValue(botAI, "possible targets", sPlayerbotAIConfig.sightDistance, true); } static UntypedValue* possible_adds(PlayerbotAI* botAI) { return new PossibleAddsValue(botAI); } static UntypedValue* prioritized_targets(PlayerbotAI* botAI) { return new PrioritizedTargetsValue(botAI); } diff --git a/src/Ai/Class/Dk/Trigger/DKTriggers.cpp b/src/Ai/Class/Dk/Trigger/DKTriggers.cpp index 90c1620953..4cad0c047c 100644 --- a/src/Ai/Class/Dk/Trigger/DKTriggers.cpp +++ b/src/Ai/Class/Dk/Trigger/DKTriggers.cpp @@ -75,4 +75,4 @@ bool DeathAndDecayCooldownTrigger::IsActive() return true; return bot->GetSpellCooldownDelay(spellId) >= 2000; -} \ No newline at end of file +} diff --git a/src/Ai/Class/Druid/Action/DruidActions.cpp b/src/Ai/Class/Druid/Action/DruidActions.cpp index 13336a674a..33b7826bf8 100644 --- a/src/Ai/Class/Druid/Action/DruidActions.cpp +++ b/src/Ai/Class/Druid/Action/DruidActions.cpp @@ -43,8 +43,8 @@ bool CastStarfallAction::isUseful() Unit* ccTarget = context->GetValue("current cc target")->Get(); if (ccTarget && ccTarget->IsAlive()) { - float dist2d = sServerFacade->GetDistance2d(ccTarget, aoePos.GetPositionX(), aoePos.GetPositionY()); - if (sServerFacade->IsDistanceLessOrEqualThan(dist2d, sPlayerbotAIConfig->aoeRadius)) + float dist2d = ServerFacade::instance().GetDistance2d(ccTarget, aoePos.GetPositionX(), aoePos.GetPositionY()); + if (ServerFacade::instance().IsDistanceLessOrEqualThan(dist2d, sPlayerbotAIConfig.aoeRadius)) return false; } @@ -75,7 +75,7 @@ std::vector CastRebirthAction::getPrerequisites() bool CastRebirthAction::isUseful() { return CastSpellAction::isUseful() && - AI_VALUE2(float, "distance", GetTargetName()) <= sPlayerbotAIConfig->spellDistance; + AI_VALUE2(float, "distance", GetTargetName()) <= sPlayerbotAIConfig.spellDistance; } Unit* CastRejuvenationOnNotFullAction::GetTarget() @@ -91,7 +91,7 @@ Unit* CastRejuvenationOnNotFullAction::GetTarget() { continue; } - if (player->GetDistance2d(bot) > sPlayerbotAIConfig->spellDistance) + if (player->GetDistance2d(bot) > sPlayerbotAIConfig.spellDistance) { continue; } @@ -107,4 +107,4 @@ Unit* CastRejuvenationOnNotFullAction::GetTarget() bool CastRejuvenationOnNotFullAction::isUseful() { return GetTarget(); -} \ No newline at end of file +} diff --git a/src/Ai/Class/Druid/Action/DruidShapeshiftActions.cpp b/src/Ai/Class/Druid/Action/DruidShapeshiftActions.cpp index 4f4a4e5968..1f066dc349 100644 --- a/src/Ai/Class/Druid/Action/DruidShapeshiftActions.cpp +++ b/src/Ai/Class/Druid/Action/DruidShapeshiftActions.cpp @@ -36,7 +36,7 @@ bool CastCasterFormAction::isUseful() { return botAI->HasAnyAuraOf(GetTarget(), "dire bear form", "bear form", "cat form", "travel form", "aquatic form", "flight form", "swift flight form", "moonkin form", nullptr) && - AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig->mediumHealth; + AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig.mediumHealth; } bool CastCasterFormAction::Execute(Event event) @@ -59,4 +59,4 @@ bool CastCancelTreeFormAction::Execute(Event event) bool CastTreeFormAction::isUseful() { return GetTarget() && CastSpellAction::isUseful() && !botAI->HasAura(33891, bot); -} \ No newline at end of file +} diff --git a/src/Ai/Class/Druid/Strategy/OffhealDruidCatStrategy.h b/src/Ai/Class/Druid/Strategy/OffhealDruidCatStrategy.h index 736de37cda..83775ef98c 100644 --- a/src/Ai/Class/Druid/Strategy/OffhealDruidCatStrategy.h +++ b/src/Ai/Class/Druid/Strategy/OffhealDruidCatStrategy.h @@ -24,4 +24,4 @@ } }; - #endif \ No newline at end of file + #endif diff --git a/src/Ai/Class/Hunter/Trigger/HunterTriggers.cpp b/src/Ai/Class/Hunter/Trigger/HunterTriggers.cpp index 091b8d5f72..84ece04b76 100644 --- a/src/Ai/Class/Hunter/Trigger/HunterTriggers.cpp +++ b/src/Ai/Class/Hunter/Trigger/HunterTriggers.cpp @@ -62,7 +62,7 @@ bool HuntersPetLowHealthTrigger::IsActive() bool HuntersPetMediumHealthTrigger::IsActive() { Unit* pet = AI_VALUE(Unit*, "pet target"); - return pet && AI_VALUE2(uint8, "health", "pet target") < sPlayerbotAIConfig->mediumHealth && + return pet && AI_VALUE2(uint8, "health", "pet target") < sPlayerbotAIConfig.mediumHealth && !AI_VALUE2(bool, "dead", "pet target") && !AI_VALUE2(bool, "mounted", "self target"); } @@ -74,7 +74,7 @@ bool HunterPetNotHappy::IsActive() bool HunterAspectOfTheViperTrigger::IsActive() { return SpellTrigger::IsActive() && !botAI->HasAura(spell, GetTarget()) && - AI_VALUE2(uint8, "mana", "self target") < (sPlayerbotAIConfig->lowMana / 2); + AI_VALUE2(uint8, "mana", "self target") < (sPlayerbotAIConfig.lowMana / 2); ; } @@ -96,7 +96,7 @@ bool SwitchToRangedTrigger::IsActive() Unit* target = AI_VALUE(Unit*, "current target"); return botAI->HasStrategy("close", BOT_STATE_COMBAT) && target && (target->GetVictim() != bot && - sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "current target"), 8.0f)); + ServerFacade::instance().IsDistanceGreaterThan(AI_VALUE2(float, "distance", "current target"), 8.0f)); } bool SwitchToMeleeTrigger::IsActive() @@ -104,7 +104,7 @@ bool SwitchToMeleeTrigger::IsActive() Unit* target = AI_VALUE(Unit*, "current target"); return botAI->HasStrategy("ranged", BOT_STATE_COMBAT) && target && (target->GetVictim() == bot && - sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "current target"), 8.0f)); + ServerFacade::instance().IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "current target"), 8.0f)); } bool NoTrackTrigger::IsActive() diff --git a/src/Ai/Class/Mage/Action/MageActions.cpp b/src/Ai/Class/Mage/Action/MageActions.cpp index 67587e3213..5eb63ea866 100644 --- a/src/Ai/Class/Mage/Action/MageActions.cpp +++ b/src/Ai/Class/Mage/Action/MageActions.cpp @@ -61,13 +61,13 @@ bool CastFrostNovaAction::isUseful() if (target->isFrozen()) return false; - return sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", GetTargetName()), 10.f); + return ServerFacade::instance().IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", GetTargetName()), 10.f); } bool CastConeOfColdAction::isUseful() { bool facingTarget = AI_VALUE2(bool, "facing", "current target"); - bool targetClose = sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", GetTargetName()), 10.f); + bool targetClose = ServerFacade::instance().IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", GetTargetName()), 10.f); return facingTarget && targetClose; } @@ -105,7 +105,7 @@ Unit* CastFocusMagicOnPartyAction::GetTarget() if (!member || member == bot || !member->IsAlive()) continue; - if (member->GetMap() != bot->GetMap() || bot->GetDistance(member) > sPlayerbotAIConfig->spellDistance) + if (member->GetMap() != bot->GetMap() || bot->GetDistance(member) > sPlayerbotAIConfig.spellDistance) continue; if (member->HasAura(54646)) diff --git a/src/Ai/Class/Paladin/PaladinAiObjectContext.cpp b/src/Ai/Class/Paladin/PaladinAiObjectContext.cpp index 4929eb9df0..45f676ec9f 100644 --- a/src/Ai/Class/Paladin/PaladinAiObjectContext.cpp +++ b/src/Ai/Class/Paladin/PaladinAiObjectContext.cpp @@ -454,4 +454,4 @@ void PaladinAiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContext void PaladinAiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts) { AiObjectContext::BuildSharedValueContexts(valueContexts); -} \ No newline at end of file +} diff --git a/src/Ai/Class/Paladin/Strategy/OffhealRetPaladinStrategy.h b/src/Ai/Class/Paladin/Strategy/OffhealRetPaladinStrategy.h index 3dfd24aa81..eeb9672ede 100644 --- a/src/Ai/Class/Paladin/Strategy/OffhealRetPaladinStrategy.h +++ b/src/Ai/Class/Paladin/Strategy/OffhealRetPaladinStrategy.h @@ -24,4 +24,4 @@ class OffhealRetPaladinStrategy : public GenericPaladinStrategy } }; -#endif \ No newline at end of file +#endif diff --git a/src/Ai/Class/Priest/Action/PriestActions.cpp b/src/Ai/Class/Priest/Action/PriestActions.cpp index e1c61033a1..ae55b104dc 100644 --- a/src/Ai/Class/Priest/Action/PriestActions.cpp +++ b/src/Ai/Class/Priest/Action/PriestActions.cpp @@ -30,11 +30,11 @@ Unit* CastPowerWordShieldOnAlmostFullHealthBelowAction::GetTarget() { continue; } - if (player->GetHealthPct() > sPlayerbotAIConfig->almostFullHealth) + if (player->GetHealthPct() > sPlayerbotAIConfig.almostFullHealth) { continue; } - if (player->GetDistance2d(bot) > sPlayerbotAIConfig->spellDistance) + if (player->GetDistance2d(bot) > sPlayerbotAIConfig.spellDistance) { continue; } @@ -59,11 +59,11 @@ bool CastPowerWordShieldOnAlmostFullHealthBelowAction::isUseful() { continue; } - if (player->GetHealthPct() > sPlayerbotAIConfig->almostFullHealth) + if (player->GetHealthPct() > sPlayerbotAIConfig.almostFullHealth) { continue; } - if (player->GetDistance2d(bot) > sPlayerbotAIConfig->spellDistance) + if (player->GetDistance2d(bot) > sPlayerbotAIConfig.spellDistance) { continue; } @@ -89,7 +89,7 @@ Unit* CastPowerWordShieldOnNotFullAction::GetTarget() { continue; } - if (player->GetDistance2d(bot) > sPlayerbotAIConfig->spellDistance) + if (player->GetDistance2d(bot) > sPlayerbotAIConfig.spellDistance) { continue; } @@ -105,4 +105,4 @@ Unit* CastPowerWordShieldOnNotFullAction::GetTarget() bool CastPowerWordShieldOnNotFullAction::isUseful() { return GetTarget(); -} \ No newline at end of file +} diff --git a/src/Ai/Class/Priest/Trigger/PriestTriggers.cpp b/src/Ai/Class/Priest/Trigger/PriestTriggers.cpp index 894780ad45..7f61ba6eec 100644 --- a/src/Ai/Class/Priest/Trigger/PriestTriggers.cpp +++ b/src/Ai/Class/Priest/Trigger/PriestTriggers.cpp @@ -68,14 +68,14 @@ bool ShadowformTrigger::IsActive() { return !botAI->HasAura("shadowform", bot); bool ShadowfiendTrigger::IsActive() { return BoostTrigger::IsActive() && !bot->HasSpellCooldown(34433); } BindingHealTrigger::BindingHealTrigger(PlayerbotAI* botAI) - : PartyMemberLowHealthTrigger(botAI, "binding heal", sPlayerbotAIConfig->lowHealth, 0) + : PartyMemberLowHealthTrigger(botAI, "binding heal", sPlayerbotAIConfig.lowHealth, 0) { } bool BindingHealTrigger::IsActive() { return PartyMemberLowHealthTrigger::IsActive() && - AI_VALUE2(uint8, "health", "self target") < sPlayerbotAIConfig->mediumHealth; + AI_VALUE2(uint8, "health", "self target") < sPlayerbotAIConfig.mediumHealth; } const std::set MindSearChannelCheckTrigger::MIND_SEAR_SPELL_IDS = { diff --git a/src/Ai/Class/Rogue/Action/RogueActions.cpp b/src/Ai/Class/Rogue/Action/RogueActions.cpp index 3019e0ec86..fb4975ab33 100644 --- a/src/Ai/Class/Rogue/Action/RogueActions.cpp +++ b/src/Ai/Class/Rogue/Action/RogueActions.cpp @@ -14,7 +14,7 @@ bool CastStealthAction::isUseful() { Unit* target = AI_VALUE(Unit*, "current target"); - if (target && bot->GetDistance(target) >= sPlayerbotAIConfig->spellDistance) + if (target && bot->GetDistance(target) >= sPlayerbotAIConfig.spellDistance) return false; return true; } diff --git a/src/Ai/Class/Rogue/RogueAiObjectContext.cpp b/src/Ai/Class/Rogue/RogueAiObjectContext.cpp index 9875f23dec..8586d93d14 100644 --- a/src/Ai/Class/Rogue/RogueAiObjectContext.cpp +++ b/src/Ai/Class/Rogue/RogueAiObjectContext.cpp @@ -227,4 +227,4 @@ void RogueAiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextLi void RogueAiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts) { AiObjectContext::BuildSharedValueContexts(valueContexts); -} \ No newline at end of file +} diff --git a/src/Ai/Class/Rogue/Strategy/AssassinationRogueStrategy.h b/src/Ai/Class/Rogue/Strategy/AssassinationRogueStrategy.h index 5692528a0e..3a6ac209d1 100644 --- a/src/Ai/Class/Rogue/Strategy/AssassinationRogueStrategy.h +++ b/src/Ai/Class/Rogue/Strategy/AssassinationRogueStrategy.h @@ -16,4 +16,4 @@ class AssassinationRogueStrategy : public MeleeCombatStrategy uint32 GetType() const override { return MeleeCombatStrategy::GetType() | STRATEGY_TYPE_DPS; } }; -#endif \ No newline at end of file +#endif diff --git a/src/Ai/Class/Rogue/Trigger/RogueTriggers.cpp b/src/Ai/Class/Rogue/Trigger/RogueTriggers.cpp index fd9901552e..c33dbb7fe4 100644 --- a/src/Ai/Class/Rogue/Trigger/RogueTriggers.cpp +++ b/src/Ai/Class/Rogue/Trigger/RogueTriggers.cpp @@ -22,7 +22,7 @@ bool UnstealthTrigger::IsActive() return botAI->HasAura("stealth", bot) && !AI_VALUE(uint8, "attacker count") && (AI_VALUE2(bool, "moving", "self target") && ((botAI->GetMaster() && - sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "group leader"), 10.0f) && + ServerFacade::instance().IsDistanceGreaterThan(AI_VALUE2(float, "distance", "group leader"), 10.0f) && AI_VALUE2(bool, "moving", "group leader")) || !AI_VALUE(uint8, "attacker count"))); } @@ -60,7 +60,7 @@ bool StealthTrigger::IsActive() if (bot->InArena()) distance += 15; - return target && sServerFacade->GetDistance2d(bot, target) < distance; + return target && ServerFacade::instance().GetDistance2d(bot, target) < distance; } bool SapTrigger::IsPossible() { return bot->GetLevel() > 10 && bot->HasSpell(6770) && !bot->IsInCombat(); } @@ -99,8 +99,8 @@ bool SprintTrigger::IsActive() return AI_VALUE2(bool, "moving", "self target") && (AI_VALUE2(bool, "moving", "dps target") || AI_VALUE2(bool, "moving", "enemy player target")) && targeted && - (sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "dps target"), distance) || - sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "enemy player target"), distance)); + (ServerFacade::instance().IsDistanceGreaterThan(AI_VALUE2(float, "distance", "dps target"), distance) || + ServerFacade::instance().IsDistanceGreaterThan(AI_VALUE2(float, "distance", "enemy player target"), distance)); } bool ExposeArmorTrigger::IsActive() diff --git a/src/Ai/Class/Warlock/Action/WarlockActions.cpp b/src/Ai/Class/Warlock/Action/WarlockActions.cpp index e899c7a2f6..4e09eb6523 100644 --- a/src/Ai/Class/Warlock/Action/WarlockActions.cpp +++ b/src/Ai/Class/Warlock/Action/WarlockActions.cpp @@ -25,7 +25,7 @@ const int ITEM_SOUL_SHARD = 6265; bool CastDrainSoulAction::isUseful() { return AI_VALUE2(uint32, "item count", "soul shard") < 26; } // Checks if the bot's health is above a certain threshold, and if so, allows casting Life Tap -bool CastLifeTapAction::isUseful() { return AI_VALUE2(uint8, "health", "self target") > sPlayerbotAIConfig->lowHealth; } +bool CastLifeTapAction::isUseful() { return AI_VALUE2(uint8, "health", "self target") > sPlayerbotAIConfig.lowHealth; } // Checks if the target marked with the moon icon can be banished bool CastBanishOnCcAction::isPossible() @@ -288,7 +288,7 @@ bool UseSoulstoneMasterAction::Execute(Event event) soulstoneReservations[master->GetGUID()] = now + 2500; // Reserve for 2.5 seconds } - float distance = sServerFacade->GetDistance2d(bot, master); + float distance = ServerFacade::instance().GetDistance2d(bot, master); if (distance >= 30.0f) return false; @@ -325,7 +325,7 @@ bool UseSoulstoneTankAction::Execute(Event event) if (soulstoneReservations.count(member->GetGUID()) && soulstoneReservations[member->GetGUID()] > now) continue; // Already being soulstoned - float distance = sServerFacade->GetDistance2d(bot, member); + float distance = ServerFacade::instance().GetDistance2d(bot, member); if (distance < 30.0f && bot->IsWithinLOSInMap(member)) { chosenTank = member; @@ -348,7 +348,7 @@ bool UseSoulstoneTankAction::Execute(Event event) soulstoneReservations[member->GetGUID()] > now) continue; // Already being soulstoned - float distance = sServerFacade->GetDistance2d(bot, member); + float distance = ServerFacade::instance().GetDistance2d(bot, member); if (distance < 30.0f && bot->IsWithinLOSInMap(member)) { chosenTank = member; @@ -392,7 +392,7 @@ bool UseSoulstoneHealerAction::Execute(Event event) soulstoneReservations[member->GetGUID()] > now) continue; // Already being soulstoned - float distance = sServerFacade->GetDistance2d(bot, member); + float distance = ServerFacade::instance().GetDistance2d(bot, member); if (distance < 30.0f && bot->IsWithinLOSInMap(member)) { healer = member; diff --git a/src/Ai/Class/Warlock/Trigger/WarlockTriggers.cpp b/src/Ai/Class/Warlock/Trigger/WarlockTriggers.cpp index 04592c9b41..53e77669b2 100644 --- a/src/Ai/Class/Warlock/Trigger/WarlockTriggers.cpp +++ b/src/Ai/Class/Warlock/Trigger/WarlockTriggers.cpp @@ -96,7 +96,7 @@ bool DecimationTrigger::IsActive() // Checks if the bot's mana is below 85% and health is above a low health threshold bool LifeTapTrigger::IsActive() { - if (AI_VALUE2(uint8, "health", "self target") <= sPlayerbotAIConfig->lowHealth) + if (AI_VALUE2(uint8, "health", "self target") <= sPlayerbotAIConfig.lowHealth) return false; if (!AI_VALUE2(bool, "has mana", "self target")) diff --git a/src/Ai/Class/Warrior/Trigger/WarriorTriggers.cpp b/src/Ai/Class/Warrior/Trigger/WarriorTriggers.cpp index b561c4815d..5aa419c927 100644 --- a/src/Ai/Class/Warrior/Trigger/WarriorTriggers.cpp +++ b/src/Ai/Class/Warrior/Trigger/WarriorTriggers.cpp @@ -9,7 +9,7 @@ bool BloodrageBuffTrigger::IsActive() { - return AI_VALUE2(uint8, "health", "self target") >= sPlayerbotAIConfig->mediumHealth && + return AI_VALUE2(uint8, "health", "self target") >= sPlayerbotAIConfig.mediumHealth && AI_VALUE2(uint8, "rage", "self target") < 20; } diff --git a/src/Ai/Class/Warrior/WarriorAiObjectContext.cpp b/src/Ai/Class/Warrior/WarriorAiObjectContext.cpp index 3a9af55172..22754beab4 100644 --- a/src/Ai/Class/Warrior/WarriorAiObjectContext.cpp +++ b/src/Ai/Class/Warrior/WarriorAiObjectContext.cpp @@ -358,4 +358,4 @@ void WarriorAiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContext void WarriorAiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts) { AiObjectContext::BuildSharedValueContexts(valueContexts); -} \ No newline at end of file +} diff --git a/src/Ai/Dungeon/UtgardePinnacle/Multiplier/UtgardePinnacleMultipliers.cpp b/src/Ai/Dungeon/UtgardePinnacle/Multiplier/UtgardePinnacleMultipliers.cpp index 9a950933e5..cc34cb6a4e 100644 --- a/src/Ai/Dungeon/UtgardePinnacle/Multiplier/UtgardePinnacleMultipliers.cpp +++ b/src/Ai/Dungeon/UtgardePinnacle/Multiplier/UtgardePinnacleMultipliers.cpp @@ -96,4 +96,4 @@ float YmironMultiplier::GetValue(Action* action) } } return 1.0f; -} \ No newline at end of file +} diff --git a/src/Ai/Dungeon/UtgardePinnacle/Trigger/UtgardePinnacleTriggers.cpp b/src/Ai/Dungeon/UtgardePinnacle/Trigger/UtgardePinnacleTriggers.cpp index b9b21dc846..dc35e8be08 100644 --- a/src/Ai/Dungeon/UtgardePinnacle/Trigger/UtgardePinnacleTriggers.cpp +++ b/src/Ai/Dungeon/UtgardePinnacle/Trigger/UtgardePinnacleTriggers.cpp @@ -53,4 +53,4 @@ bool YmironBaneTrigger::IsActive() if (!boss) { return false; } return boss->FindCurrentSpellBySpellId(SPELL_BANE) || boss->HasAura(SPELL_BANE); -} \ No newline at end of file +} diff --git a/src/Ai/Raid/BlackwingLair/Strategy/RaidBwlStrategy.h b/src/Ai/Raid/BlackwingLair/Strategy/RaidBwlStrategy.h index 27bced8ea4..4308871c85 100644 --- a/src/Ai/Raid/BlackwingLair/Strategy/RaidBwlStrategy.h +++ b/src/Ai/Raid/BlackwingLair/Strategy/RaidBwlStrategy.h @@ -15,4 +15,4 @@ class RaidBwlStrategy : public Strategy // virtual void InitMultipliers(std::vector &multipliers) override; }; -#endif \ No newline at end of file +#endif diff --git a/src/Ai/Raid/Icecrown/Action/RaidIccActions.cpp b/src/Ai/Raid/Icecrown/Action/RaidIccActions.cpp index 14c8ada9ac..d6a91d0477 100644 --- a/src/Ai/Raid/Icecrown/Action/RaidIccActions.cpp +++ b/src/Ai/Raid/Icecrown/Action/RaidIccActions.cpp @@ -6810,7 +6810,7 @@ bool IccLichKingShadowTrapAction::Execute(Event event) Difficulty diff = bot->GetRaidDifficulty(); - if (sPlayerbotAIConfig->EnableICCBuffs && diff && (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC)) + if (sPlayerbotAIConfig.EnableICCBuffs && diff && (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC)) { //-------CHEAT------- if (!bot->HasAura(SPELL_EXPERIENCED)) @@ -7006,7 +7006,7 @@ bool IccLichKingWinterAction::Execute(Event event) Difficulty diff = bot->GetRaidDifficulty(); - if (sPlayerbotAIConfig->EnableICCBuffs && diff && (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC)) + if (sPlayerbotAIConfig.EnableICCBuffs && diff && (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC)) { //------CHEAT------- if (!bot->HasAura(SPELL_EXPERIENCED)) @@ -7792,7 +7792,7 @@ bool IccLichKingAddsAction::Execute(Event event) Difficulty diff = bot->GetRaidDifficulty(); - if (sPlayerbotAIConfig->EnableICCBuffs && diff && (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC)) + if (sPlayerbotAIConfig.EnableICCBuffs && diff && (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC)) { //------CHEAT------- if (!bot->HasAura(SPELL_EXPERIENCED)) @@ -9192,7 +9192,7 @@ void IccLichKingAddsAction::HandleValkyrAssignment(const std::vector& gra bot->SetFacingToObject(myValkyr); Difficulty diff = bot->GetRaidDifficulty(); - if (sPlayerbotAIConfig->EnableICCBuffs && diff && (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC)) + if (sPlayerbotAIConfig.EnableICCBuffs && diff && (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC)) { //---------CHEAT--------- if (!myValkyr->HasAura(SPELL_HAMMER_OF_JUSTICE)) diff --git a/src/Ai/Raid/Icecrown/RaidIccScripts.h b/src/Ai/Raid/Icecrown/RaidIccScripts.h index 98c7d1ba3b..e2fc782cad 100644 --- a/src/Ai/Raid/Icecrown/RaidIccScripts.h +++ b/src/Ai/Raid/Icecrown/RaidIccScripts.h @@ -3,4 +3,4 @@ #include "../../../../src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h" -#endif \ No newline at end of file +#endif diff --git a/src/Ai/Raid/Icecrown/Trigger/RaidIccTriggers.cpp b/src/Ai/Raid/Icecrown/Trigger/RaidIccTriggers.cpp index 55cfe9fc93..b34fe003fc 100644 --- a/src/Ai/Raid/Icecrown/Trigger/RaidIccTriggers.cpp +++ b/src/Ai/Raid/Icecrown/Trigger/RaidIccTriggers.cpp @@ -99,7 +99,10 @@ bool IccGunshipCannonNearTrigger::IsActive() bool IccGunshipTeleportAllyTrigger::IsActive() { Unit* boss = bot->FindNearestCreature(NPC_HIGH_OVERLORD_SAURFANG, 100.0f); - if (!boss) + if (!boss || !boss->IsInWorld() || boss->IsDuringRemoveFromWorld()) + return false; + + if (!boss->IsAlive()) return false; if (!boss->IsHostileTo(bot)) @@ -111,7 +114,10 @@ bool IccGunshipTeleportAllyTrigger::IsActive() bool IccGunshipTeleportHordeTrigger::IsActive() { Unit* boss = bot->FindNearestCreature(NPC_MURADIN_BRONZEBEARD, 100.0f); - if (!boss) + if (!boss || !boss->IsInWorld() || boss->IsDuringRemoveFromWorld()) + return false; + + if (!boss->IsAlive()) return false; if (!boss->IsHostileTo(bot)) @@ -281,7 +287,7 @@ bool IccPutricideGrowingOozePuddleTrigger::IsActive() Difficulty diff = bot->GetRaidDifficulty(); - if (sPlayerbotAIConfig->EnableICCBuffs && diff && (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC)) + if (sPlayerbotAIConfig.EnableICCBuffs && diff && (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC)) { //-------CHEAT------- if (!bot->HasAura(SPELL_EXPERIENCED)) @@ -828,7 +834,7 @@ bool IccSindragosaGroupPositionTrigger::IsActive() Difficulty diff = bot->GetRaidDifficulty(); - if (sPlayerbotAIConfig->EnableICCBuffs && diff && (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC)) + if (sPlayerbotAIConfig.EnableICCBuffs && diff && (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC)) { //-------CHEAT------- if (!bot->HasAura(SPELL_EXPERIENCED)) diff --git a/src/Ai/Raid/Karazhan/Action/RaidKarazhanActions.cpp b/src/Ai/Raid/Karazhan/Action/RaidKarazhanActions.cpp index 2e5d7abcfd..adf0eac488 100644 --- a/src/Ai/Raid/Karazhan/Action/RaidKarazhanActions.cpp +++ b/src/Ai/Raid/Karazhan/Action/RaidKarazhanActions.cpp @@ -617,7 +617,7 @@ bool NetherspiteBlockRedBeamAction::Execute(Event event) if (!wasBlocking) { std::map placeholders{{"%player", bot->GetName()}}; - std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( + std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault( "netherspite_beam_blocking_red", "%player is moving to block the red beam!", placeholders); bot->Yell(text, LANG_UNIVERSAL); } @@ -700,7 +700,7 @@ bool NetherspiteBlockBlueBeamAction::Execute(Event event) if (wasBlocking && !isBlockingNow) { std::map placeholders{{"%player", bot->GetName()}}; - std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( + std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault( "netherspite_beam_leaving_blue", "%player is leaving the blue beam--next blocker up!", placeholders); bot->Yell(text, LANG_UNIVERSAL); _wasBlockingBlueBeam[botGuid] = false; @@ -711,7 +711,7 @@ bool NetherspiteBlockBlueBeamAction::Execute(Event event) if (!wasBlocking) { std::map placeholders{{"%player", bot->GetName()}}; - std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( + std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault( "netherspite_beam_blocking_blue", "%player is moving to block the blue beam!", placeholders); bot->Yell(text, LANG_UNIVERSAL); } @@ -793,7 +793,7 @@ bool NetherspiteBlockGreenBeamAction::Execute(Event event) if (wasBlocking && !isBlockingNow) { std::map placeholders{{"%player", bot->GetName()}}; - std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( + std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault( "netherspite_beam_leaving_green", "%player is leaving the green beam--next blocker up!", placeholders); bot->Yell(text, LANG_UNIVERSAL); _wasBlockingGreenBeam[botGuid] = false; @@ -804,7 +804,7 @@ bool NetherspiteBlockGreenBeamAction::Execute(Event event) if (!wasBlocking) { std::map placeholders{{"%player", bot->GetName()}}; - std::string text = sPlayerbotTextMgr->GetBotTextOrDefault( + std::string text = PlayerbotTextMgr::instance().GetBotTextOrDefault( "netherspite_beam_blocking_green", "%player is moving to block the green beam!", placeholders); bot->Yell(text, LANG_UNIVERSAL); } diff --git a/src/Ai/Raid/Karazhan/RaidKarazhanTriggerContext.h b/src/Ai/Raid/Karazhan/RaidKarazhanTriggerContext.h index fa2b7d37a5..e3f606c949 100644 --- a/src/Ai/Raid/Karazhan/RaidKarazhanTriggerContext.h +++ b/src/Ai/Raid/Karazhan/RaidKarazhanTriggerContext.h @@ -260,4 +260,4 @@ class RaidKarazhanTriggerContext : public NamedObjectContext PlayerbotAI* botAI) { return new NightbaneNeedToManageTimersAndTrackersTrigger(botAI); } }; -#endif \ No newline at end of file +#endif diff --git a/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions.h b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions.h new file mode 100644 index 0000000000..5e1290c124 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions.h @@ -0,0 +1,398 @@ +#ifndef _PLAYERBOT_RAIDNAXXACTIONS_H +#define _PLAYERBOT_RAIDNAXXACTIONS_H + +#include "Action.h" +#include "AttackAction.h" +#include "GenericActions.h" +#include "MovementActions.h" +#include "PlayerbotAI.h" +#include "Playerbots.h" +#include "RaidNaxxBossHelper.h" + +// just for test +// class TryToGetBossAIAction : public Action +// { +// public: +// TryToGetBossAIAction(PlayerbotAI* ai) : Action(ai, "try to get boss ai") {} + +// public: +// virtual bool Execute(Event event); +// }; + +class GrobbulusGoBehindAction : public MovementAction +{ +public: + GrobbulusGoBehindAction(PlayerbotAI* ai, float distance = 24.0f, float delta_angle = M_PI / 8) + : MovementAction(ai, "grobbulus go behind") + { + this->distance = distance; + this->delta_angle = delta_angle; + } + virtual bool Execute(Event event); + +protected: + float distance, delta_angle; +}; + +class GrobbulusRotateAction : public RotateAroundTheCenterPointAction +{ +public: + GrobbulusRotateAction(PlayerbotAI* botAI) + : RotateAroundTheCenterPointAction(botAI, "rotate grobbulus", 3281.23f, -3310.38f, 35.0f, 8, true, M_PI) + { + } + virtual bool isUseful() override + { + return RotateAroundTheCenterPointAction::isUseful() && botAI->IsMainTank(bot) && + AI_VALUE2(bool, "has aggro", "boss target"); + } + uint32 GetCurrWaypoint() override; +}; + +class GrobblulusMoveCenterAction : public MoveInsideAction +{ +public: + GrobblulusMoveCenterAction(PlayerbotAI* ai) : MoveInsideAction(ai, 3281.23f, -3310.38f, 5.0f) {} +}; + +class GrobbulusMoveAwayAction : public MovementAction +{ +public: + GrobbulusMoveAwayAction(PlayerbotAI* ai, float distance = 18.0f) + : MovementAction(ai, "grobbulus move away"), distance(distance) + { + } + bool Execute(Event event) override; + +private: + float distance; +}; + +class FaerlinaSacrificeWorshipperAction : public AttackAction +{ +public: + FaerlinaSacrificeWorshipperAction(PlayerbotAI* ai) : AttackAction(ai, "faerlina sacrifice worshipper") {} + + bool Execute(Event event) override; + bool isUseful() override; + +protected: + Unit* GetTarget() override; +}; + +class HeiganDanceAction : public MovementAction +{ +public: + HeiganDanceAction(PlayerbotAI* ai) : MovementAction(ai, "heigan dance") + { + this->last_eruption_ms = 0; + this->platform_phase = false; + ResetSafe(); + waypoints.push_back(std::make_pair(2794.88f, -3668.12f)); + waypoints.push_back(std::make_pair(2775.49f, -3674.43f)); + waypoints.push_back(std::make_pair(2762.30f, -3684.59f)); + waypoints.push_back(std::make_pair(2755.99f, -3703.96f)); + platform = std::make_pair(2794.26f, -3706.67f); + } + +protected: + bool CalculateSafe(); + void ResetSafe() + { + curr_safe = 0; + curr_dir = 1; + } + void NextSafe() + { + curr_safe += curr_dir; + if (curr_safe == 3 || curr_safe == 0) + { + curr_dir = -curr_dir; + } + } + uint32 last_eruption_ms; + bool platform_phase; + uint32 curr_safe, curr_dir; + std::vector> waypoints; + std::pair platform; +}; + +class HeiganDanceMeleeAction : public HeiganDanceAction +{ +public: + HeiganDanceMeleeAction(PlayerbotAI* ai) : HeiganDanceAction(ai) {} + virtual bool Execute(Event event); +}; + +class HeiganDanceRangedAction : public HeiganDanceAction +{ +public: + HeiganDanceRangedAction(PlayerbotAI* ai) : HeiganDanceAction(ai) {} + virtual bool Execute(Event event); +}; + +class ThaddiusAttackNearestPetAction : public AttackAction +{ +public: + ThaddiusAttackNearestPetAction(PlayerbotAI* ai) : AttackAction(ai, "thaddius attack nearest pet"), helper(ai) {} + virtual bool Execute(Event event); + virtual bool isUseful(); + +private: + ThaddiusBossHelper helper; +}; + +// class ThaddiusMeleeToPlaceAction : public MovementAction +// { +// public: +// ThaddiusMeleeToPlaceAction(PlayerbotAI* ai) : MovementAction(ai, "thaddius melee to place") {} +// virtual bool Execute(Event event); +// virtual bool isUseful(); +// }; + +// class ThaddiusRangedToPlaceAction : public MovementAction +// { +// public: +// ThaddiusRangedToPlaceAction(PlayerbotAI* ai) : MovementAction(ai, "thaddius ranged to place") {} +// virtual bool Execute(Event event); +// virtual bool isUseful(); +// }; + +class ThaddiusMoveToPlatformAction : public MovementAction +{ +public: + ThaddiusMoveToPlatformAction(PlayerbotAI* ai) : MovementAction(ai, "thaddius move to platform") {} + virtual bool Execute(Event event); + virtual bool isUseful(); +}; + +class ThaddiusMovePolarityAction : public MovementAction +{ +public: + ThaddiusMovePolarityAction(PlayerbotAI* ai) : MovementAction(ai, "thaddius move polarity") {} + virtual bool Execute(Event event); + virtual bool isUseful(); +}; + +class RazuviousUseObedienceCrystalAction : public MovementAction +{ +public: + RazuviousUseObedienceCrystalAction(PlayerbotAI* ai) + : MovementAction(ai, "razuvious use obedience crystal"), helper(ai) + { + } + bool Execute(Event event) override; + +private: + RazuviousBossHelper helper; +}; + +class RazuviousTargetAction : public AttackAction +{ +public: + RazuviousTargetAction(PlayerbotAI* ai) : AttackAction(ai, "razuvious target"), helper(ai) {} + bool Execute(Event event) override; + +private: + RazuviousBossHelper helper; +}; + +class HorsemanAttractAlternativelyAction : public AttackAction +{ +public: + HorsemanAttractAlternativelyAction(PlayerbotAI* ai) : AttackAction(ai, "horseman attract alternatively"), helper(ai) + { + } + bool Execute(Event event) override; + +protected: + FourhorsemanBossHelper helper; +}; + +class HorsemanAttactInOrderAction : public AttackAction +{ +public: + HorsemanAttactInOrderAction(PlayerbotAI* ai) : AttackAction(ai, "horseman attact in order"), helper(ai) {} + bool Execute(Event event) override; + +protected: + FourhorsemanBossHelper helper; +}; + +class SapphironGroundPositionAction : public MovementAction +{ +public: + SapphironGroundPositionAction(PlayerbotAI* ai) : MovementAction(ai, "sapphiron ground position"), helper(ai) {} + bool Execute(Event event) override; + +protected: + SapphironBossHelper helper; +}; + +class SapphironFlightPositionAction : public MovementAction +{ +public: + SapphironFlightPositionAction(PlayerbotAI* ai) : MovementAction(ai, "sapphiron flight position"), helper(ai) {} + bool Execute(Event event) override; + +protected: + SapphironBossHelper helper; + bool MoveToNearestIcebolt(); +}; + +class KelthuzadChooseTargetAction : public AttackAction +{ +public: + KelthuzadChooseTargetAction(PlayerbotAI* ai) : AttackAction(ai, "kel'thuzad choose target"), helper(ai) {} + virtual bool Execute(Event event); + +private: + KelthuzadBossHelper helper; +}; + +class KelthuzadPositionAction : public MovementAction +{ +public: + KelthuzadPositionAction(PlayerbotAI* ai) : MovementAction(ai, "kel'thuzad position"), helper(ai) {} + virtual bool Execute(Event event); + +private: + KelthuzadBossHelper helper; +}; + +class AnubrekhanChooseTargetAction : public AttackAction +{ +public: + AnubrekhanChooseTargetAction(PlayerbotAI* ai) : AttackAction(ai, "anub'rekhan choose target") {} + bool Execute(Event event) override; +}; + +class AnubrekhanPositionAction : public RotateAroundTheCenterPointAction +{ +public: + AnubrekhanPositionAction(PlayerbotAI* ai) + : RotateAroundTheCenterPointAction(ai, "anub'rekhan position", 3272.49f, -3476.27f, 45.0f, 16) + { + } + bool Execute(Event event) override; +}; + +class GluthChooseTargetAction : public AttackAction +{ +public: + GluthChooseTargetAction(PlayerbotAI* ai) : AttackAction(ai, "gluth choose target"), helper(ai) {} + bool Execute(Event event) override; + +private: + GluthBossHelper helper; +}; + +class GluthPositionAction : public RotateAroundTheCenterPointAction +{ +public: + GluthPositionAction(PlayerbotAI* ai) + : RotateAroundTheCenterPointAction(ai, "gluth position", 3293.61f, -3149.01f, 12.0f, 12), helper(ai) + { + } + bool Execute(Event event) override; + +private: + GluthBossHelper helper; +}; + +class GluthSlowdownAction : public Action +{ +public: + GluthSlowdownAction(PlayerbotAI* ai) : Action(ai, "gluth slowdown"), helper(ai) {} + bool Execute(Event event) override; + +private: + GluthBossHelper helper; +}; + +class LoathebPositionAction : public MovementAction +{ +public: + LoathebPositionAction(PlayerbotAI* ai) : MovementAction(ai, "loatheb position"), helper(ai) {} + virtual bool Execute(Event event); + +private: + LoathebBossHelper helper; +}; + +class LoathebChooseTargetAction : public AttackAction +{ +public: + LoathebChooseTargetAction(PlayerbotAI* ai) : AttackAction(ai, "loatheb choose target"), helper(ai) {} + virtual bool Execute(Event event); + +private: + LoathebBossHelper helper; +}; + +class NothChooseTargetAction : public AttackAction +{ +public: + NothChooseTargetAction(PlayerbotAI* ai) : AttackAction(ai, "noth choose target"), helper(ai) {} + bool Execute(Event event) override; + +private: + NothBossHelper helper; +}; + +class NothPositionAction : public MovementAction +{ +public: + NothPositionAction(PlayerbotAI* ai) : MovementAction(ai, "noth position"), helper(ai) {} + bool Execute(Event event) override; + +private: + NothBossHelper helper; +}; + +class PatchwerkRangedPositionAction : public MovementAction +{ +public: + PatchwerkRangedPositionAction(PlayerbotAI* ai) : MovementAction(ai, "patchwerk ranged position") {} + bool Execute(Event event) override; +}; + +// Maexxna +class MaexxnaAttackWebWrapAction : public AttackAction +{ +public: + MaexxnaAttackWebWrapAction(PlayerbotAI* ai) : AttackAction(ai, "maexxna attack web wrap") {} + + bool Execute(Event event) override; + bool isUseful() override; +}; + +class MaexxnaTankSpiderlingsAction : public AttackAction +{ +public: + MaexxnaTankSpiderlingsAction(PlayerbotAI* ai) : AttackAction(ai, "maexxna tank spiderlings") {} + + bool Execute(Event event) override; + bool isUseful() override; +}; + +// Gothik the Harvester +class GothikMoveToAssignedSideAction : public MovementAction +{ +public: + GothikMoveToAssignedSideAction(PlayerbotAI* ai) : MovementAction(ai, "gothik move to assigned side") {} + + bool Execute(Event event) override; + bool isUseful() override; +}; + +class GothikChooseTargetAction : public AttackAction +{ +public: + GothikChooseTargetAction(PlayerbotAI* ai) : AttackAction(ai, "gothik choose target") {} + + bool Execute(Event event) override; + bool isUseful() override; +}; + +#endif \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Anubrekhan.cpp b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Anubrekhan.cpp new file mode 100644 index 0000000000..1dd4356b42 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Anubrekhan.cpp @@ -0,0 +1,121 @@ +#include "RaidNaxxActions.h" + +#include "ObjectGuid.h" +#include "Playerbots.h" +#include "RaidNaxxSpellIds.h" + +bool AnubrekhanChooseTargetAction::Execute(Event event) +{ + GuidVector attackers = context->GetValue("attackers")->Get(); + Unit* target = nullptr; + Unit* targetBoss = nullptr; + std::vector cryptGuards; + std::vector corpseScarabs; + for (ObjectGuid const guid : attackers) + { + Unit* unit = botAI->GetUnit(guid); + if (!unit) + continue; + + if (botAI->EqualLowercaseName(unit->GetName(), "anub'rekhan")) + targetBoss = unit; + else if (botAI->EqualLowercaseName(unit->GetName(), "crypt guard")) + cryptGuards.push_back(unit); + else if (botAI->EqualLowercaseName(unit->GetName(), "corpse scarab")) + corpseScarabs.push_back(unit); + } + + if (!targetBoss && cryptGuards.empty() && corpseScarabs.empty()) + return false; + + if (botAI->IsMainTank(bot)) + { + target = targetBoss; + } + else if (botAI->IsAssistTank(bot)) + { + for (Unit* add : cryptGuards) + { + Player* victim = add->GetVictim() ? add->GetVictim()->ToPlayer() : nullptr; + if (!victim || !botAI->IsTank(victim)) + { + target = add; + break; + } + } + if (!target) + { + if (!cryptGuards.empty()) + target = cryptGuards.front(); + else + target = targetBoss; + } + } + else + { + if (!cryptGuards.empty()) + { + for (Unit* add : cryptGuards) + { + if (!target || target->GetHealthPct() > add->GetHealthPct()) + target = add; + } + } + else if (!corpseScarabs.empty()) + { + for (Unit* scarab : corpseScarabs) + { + Player* victim = scarab->GetVictim() ? scarab->GetVictim()->ToPlayer() : nullptr; + if (victim && !botAI->IsTank(victim)) + { + target = scarab; + break; + } + } + + if (!target) + target = corpseScarabs.front(); + } + else + { + target = targetBoss; + } + } + + if (!target) + return false; + + if (context->GetValue("current target")->Get() == target) + { + return false; + } + return Attack(target); +} + +bool AnubrekhanPositionAction::Execute(Event event) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "anub'rekhan"); + if (!boss) + { + return false; + } + + bool inPhase = NaxxSpellIds::HasAnyAura(botAI, boss, {NaxxSpellIds::LocustSwarm10, NaxxSpellIds::LocustSwarm10Alt, + NaxxSpellIds::LocustSwarm25}) || + botAI->HasAura("locust swarm", boss); + if (inPhase) + { + if (botAI->IsMainTank(bot)) + { + uint32 nearest = FindNearestWaypoint(); + uint32 nextPoint = (nearest + 1) % intervals; + return MoveTo(bot->GetMapId(), waypoints[nextPoint].first, waypoints[nextPoint].second, bot->GetPositionZ(), false, false, + false, false, MovementPriority::MOVEMENT_COMBAT); + } + else + { + return MoveInside(533, 3272.49f, -3476.27f, bot->GetPositionZ(), 3.0f, MovementPriority::MOVEMENT_COMBAT); + } + } + return false; +} \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Faerlina.cpp b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Faerlina.cpp new file mode 100644 index 0000000000..54d535d363 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Faerlina.cpp @@ -0,0 +1,107 @@ +#include "RaidNaxxActions.h" + +#include "RaidNaxxSpellIds.h" + +#include + +namespace +{ + constexpr uint32 NpcNaxxramasWorshipper = 16506; + constexpr uint32 NpcNaxxramasFollower = 16505; + constexpr float MaxAddDistanceToBoss = 60.0f; +} + +bool FaerlinaSacrificeWorshipperAction::Execute(Event event) +{ + return AttackAction::Execute(event); +} + +bool FaerlinaSacrificeWorshipperAction::isUseful() +{ + if (!bot->IsInCombat()) + { + return false; + } + + if (!botAI->IsAssistTankOfIndex(bot, 0)) + { + return false; + } + + Unit* boss = AI_VALUE2(Unit*, "find target", "grand widow faerlina"); + if (!boss) + { + return false; + } + + if (boss->HasAura(NaxxSpellIds::FaerlinaWidowsEmbrace)) + { + return false; + } + + if (!boss->HasAura(NaxxSpellIds::FaerlinaFrenzy)) + { + return false; + } + + return GetTarget() != nullptr; +} + +Unit* FaerlinaSacrificeWorshipperAction::GetTarget() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "grand widow faerlina"); + if (!boss) + { + return nullptr; + } + + Creature* bestWorshipper = nullptr; + float bestWorshipperDist = std::numeric_limits::max(); + + Creature* bestFollower = nullptr; + float bestFollowerDist = std::numeric_limits::max(); + + GuidVector const npcs = AI_VALUE(GuidVector, "nearest hostile npcs"); + for (ObjectGuid const guid : npcs) + { + Unit* unit = botAI->GetUnit(guid); + if (!unit || unit->isDead()) + { + continue; + } + + Creature* creature = unit->ToCreature(); + if (!creature) + { + continue; + } + + if (!creature->IsWithinDistInMap(boss, MaxAddDistanceToBoss)) + { + continue; + } + + uint32 const entry = creature->GetEntry(); + float const distToBoss = creature->GetDistance(boss); + + if (entry == NpcNaxxramasWorshipper) + { + if (distToBoss < bestWorshipperDist) + { + bestWorshipper = creature; + bestWorshipperDist = distToBoss; + } + } + else if (entry == NpcNaxxramasFollower) + { + if (distToBoss < bestFollowerDist) + { + bestFollower = creature; + bestFollowerDist = distToBoss; + } + } + } + + // Prefer worshippers for the intended mechanic. Followers are a fallback for clean-up. + return bestWorshipper ? static_cast(bestWorshipper) : static_cast(bestFollower); +} \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_FourHorseman.cpp b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_FourHorseman.cpp new file mode 100644 index 0000000000..0d29526fef --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_FourHorseman.cpp @@ -0,0 +1,70 @@ +#include "RaidNaxxActions.h" + +#include "Playerbots.h" + +bool HorsemanAttractAlternativelyAction::Execute(Event event) +{ + if (!helper.UpdateBossAI()) + { + return false; + } + helper.CalculatePosToGo(bot); + auto [posX, posY] = helper.CurrentAttractPos(); + if (MoveTo(bot->GetMapId(), posX, posY, helper.posZ, false, false, false, false, MovementPriority::MOVEMENT_COMBAT)) + { + return true; + } + Unit* attackTarget = helper.CurrentAttackTarget(); + if (context->GetValue("current target")->Get() != attackTarget) + { + return Attack(attackTarget); + } + return false; +} + +bool HorsemanAttactInOrderAction::Execute(Event event) +{ + if (!helper.UpdateBossAI()) + { + return false; + } + Unit* target = nullptr; + Unit* thane = AI_VALUE2(Unit*, "find target", "thane korth'azz"); + Unit* lady = AI_VALUE2(Unit*, "find target", "lady blaumeux"); + Unit* sir = AI_VALUE2(Unit*, "find target", "sir zeliek"); + Unit* fourth = AI_VALUE2(Unit*, "find target", "baron rivendare"); + if (!fourth) + { + fourth = AI_VALUE2(Unit*, "find target", "highlord mograine"); + } + std::vector attack_order; + if (botAI->IsAssistTank(bot)) + { + attack_order = {fourth, thane, lady, sir}; + } + else + { + attack_order = {thane, fourth, lady, sir}; + } + for (Unit* t : attack_order) + { + if (t && t->IsAlive()) + { + target = t; + break; + } + } + if (target) + { + if (context->GetValue("current target")->Get() == target && botAI->GetState() == BOT_STATE_COMBAT) + { + return false; + } + if (!bot->IsWithinLOSInMap(target)) + { + return MoveNear(target, 22.0f, MovementPriority::MOVEMENT_COMBAT); + } + return Attack(target); + } + return false; +} \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Gluth.cpp b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Gluth.cpp new file mode 100644 index 0000000000..7cf5f41308 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Gluth.cpp @@ -0,0 +1,206 @@ +#include "RaidNaxxActions.h" + +#include "PlayerbotAIConfig.h" +#include "Playerbots.h" +#include "SharedDefines.h" + +bool GluthChooseTargetAction::Execute(Event event) +{ + if (!helper.UpdateBossAI()) + { + return false; + } + GuidVector attackers = context->GetValue("possible targets")->Get(); + Unit* target = nullptr; + Unit* target_boss = nullptr; + std::vector target_zombies; + for (GuidVector::iterator i = attackers.begin(); i != attackers.end(); ++i) + { + Unit* unit = botAI->GetUnit(*i); + if (!unit) + continue; + if (!unit->IsAlive()) + { + continue; + } + if (botAI->EqualLowercaseName(unit->GetName(), "zombie chow")) + { + target_zombies.push_back(unit); + } + if (botAI->EqualLowercaseName(unit->GetName(), "gluth")) + { + target_boss = unit; + } + } + if (botAI->IsMainTank(bot) || botAI->IsAssistTankOfIndex(bot, 0)) + { + target = target_boss; + } + else if (botAI->IsAssistTankOfIndex(bot, 1)) + { + for (Unit* t : target_zombies) + { + if (t->GetHealthPct() > helper.decimatedZombiePct && t->GetVictim() != bot && t->GetDistance2d(bot) <= 10.0f) + { + if (!target || t->GetDistance2d(bot) < target->GetDistance2d(bot)) + { + target = t; + } + } + } + } + else if (botAI->GetClassIndex(bot, CLASS_HUNTER) == 0 || botAI->GetClassIndex(bot, CLASS_HUNTER) == 1) + { + // prevent zombie go straight to gluth + for (Unit* t : target_zombies) + { + if (t->GetHealthPct() > helper.decimatedZombiePct && t->GetVictim() == target_boss && + t->GetDistance2d(bot) <= sPlayerbotAIConfig.spellDistance) + { + if (!target || t->GetDistance2d(bot) < target->GetDistance2d(bot)) + { + target = t; + } + } + } + if (!target) + { + target = target_boss; + } + } + else + { + for (Unit* t : target_zombies) + { + if (t->GetHealthPct() <= helper.decimatedZombiePct) + { + if (target == nullptr || + target->GetDistance2d(helper.mainTankPos25.first, helper.mainTankPos25.second) > + t->GetDistance2d(helper.mainTankPos25.first, helper.mainTankPos25.second)) + { + target = t; + } + } + } + if (target == nullptr) + { + target = target_boss; + } + } + if (!target || context->GetValue("current target")->Get() == target) + { + return false; + } + if (target_boss && target == target_boss) + return Attack(target, true); + return Attack(target, false); + // return Attack(target); +} + +bool GluthPositionAction::Execute(Event event) +{ + if (!helper.UpdateBossAI()) + { + return false; + } + bool raid25 = bot->GetRaidDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL; + if (botAI->IsMainTank(bot) || botAI->IsAssistTankOfIndex(bot, 0)) + { + if (AI_VALUE2(bool, "has aggro", "boss target")) + { + if (raid25) + { + if (MoveTo(NAXX_MAP_ID, helper.mainTankPos25.first, helper.mainTankPos25.second, bot->GetPositionZ(), false, false, false, + false, MovementPriority::MOVEMENT_COMBAT)) + { + return true; + } + return MoveInside(NAXX_MAP_ID, helper.mainTankPos25.first, helper.mainTankPos25.second, bot->GetPositionZ(), 2.0f, + MovementPriority::MOVEMENT_COMBAT); + } + else + { + if (MoveTo(NAXX_MAP_ID, helper.mainTankPos10.first, helper.mainTankPos10.second, bot->GetPositionZ(), false, false, false, + false, MovementPriority::MOVEMENT_COMBAT)) + { + return true; + } + return MoveInside(NAXX_MAP_ID, helper.mainTankPos10.first, helper.mainTankPos10.second, bot->GetPositionZ(), 2.0f, + MovementPriority::MOVEMENT_COMBAT); + } + } + } + else if (botAI->IsAssistTankOfIndex(bot, 1)) + { + if (helper.BeforeDecimate()) + { + if (MoveTo(bot->GetMapId(), helper.beforeDecimatePos.first, helper.beforeDecimatePos.second, bot->GetPositionZ(), false, false, + false, false, MovementPriority::MOVEMENT_COMBAT)) + { + return true; + } + return MoveInside(bot->GetMapId(), helper.beforeDecimatePos.first, helper.beforeDecimatePos.second, bot->GetPositionZ(), 2.0f, + MovementPriority::MOVEMENT_COMBAT); + } + else + { + if (AI_VALUE2(bool, "has aggro", "current target")) + { + uint32 nearest = FindNearestWaypoint(); + uint32 next_point = (nearest + 1) % intervals; + return MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second, bot->GetPositionZ(), + false, false, false, false, MovementPriority::MOVEMENT_COMBAT); + } + } + } + else if (botAI->IsRangedDps(bot)) + { + if (raid25) + { + if (botAI->GetClassIndex(bot, CLASS_HUNTER) == 0) + { + return MoveInside(NAXX_MAP_ID, helper.leftSlowDownPos.first, helper.leftSlowDownPos.second, bot->GetPositionZ(), 0.0f, + MovementPriority::MOVEMENT_COMBAT); + } + if (botAI->GetClassIndex(bot, CLASS_HUNTER) == 1) + { + return MoveInside(NAXX_MAP_ID, helper.rightSlowDownPos.first, helper.rightSlowDownPos.second, bot->GetPositionZ(), 0.0f, + MovementPriority::MOVEMENT_COMBAT); + } + } + return MoveInside(NAXX_MAP_ID, helper.rangedPos.first, helper.rangedPos.second, bot->GetPositionZ(), 3.0f, + MovementPriority::MOVEMENT_COMBAT); + } + else if (botAI->IsHeal(bot)) + { + return MoveInside(NAXX_MAP_ID, helper.healPos.first, helper.healPos.second, bot->GetPositionZ(), 0.0f, + MovementPriority::MOVEMENT_COMBAT); + } + return false; +} + +bool GluthSlowdownAction::Execute(Event event) +{ + if (!helper.UpdateBossAI()) + { + return false; + } + bool raid25 = bot->GetRaidDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL; + if (!raid25) + { + return false; + } + if (helper.JustStartCombat()) + { + return false; + } + switch (bot->getClass()) + { + case CLASS_HUNTER: + return botAI->CastSpell("frost trap", bot); + break; + default: + break; + } + return false; +} \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Gothik.cpp b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Gothik.cpp new file mode 100644 index 0000000000..5f721a09d2 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Gothik.cpp @@ -0,0 +1,403 @@ +#include "RaidNaxxActions.h" + +#include +#include + +#include "Playerbots.h" +#include "RaidNaxxSpellIds.h" + +namespace +{ + constexpr float LiveX = 2691.2f; + constexpr float LiveY = -3387.0f; + constexpr float LiveZ = 267.68f; + + constexpr float DeadX = 2693.5f; + constexpr float DeadY = -3334.6f; + constexpr float DeadZ = 267.68f; + + constexpr char const* StratCoTank = "co tank"; + constexpr char const* StratTankFace = "tank face"; + constexpr char const* StratTankAssist = "tank assist"; + constexpr char const* StratHeal = "heal"; + + enum class GothikSide : uint8 + { + Live = 0, + Dead = 1 + }; + + inline bool IsLiveSide(Unit const* who) + { + return who && who->GetPositionY() < NaxxSpellIds::GothikGateY; + } + + inline bool IsGothikAdd(uint32 entry) + { + switch (entry) + { + case NaxxSpellIds::GothikLivingTraineeEntry: + case NaxxSpellIds::GothikLivingKnightEntry: + case NaxxSpellIds::GothikLivingRiderEntry: + case NaxxSpellIds::GothikDeadTraineeEntry: + case NaxxSpellIds::GothikDeadKnightEntry: + case NaxxSpellIds::GothikDeadHorseEntry: + case NaxxSpellIds::GothikDeadRiderEntry: + return true; + } + return false; + } + + inline uint32 GetAddPriority(uint32 entry) + { + switch (entry) + { + case NaxxSpellIds::GothikLivingRiderEntry: return 70; + case NaxxSpellIds::GothikLivingKnightEntry: return 60; + case NaxxSpellIds::GothikLivingTraineeEntry: return 50; + case NaxxSpellIds::GothikDeadRiderEntry: return 40; + case NaxxSpellIds::GothikDeadKnightEntry: return 30; + case NaxxSpellIds::GothikDeadHorseEntry: return 20; + case NaxxSpellIds::GothikDeadTraineeEntry: return 10; + } + return 0; + } + + static inline bool HasStrategyAnyState(Player* p, char const* name) + { + if (!p || !name) + return false; + if (PlayerbotAI* ai = GET_PLAYERBOT_AI(p)) + { + return ai->HasStrategy(name, BOT_STATE_NON_COMBAT) || + ai->HasStrategy(name, BOT_STATE_COMBAT); + } + return false; + } + + static inline bool IsTankRoleForGothik(PlayerbotAI* localAI, Player* p) + { + if (!p) + return false; + + if (p->HasTankSpec()) + return true; + + if (localAI && localAI->IsTank(p)) + return true; + + return HasStrategyAnyState(p, StratTankFace) || HasStrategyAnyState(p, StratTankAssist) || HasStrategyAnyState(p, "tank") || + HasStrategyAnyState(p, "bear"); + } + + static inline bool IsHealerRoleForGothik(PlayerbotAI* localAI, Player* p) + { + if (!p) + return false; + + if (localAI && localAI->IsHeal(p)) + return true; + + return HasStrategyAnyState(p, StratHeal) || HasStrategyAnyState(p, "holy heal") || HasStrategyAnyState(p, "offheal"); + } + + static inline bool IsMainTankByStrategies(Player* p) + { + return HasStrategyAnyState(p, StratTankFace); + } + + static inline bool IsOffTankByStrategies(Player* p) + { + return HasStrategyAnyState(p, StratTankAssist) && !HasStrategyAnyState(p, StratTankFace); + } + + GothikSide GetAssignedSide(PlayerbotAI* localAI, Player* bot) + { + if (!localAI || !bot) + return GothikSide::Live; + + Group* group = bot->GetGroup(); + if (!group) + return GothikSide::Live; + + std::vector members; + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + Player* m = ref->GetSource(); + if (m && m->IsAlive()) + members.push_back(m); + } + + if (members.empty()) + return GothikSide::Live; + + std::sort(members.begin(), members.end(), [](Player* a, Player* b) + { + return a->GetGUID() < b->GetGUID(); + }); + + std::vector tanks, heals, dps; + tanks.reserve(2); + heals.reserve(4); + dps.reserve(25); + + for (Player* m : members) + { + if (IsTankRoleForGothik(localAI, m)) + tanks.push_back(m); + else if (IsHealerRoleForGothik(localAI, m)) + heals.push_back(m); + else + dps.push_back(m); + } + + Player* mainTank = nullptr; + Player* offTank = nullptr; + + for (Player* t : tanks) + { + if (HasStrategyAnyState(t, StratCoTank) && HasStrategyAnyState(t, StratTankFace)) + { + mainTank = t; + break; + } + } + + if (!mainTank) + { + for (Player* t : tanks) + { + if (IsMainTankByStrategies(t)) + { + mainTank = t; + break; + } + } + } + + for (Player* t : tanks) + { + if (t != mainTank && IsOffTankByStrategies(t)) + { + offTank = t; + break; + } + } + + if (!mainTank) + { + for (Player* t : tanks) + { + if (HasStrategyAnyState(t, StratTankFace) && !HasStrategyAnyState(t, StratTankAssist)) + { + mainTank = t; + break; + } + } + } + + if (!mainTank && !tanks.empty()) + mainTank = tanks.front(); + + if (!offTank) + { + for (Player* t : tanks) + { + if (t != mainTank) + { + offTank = t; + break; + } + } + } + + std::unordered_map side; + side.reserve(members.size()); + + if (mainTank) + side[mainTank->GetGUID()] = GothikSide::Live; + if (offTank) + side[offTank->GetGUID()] = GothikSide::Dead; + + for (Player* t : tanks) + { + if (t == mainTank || t == offTank) + continue; + side[t->GetGUID()] = GothikSide::Dead; + } + + if (heals.size() == 1) + { + side[heals[0]->GetGUID()] = GothikSide::Live; + } + else if (heals.size() >= 2) + { + side[heals[0]->GetGUID()] = GothikSide::Live; + side[heals[1]->GetGUID()] = GothikSide::Dead; + + uint32 liveCount = 0, deadCount = 0; + for (Player* m : members) + { + auto it = side.find(m->GetGUID()); + GothikSide s = (it != side.end()) ? it->second : GothikSide::Live; + (s == GothikSide::Live ? liveCount : deadCount)++; + } + + for (size_t i = 2; i < heals.size(); ++i) + { + GothikSide s = (liveCount <= deadCount) ? GothikSide::Live : GothikSide::Dead; + side[heals[i]->GetGUID()] = s; + (s == GothikSide::Live ? liveCount : deadCount)++; + } + } + uint32 const minLiveDps = std::min(2u, uint32(dps.size())); + uint32 liveDps = 0; + for (Player* m : dps) + { + auto it = side.find(m->GetGUID()); + if (it != side.end() && it->second == GothikSide::Live) + ++liveDps; + } + for (Player* m : dps) + { + if (liveDps >= minLiveDps) + break; + + if (side.find(m->GetGUID()) != side.end()) + continue; + + side[m->GetGUID()] = GothikSide::Live; + ++liveDps; + } + uint32 liveCount = 0, deadCount = 0; + for (Player* m : members) + { + auto it = side.find(m->GetGUID()); + GothikSide s = (it != side.end()) ? it->second : GothikSide::Live; + (s == GothikSide::Live ? liveCount : deadCount)++; + } + + for (Player* m : dps) + { + if (side.find(m->GetGUID()) != side.end()) + continue; + + GothikSide s = (liveCount <= deadCount) ? GothikSide::Live : GothikSide::Dead; + side[m->GetGUID()] = s; + (s == GothikSide::Live ? liveCount : deadCount)++; + } + + auto it = side.find(bot->GetGUID()); + return (it != side.end()) ? it->second : GothikSide::Live; + } +} // namespace + +bool GothikMoveToAssignedSideAction::isUseful() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "gothik the harvester"); + if (!boss) + return false; + + if (bot->GetDistance(boss) > 160.0f) + return false; + + GothikSide assigned = GetAssignedSide(botAI, bot); + bool wantLive = (assigned == GothikSide::Live); + bool isLive = IsLiveSide(bot); + + if (wantLive != isLive) + return true; + + float ax = wantLive ? LiveX : DeadX; + float ay = wantLive ? LiveY : DeadY; + float az = wantLive ? LiveZ : DeadZ; + return bot->GetDistance(ax, ay, az) > 12.0f; +} + +bool GothikMoveToAssignedSideAction::Execute(Event /*event*/) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "gothik the harvester"); + if (!boss) + return false; + + GothikSide assigned = GetAssignedSide(botAI, bot); + bool wantLive = (assigned == GothikSide::Live); + + float ax = wantLive ? LiveX : DeadX; + float ay = wantLive ? LiveY : DeadY; + float az = wantLive ? LiveZ : DeadZ; + + if (MoveTo(NAXX_MAP_ID, ax, ay, az, false, false, false, false, MovementPriority::MOVEMENT_COMBAT)) + return true; + + return MoveInside(NAXX_MAP_ID, ax, ay, az, 3.0f, MovementPriority::MOVEMENT_COMBAT); +} + +bool GothikChooseTargetAction::isUseful() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "gothik the harvester"); + if (!boss) + return false; + + return boss->IsInCombat() || bot->IsInCombat(); +} + +bool GothikChooseTargetAction::Execute(Event /*event*/) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "gothik the harvester"); + if (!boss) + return false; + + bool myLiveSide = IsLiveSide(bot); + + Creature* gothik = boss->ToCreature(); + bool bossAttackable = false; + if (gothik && gothik->IsAlive()) + { + bossAttackable = (gothik->GetReactState() == REACT_AGGRESSIVE) && !gothik->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE); + } + + GuidVector candidates = context->GetValue("possible targets")->Get(); + + Unit* bestAdd = nullptr; + uint32 bestPrio = 0; + float bestDist = 0.0f; + + for (ObjectGuid const& guid : candidates) + { + Unit* unit = botAI->GetUnit(guid); + if (!unit || !unit->IsAlive()) + continue; + + if (!IsGothikAdd(unit->GetEntry())) + continue; + + if (IsLiveSide(unit) != myLiveSide) + continue; + + uint32 prio = GetAddPriority(unit->GetEntry()); + float dist = bot->GetDistance(unit); + + if (!bestAdd || prio > bestPrio || (prio == bestPrio && dist < bestDist)) + { + bestAdd = unit; + bestPrio = prio; + bestDist = dist; + } + } + + if (bestAdd) + { + if (AI_VALUE(Unit*, "current target") == bestAdd) + return false; + return Attack(bestAdd); + } + if (bossAttackable && IsLiveSide(boss) == myLiveSide) + { + if (AI_VALUE(Unit*, "current target") == boss) + return false; + return Attack(boss); + } + + return false; +} \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Grobbulus.cpp b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Grobbulus.cpp new file mode 100644 index 0000000000..34af48b782 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Grobbulus.cpp @@ -0,0 +1,52 @@ +#include "RaidNaxxActions.h" + +#include "Playerbots.h" + +bool GrobbulusGoBehindAction::Execute(Event event) +{ + Unit* boss = AI_VALUE(Unit*, "boss target"); + if (!boss) + { + return false; + } + // Position* pos = boss->GetPosition(); + float orientation = boss->GetOrientation() + M_PI + delta_angle; + float x = boss->GetPositionX(); + float y = boss->GetPositionY(); + float z = boss->GetPositionZ(); + float rx = x + cos(orientation) * distance; + float ry = y + sin(orientation) * distance; + return MoveTo(bot->GetMapId(), rx, ry, z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT); +} + +bool GrobbulusMoveAwayAction::Execute(Event event) +{ + Unit* boss = AI_VALUE(Unit*, "boss target"); + if (!boss) + { + return false; + } + + const float currentDistance = bot->GetExactDist2d(boss); + if (currentDistance >= distance) + { + return false; + } + + const float angle = boss->GetAngle(bot); + const float x = boss->GetPositionX() + cos(angle) * distance; + const float y = boss->GetPositionY() + sin(angle) * distance; + const float z = bot->GetPositionZ(); + + return MoveTo(bot->GetMapId(), x, y, z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT); +} + +uint32 GrobbulusRotateAction::GetCurrWaypoint() +{ + uint32 current = FindNearestWaypoint(); + if (clockwise) + { + return (current + 1) % intervals; + } + return (current + intervals - 1) % intervals; +} \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Heigan.cpp b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Heigan.cpp new file mode 100644 index 0000000000..b7c19f2559 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Heigan.cpp @@ -0,0 +1,76 @@ +#include "RaidNaxxActions.h" + +#include "Playerbots.h" +#include "RaidNaxxSpellIds.h" +#include "Spell.h" +#include "Timer.h" + +bool HeiganDanceAction::CalculateSafe() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "heigan the unclean"); + if (!boss) + { + return false; + } + uint32 now = getMSTime(); + platform_phase = boss->IsWithinDist2d(platform.first, platform.second, 10.0f); + if (last_eruption_ms != 0 && now - last_eruption_ms > 15000) + { + ResetSafe(); + } + if (boss->HasUnitState(UNIT_STATE_CASTING)) + { + Spell* spell = boss->GetCurrentSpell(CURRENT_GENERIC_SPELL); + if (!spell) + { + spell = boss->GetCurrentSpell(CURRENT_CHANNELED_SPELL); + } + if (spell) + { + SpellInfo const* info = spell->GetSpellInfo(); + bool isEruption = NaxxSpellIds::MatchesAnySpellId(info, {NaxxSpellIds::Eruption10}); + if (!isEruption && info && info->SpellName[LOCALE_enUS]) + { + // Fallback to name for custom spell data. + isEruption = botAI->EqualLowercaseName(info->SpellName[LOCALE_enUS], "eruption"); + } + if (isEruption) + { + if (last_eruption_ms == 0 || now - last_eruption_ms > 500) + { + NextSafe(); + } + last_eruption_ms = now; + } + } + } + return true; +} + +bool HeiganDanceMeleeAction::Execute(Event event) +{ + CalculateSafe(); + if (!platform_phase && botAI->IsMainTank(bot) && !AI_VALUE2(bool, "has aggro", "boss target")) + { + return false; + } + assert(curr_safe >= 0 && curr_safe <= 3); + return MoveInside(bot->GetMapId(), waypoints[curr_safe].first, waypoints[curr_safe].second, bot->GetPositionZ(), + botAI->IsMainTank(bot) ? 0 : 0, MovementPriority::MOVEMENT_COMBAT); +} + +bool HeiganDanceRangedAction::Execute(Event event) +{ + CalculateSafe(); + if (!platform_phase) + { + if (MoveTo(bot->GetMapId(), platform.first, platform.second, 276.54f, false, false, false, false, MovementPriority::MOVEMENT_COMBAT)) + { + return true; + } + return MoveInside(bot->GetMapId(), platform.first, platform.second, 276.54f, 2.0f, MovementPriority::MOVEMENT_COMBAT); + } + botAI->InterruptSpell(); + return MoveInside(bot->GetMapId(), waypoints[curr_safe].first, waypoints[curr_safe].second, bot->GetPositionZ(), 0, + MovementPriority::MOVEMENT_COMBAT); +} \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Kelthuzad.cpp b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Kelthuzad.cpp new file mode 100644 index 0000000000..a59798032c --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Kelthuzad.cpp @@ -0,0 +1,300 @@ +#include "RaidNaxxActions.h" + +#include +#include + +#include "PlayerbotAIConfig.h" +#include "Playerbots.h" + +bool KelthuzadChooseTargetAction::Execute(Event event) +{ + if (!helper.UpdateBossAI()) + { + return false; + } + GuidVector attackers = context->GetValue("possible targets")->Get(); + Unit* target = nullptr; + Unit *target_soldier = nullptr, *target_weaver = nullptr, *target_abomination = nullptr, *target_kelthuzad = nullptr, + *target_guardian = nullptr; + + bool isOffTankForKT = botAI->IsTank(bot) && !botAI->IsMainTank(bot) && + (botAI->IsAssistTank(bot) || botAI->HasStrategy("tank assist", BOT_STATE_COMBAT)); + + for (auto i = attackers.begin(); i != attackers.end(); ++i) + { + Unit* unit = botAI->GetUnit(*i); + if (!unit) + continue; + + if (unit->GetDistance2d(helper.center.first, helper.center.second) > 30.0f) + { + continue; + } + if (bot->GetDistance2d(unit) > sPlayerbotAIConfig.spellDistance) + { + continue; + } + if (botAI->EqualLowercaseName(unit->GetName(), "unstoppable abomination")) + { + if (target_abomination == nullptr || + target_abomination->GetDistance2d(helper.center.first, helper.center.second) > + unit->GetDistance2d(helper.center.first, helper.center.second)) + { + target_abomination = unit; + } + } + if (botAI->EqualLowercaseName(unit->GetName(), "soldier of the frozen wastes")) + { + if (target_soldier == nullptr || + target_soldier->GetDistance2d(helper.center.first, helper.center.second) > + unit->GetDistance2d(helper.center.first, helper.center.second)) + { + target_soldier = unit; + } + } + if (botAI->EqualLowercaseName(unit->GetName(), "soul weaver")) + { + if (target_weaver == nullptr || target_weaver->GetDistance2d(helper.center.first, helper.center.second) > + unit->GetDistance2d(helper.center.first, helper.center.second)) + { + target_weaver = unit; + } + } + if (botAI->EqualLowercaseName(unit->GetName(), "kel'thuzad")) + { + target_kelthuzad = unit; + } + } + + std::vector guardians = helper.GetGuardians(); + bool guardiansPresent = !guardians.empty(); + if (isOffTankForKT && guardiansPresent) + { + target_guardian = helper.GetGuardianToPickup(bot); + } + std::vector targets; + if (botAI->IsRanged(bot)) + { + bool hasRemainingP1Adds = (target_weaver || target_soldier || target_abomination); + + if (helper.IsPhaseTwo() && hasRemainingP1Adds && !botAI->IsHeal(bot)) + targets = {target_weaver, target_soldier, target_abomination, target_kelthuzad}; + else if (helper.IsPhaseTwo()) + targets = {target_kelthuzad, target_weaver, target_soldier, target_abomination}; + else + targets = {target_weaver, target_soldier, target_abomination, target_kelthuzad}; + } + else if (isOffTankForKT) + { + if (guardiansPresent) + targets = {target_guardian}; + else + targets = {target_abomination, target_kelthuzad}; + } + else + { + targets = {target_abomination, target_kelthuzad}; + } + for (Unit* t : targets) + { + if (!botAI->IsRanged(bot)) + { + float maxCenterDist = 20.0f; + + if (isOffTankForKT && guardiansPresent) + maxCenterDist = KelthuzadBossHelper::ROOM_MAX_RADIUS + 2.0f; + + if (t && t->GetDistance2d(helper.center.first, helper.center.second) > maxCenterDist) + { + continue; + } + } + if (t) + { + target = t; + break; + } + } + if (context->GetValue("current target")->Get() == target) + { + return false; + } + if (target_kelthuzad && target == target_kelthuzad) + { + return Attack(target, true); + } + return Attack(target, false); +} + +bool KelthuzadPositionAction::Execute(Event event) +{ + if (!helper.UpdateBossAI()) + { + return false; + } + + helper.RecallControlledPetsToBot(); + + if (helper.IsPhaseOne()) + { + if (botAI->IsTank(bot)) + { + float dx = helper.center.first; + float dy = helper.center.second; + + helper.ClampToRoom(dx, dy, + KelthuzadBossHelper::PHASE1_TANK_HOLD_RADIUS, + KelthuzadBossHelper::PHASE1_TANK_HOLD_RADIUS); + + if (bot->GetDistance2d(helper.center.first, helper.center.second) > KelthuzadBossHelper::PHASE1_TANK_MAX_RADIUS) + { + return MoveTo(NAXX_MAP_ID, dx, dy, bot->GetPositionZ(), false, false, false, false, + MovementPriority::MOVEMENT_COMBAT); + } + + Unit* currentTarget = AI_VALUE(Unit*, "current target"); + if (currentTarget && + currentTarget->GetDistance2d(helper.center.first, helper.center.second) <= KelthuzadBossHelper::PHASE1_TANK_MAX_RADIUS) + { + if (bot->GetDistance2d(currentTarget) > 3.0f) + return MoveNear(currentTarget, 3.0f, MovementPriority::MOVEMENT_COMBAT); + } + + return false; + } + if (bot->GetDistance2d(helper.center.first, helper.center.second) > 20.0f) + { + return MoveInside(NAXX_MAP_ID, helper.center.first, helper.center.second, bot->GetPositionZ(), 3.0f, + MovementPriority::MOVEMENT_COMBAT); + } + if (!botAI->IsRanged(bot)) + { + Unit* currentTarget = AI_VALUE(Unit*, "current target"); + if (currentTarget && + currentTarget->GetDistance2d(helper.center.first, helper.center.second) <= 20.0f && + bot->GetDistance2d(currentTarget) > 3.0f) + { + return MoveNear(currentTarget, 3.0f, MovementPriority::MOVEMENT_COMBAT); + } + } + if (AI_VALUE(Unit*, "current target") == nullptr) + { + return MoveInside(NAXX_MAP_ID, helper.center.first, helper.center.second, bot->GetPositionZ(), 3.0f, + MovementPriority::MOVEMENT_COMBAT); + } + } + else if (helper.IsPhaseTwo()) + { + if (helper.HasDetonateMana(bot)) + { + float angle = helper.center.first == bot->GetPositionX() && helper.center.second == bot->GetPositionY() + ? 0.0f + : bot->GetAngle(helper.center.first, helper.center.second) + M_PI; + float currentDist = bot->GetDistance2d(helper.center.first, helper.center.second); + float spreadDistance = std::clamp(currentDist + 12.0f, + KelthuzadBossHelper::DETONATE_MIN_RADIUS, + KelthuzadBossHelper::DETONATE_MAX_RADIUS); + float dx = helper.center.first + std::cos(angle) * spreadDistance; + float dy = helper.center.second + std::sin(angle) * spreadDistance; + helper.ClampToRoom(dx, dy, KelthuzadBossHelper::DETONATE_MIN_RADIUS, KelthuzadBossHelper::DETONATE_MAX_RADIUS); + return MoveTo(NAXX_MAP_ID, dx, dy, bot->GetPositionZ(), false, false, false, false, + MovementPriority::MOVEMENT_COMBAT); + } + if (helper.HasChains(bot)) + { + bot->AttackStop(); + return false; + } + Player* frostBlastTarget = helper.GetPlayerWithAura(NaxxSpellIds::FrostBlast); + if (frostBlastTarget && frostBlastTarget != bot && bot->GetDistance2d(frostBlastTarget) <= 8.0f) + { + float angle = frostBlastTarget->GetAngle(bot); + float dx = frostBlastTarget->GetPositionX() + cos(angle) * 8.0f; + float dy = frostBlastTarget->GetPositionY() + sin(angle) * 8.0f; + helper.ClampToRoom(dx, dy); + return MoveTo(NAXX_MAP_ID, dx, dy, bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT); + } + Unit* shadow_fissure = helper.GetAnyShadowFissure(); + if (!shadow_fissure || !bot->IsWithinDistInMap(shadow_fissure, 10.0f)) + { + bool isOffTankForKT = botAI->IsTank(bot) && !botAI->IsMainTank(bot) && + (botAI->IsAssistTank(bot) || botAI->HasStrategy("tank assist", BOT_STATE_COMBAT)); + + if (botAI->IsMainTank(bot)) + { + if (AI_VALUE2(bool, "has aggro", "current target")) + { + auto hold = helper.GetMainTankHoldPosition(); + return MoveTo(NAXX_MAP_ID, hold.first, hold.second, bot->GetPositionZ(), false, false, false, false, + MovementPriority::MOVEMENT_COMBAT); + } + else + { + return false; + } + } + else if (botAI->IsRanged(bot)) + { + float dx, dy; + uint32 index = botAI->GetRangedIndex(bot); + uint32 total = std::max(1, helper.GetRangedCount()); + helper.ComputeRangedSpreadPosition(index, total, dx, dy); + if (bot->GetDistance2d(dx, dy) <= 2.0f) + { + return false; + } + return MoveTo(NAXX_MAP_ID, dx, dy, bot->GetPositionZ(), false, false, false, false, + MovementPriority::MOVEMENT_COMBAT); + } + else if (botAI->IsTank(bot)) + { + if (isOffTankForKT) + { + std::vector guardians = helper.GetGuardians(); + if (!guardians.empty()) + { + Unit* pickup = helper.GetGuardianToPickup(bot); + if (pickup && pickup->GetVictim() != bot) + { + if (bot->GetDistance2d(pickup) > 6.0f) + { + return MoveNear(pickup, 4.0f, MovementPriority::MOVEMENT_COMBAT); + } + return false; + } + if (helper.AllGuardiansOnAssistTank(bot)) + { + auto hold = helper.GetAssistTankHoldPosition(); + if (bot->GetDistance2d(hold.first, hold.second) > 3.0f) + { + return MoveTo(NAXX_MAP_ID, hold.first, hold.second, bot->GetPositionZ(), false, false, false, false, + MovementPriority::MOVEMENT_COMBAT); + } + } + return false; + } + } + + return false; + } + } + else + { + float dx, dy; + float angle; + if (!botAI->IsRanged(bot)) + { + angle = shadow_fissure->GetAngle(helper.center.first, helper.center.second); + } + else + { + angle = bot->GetAngle(shadow_fissure) + M_PI; + } + dx = shadow_fissure->GetPositionX() + cos(angle) * 10.0f; + dy = shadow_fissure->GetPositionY() + sin(angle) * 10.0f; + helper.ClampToRoom(dx, dy); + return MoveTo(NAXX_MAP_ID, dx, dy, bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT); + } + } + return false; +} \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Loatheb.cpp b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Loatheb.cpp new file mode 100644 index 0000000000..58cbf93534 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Loatheb.cpp @@ -0,0 +1,499 @@ +#include "RaidNaxxActions.h" + +#include "Item.h" +#include "Playerbots.h" +#include "PlayerbotAI.h" + +#include + +namespace +{ +constexpr float kTankZ = 273.5857f; +constexpr float kMeleeBehindDistance = 3.0f; +constexpr float kCasterBehindDistance = 12.0f; +constexpr float kCasterSideOffset = 6.0f; +constexpr float kHealerBehindDistance = 18.0f; +constexpr float kSporeOnHealerRadius = 10.0f; +constexpr float kSporeCleanupMaxRange = 35.0f; // keep it strictly "no chase" +constexpr float kSporeRunnerNearRange = 15.0f; // if runner is already near, don't steal the job + +uint8 GetCasterSideIndex(Player* bot) +{ + if (Group* group = bot->GetGroup()) + { + return bot->GetSubGroup() % 2; + } + return 0; +} + +ObjectGuid SelectRangedDpsLeaderForSide(Player* bot, PlayerbotAI* botAI, uint8 sideIndex) +{ + if (!botAI) + return ObjectGuid::Empty; + + Group* group = bot->GetGroup(); + if (!group) + return ObjectGuid::Empty; + + ObjectGuid selected = ObjectGuid::Empty; + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + Player* member = ref->GetSource(); + if (!member || !member->IsAlive()) + continue; + + if (member->GetSubGroup() % 2 != sideIndex) + continue; + + if (bot->GetGUID() != member->GetGUID() && bot->GetMapId() != member->GetMapId()) + continue; + + if (!botAI->IsRanged(member) || botAI->IsHeal(member)) + continue; + + if (selected.IsEmpty() || member->GetGUID() < selected) + selected = member->GetGUID(); + } + + return selected; +} + +float GetSideSign(uint8 sideIndex) +{ + return sideIndex == 0 ? -1.0f : 1.0f; +} + +void GetBossBehindPosition(Unit* boss, float distance, float& outX, float& outY, float& outZ) +{ + float orientation = boss->GetOrientation(); + float dirX = -std::cos(orientation); + float dirY = -std::sin(orientation); + outX = boss->GetPositionX() + dirX * distance; + outY = boss->GetPositionY() + dirY * distance; + outZ = boss->GetPositionZ(); +} + +void GetCasterGroupPosition(Unit* boss, uint8 sideIndex, float& outX, float& outY, float& outZ) +{ + float orientation = boss->GetOrientation(); + float backX = -std::cos(orientation); + float backY = -std::sin(orientation); + float rightX = -backY; + float rightY = backX; + float sideSign = GetSideSign(sideIndex); + outX = boss->GetPositionX() + backX * kCasterBehindDistance + rightX * kCasterSideOffset * sideSign; + outY = boss->GetPositionY() + backY * kCasterBehindDistance + rightY * kCasterSideOffset * sideSign; + outZ = boss->GetPositionZ(); +} + +float GetDistance2d(float x1, float y1, float x2, float y2) +{ + float dx = x1 - x2; + float dy = y1 - y2; + return std::sqrt(dx * dx + dy * dy); +} + +void GetHealerPosition(Unit* boss, float& outX, float& outY, float& outZ) +{ + GetBossBehindPosition(boss, kHealerBehindDistance, outX, outY, outZ); +} + +uint8 GetSporeSideIndex(Unit* boss, Unit* spore) +{ + float orientation = boss->GetOrientation(); + float backX = -std::cos(orientation); + float backY = -std::sin(orientation); + float rightX = -backY; + float rightY = backX; + float dx = spore->GetPositionX() - boss->GetPositionX(); + float dy = spore->GetPositionY() - boss->GetPositionY(); + float side = dx * rightX + dy * rightY; + return side < 0.0f ? 0 : 1; +} + +uint8 GetCasterCountForSide(Player* bot, PlayerbotAI* botAI, uint8 sideIndex) +{ + if (!botAI) + { + return 0; + } + Group* group = bot->GetGroup(); + if (!group) + { + return 0; + } + uint8 count = 0; + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + Player* member = ref->GetSource(); + if (!member || !member->IsAlive()) + { + continue; + } + if (member->GetSubGroup() % 2 != sideIndex) + { + continue; + } + if (bot->GetGUID() != member->GetGUID() && bot->GetMapId() != member->GetMapId()) + { + continue; + } + if (!botAI->IsRanged(member) || botAI->IsHeal(member)) + { + continue; + } + ++count; + } + return count; +} + +bool IsSporeRunner(Player* bot, PlayerbotAI* botAI, uint8 sideIndex) +{ + if (!botAI) + { + return false; + } + Group* group = bot->GetGroup(); + if (!group) + { + return false; + } + ObjectGuid selected = SelectRangedDpsLeaderForSide(bot, botAI, sideIndex); + return !selected.IsEmpty() && bot->GetGUID() == selected; +} + +bool IsSporeInHealerPack(Player* bot, PlayerbotAI* botAI, Unit* spore) +{ + if (!botAI || !spore) + return false; + + Group* group = bot->GetGroup(); + if (!group) + return false; + + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + Player* member = ref->GetSource(); + if (!member || !member->IsAlive()) + continue; + + if (bot->GetGUID() != member->GetGUID() && bot->GetMapId() != member->GetMapId()) + continue; + + if (!botAI->IsHeal(member)) + continue; + + if (member->GetDistance(spore) <= kSporeOnHealerRadius) + return true; + } + + return false; +} + +bool HasWandEquipped(Player* bot) +{ + if (!bot) + return false; + + Item* const ranged = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED); + if (!ranged || !ranged->GetTemplate()) + return false; + + return ranged->GetTemplate()->SubClass == ITEM_SUBCLASS_WEAPON_WAND; +} + +ObjectGuid SelectSporeCleanupCaster(Player* bot, PlayerbotAI* botAI, Unit* spore, ObjectGuid sporeRunnerGuid) +{ + if (!botAI || !spore) + return ObjectGuid::Empty; + + Group* group = bot->GetGroup(); + if (!group) + return ObjectGuid::Empty; + + ObjectGuid selected = ObjectGuid::Empty; + float bestDist = 0.0f; + + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + Player* member = ref->GetSource(); + if (!member || !member->IsAlive()) + continue; + + if (member->GetGUID() == sporeRunnerGuid) + continue; + + if (bot->GetGUID() != member->GetGUID() && bot->GetMapId() != member->GetMapId()) + continue; + + // We want a true caster cleanup (no healers, no hunters), and no movement commitment. + if (!botAI->IsCaster(member) || botAI->IsHeal(member) || member->getClass() == CLASS_HUNTER) + continue; + + float const dist = member->GetDistance(spore); + if (dist > kSporeCleanupMaxRange) + continue; + + // Pick the nearest eligible caster (stable tie-breaker by GUID). + if (selected.IsEmpty() || dist < bestDist || (std::abs(dist - bestDist) < 0.001f && member->GetGUID() < selected)) + { + selected = member->GetGUID(); + bestDist = dist; + } + } + + return selected; +} + +void DoSafeInstantRangedHit(PlayerbotAI* botAI, Player* bot, Unit* target) +{ + if (!botAI || !bot || !target) + return; + + // Prefer wand "shoot" if available: lowest commitment. + if (HasWandEquipped(bot)) + { + botAI->DoSpecificAction("shoot", Event(), true); + return; + } + + // Otherwise, use a single instant ranged spell that is generally safe and low-commitment. + switch (bot->getClass()) + { + case CLASS_WARLOCK: + botAI->DoSpecificAction("corruption", Event(), true); + break; + case CLASS_PRIEST: + botAI->DoSpecificAction("shadow word: pain", Event(), true); + break; + case CLASS_DRUID: + botAI->DoSpecificAction("moonfire", Event(), true); + break; + case CLASS_SHAMAN: + botAI->DoSpecificAction("flame shock", Event(), true); + break; + case CLASS_MAGE: + botAI->DoSpecificAction("fire blast", Event(), true); + break; + default: + // Fallback: if we are considered a caster but we don't have a known instant here, do nothing. + break; + } +} +} // namespace + +bool LoathebPositionAction::Execute(Event event) +{ + if (!helper.UpdateBossAI()) + { + return false; + } + Unit* boss = helper.GetBoss(); + if (!boss) + { + return false; + } + if (botAI->IsTank(bot)) + { + if (AI_VALUE2(bool, "has aggro", "boss target")) + { + return MoveTo(533, helper.mainTankPos.first, helper.mainTankPos.second, kTankZ, false, false, false, false, + MovementPriority::MOVEMENT_COMBAT); + } + } + else + { + float targetX = 0.0f; + float targetY = 0.0f; + float targetZ = boss->GetPositionZ(); + + if (botAI->IsHeal(bot)) + { + GetHealerPosition(boss, targetX, targetY, targetZ); + } + else if (botAI->IsMelee(bot)) + { + GetBossBehindPosition(boss, kMeleeBehindDistance, targetX, targetY, targetZ); + } + else + { + uint8 sideIndex = GetCasterSideIndex(bot); + uint8 otherSideIndex = sideIndex == 0 ? 1 : 0; + bool hasOtherSideCasters = GetCasterCountForSide(bot, botAI, otherSideIndex) > 0; + bool isSporeRunner = IsSporeRunner(bot, botAI, sideIndex); + Unit* sporeTarget = nullptr; + if (isSporeRunner) + { + GuidVector attackers = context->GetValue("attackers")->Get(); + for (ObjectGuid const& guid : attackers) + { + Unit* unit = botAI->GetUnit(guid); + if (!unit || !unit->IsAlive()) + { + continue; + } + if (botAI->EqualLowercaseName(unit->GetName(), "spore") && + (!hasOtherSideCasters || GetSporeSideIndex(boss, unit) == sideIndex)) + { + if (!sporeTarget || bot->GetDistance(unit) < bot->GetDistance(sporeTarget)) + { + sporeTarget = unit; + } + } + } + } + + if (sporeTarget) + { + GetCasterGroupPosition(boss, sideIndex, targetX, targetY, targetZ); + float groupDistance = GetDistance2d(targetX, targetY, sporeTarget->GetPositionX(), sporeTarget->GetPositionY()); + if (groupDistance > 6.0f && bot->GetDistance(sporeTarget) > 5.0f) + { + targetX = sporeTarget->GetPositionX(); + targetY = sporeTarget->GetPositionY(); + targetZ = sporeTarget->GetPositionZ(); + } + } + else + { + GetCasterGroupPosition(boss, sideIndex, targetX, targetY, targetZ); + } + } + + return MoveInside(bot->GetMapId(), targetX, targetY, targetZ, 1.5f, MovementPriority::MOVEMENT_COMBAT); + } + return false; +} + +bool LoathebChooseTargetAction::Execute(Event event) +{ + if (!helper.UpdateBossAI()) + { + return false; + } + Unit* boss = helper.GetBoss(); + if (!boss) + { + return false; + } + GuidVector attackers = context->GetValue("attackers")->Get(); + Unit* target = nullptr; + Unit* target_boss = nullptr; + Unit* target_spore = nullptr; + Unit* target_spore_any = nullptr; + bool isSporeRunner = false; + uint8 sideIndex = GetCasterSideIndex(bot); + uint8 otherSideIndex = sideIndex == 0 ? 1 : 0; + bool hasOtherSideCasters = false; + if (botAI->IsRanged(bot) && !botAI->IsHeal(bot)) + { + hasOtherSideCasters = GetCasterCountForSide(bot, botAI, otherSideIndex) > 0; + isSporeRunner = IsSporeRunner(bot, botAI, sideIndex); + } + for (auto i = attackers.begin(); i != attackers.end(); ++i) + { + Unit* unit = botAI->GetUnit(*i); + if (!unit) + continue; + if (!unit->IsAlive()) + { + continue; + } + if (botAI->EqualLowercaseName(unit->GetName(), "spore")) + { + // Track a consistent spore reference for everyone (closest to boss). + if (!target_spore_any || boss->GetDistance(unit) < boss->GetDistance(target_spore_any)) + target_spore_any = unit; + + if (isSporeRunner) + { + uint8 sporeSide = GetSporeSideIndex(boss, unit); + if (!hasOtherSideCasters || sporeSide == sideIndex) + { + if (!target_spore || bot->GetDistance(unit) < bot->GetDistance(target_spore)) + { + target_spore = unit; + } + } + } + } + if (botAI->EqualLowercaseName(unit->GetName(), "loatheb")) + { + target_boss = unit; + } + } + + // --- Spore cleanup: if a spore sticks on the healer pack and the spore-runner isn't close, assign ONE caster to "tap" it safely. --- + if (target_spore_any && target_boss && IsSporeInHealerPack(bot, botAI, target_spore_any)) + { + // Identify the spore runner for the spore's side (if any). + uint8 const sporeSide = GetSporeSideIndex(boss, target_spore_any); + ObjectGuid const sporeRunnerGuid = SelectRangedDpsLeaderForSide(bot, botAI, sporeSide); + Player* sporeRunner = nullptr; + if (!sporeRunnerGuid.IsEmpty()) + { + if (Group* group = bot->GetGroup()) + { + sporeRunner = ObjectAccessor::FindPlayer(sporeRunnerGuid); + if (sporeRunner && (bot->GetGUID() != sporeRunner->GetGUID() && bot->GetMapId() != sporeRunner->GetMapId())) + sporeRunner = nullptr; + } + } + + bool const runnerIsNear = (sporeRunner && sporeRunner->IsAlive() && sporeRunner->GetDistance(target_spore_any) <= kSporeRunnerNearRange); + if (!runnerIsNear) + { + ObjectGuid const cleanupGuid = SelectSporeCleanupCaster(bot, botAI, target_spore_any, sporeRunnerGuid); + if (!cleanupGuid.IsEmpty() && bot->GetGUID() == cleanupGuid) + { + // No chase: only do it if we're already in a safe ranged window and LoS. + if (bot->IsWithinDistInMap(target_spore_any, kSporeCleanupMaxRange) && bot->IsWithinLOSInMap(target_spore_any)) + { + // Temporarily switch target -> apply ONE instant ranged hit -> immediately go back to boss. + Attack(target_spore_any); + DoSafeInstantRangedHit(botAI, bot, target_spore_any); + Attack(target_boss); + return true; + } + } + } + } + + if (target_spore) + { + target = target_spore; + } + else + { + target = target_boss; + } + + if (!target) + return false; + + // Spore runner: keep a "light" ranged attack running to reliably secure spore aggro. + // This is intentionally re-tried even if target didn't change (e.g. while moving into range/LoS). + if (target_spore && isSporeRunner && target == target_spore) + { + if (bot->getClass() == CLASS_HUNTER) + botAI->DoSpecificAction("auto shot", Event(), true); + else if (botAI->IsCaster(bot) && HasWandEquipped(bot)) + botAI->DoSpecificAction("shoot", Event(), true); + } + + if (context->GetValue("current target")->Get() == target) + return false; + + bool attacked = Attack(target); + + // Re-try after target switch so the spore runner starts the ranged attack immediately. + if (target_spore && isSporeRunner && target == target_spore) + { + if (bot->getClass() == CLASS_HUNTER) + botAI->DoSpecificAction("auto shot", Event(), true); + else if (botAI->IsCaster(bot) && HasWandEquipped(bot)) + botAI->DoSpecificAction("shoot", Event(), true); + } + + return attacked; +} \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Maexxna.cpp b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Maexxna.cpp new file mode 100644 index 0000000000..209e33a636 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Maexxna.cpp @@ -0,0 +1,84 @@ +#include + +#include "Playerbots.h" +#include "RaidNaxxActions.h" +#include "RaidNaxxSpellIds.h" + +bool MaexxnaAttackWebWrapAction::isUseful() +{ + // Prefer ranged DPS/casters for cocoon breaking to minimize movement and boss downtime. + if (botAI->IsHeal(bot) || botAI->IsTank(bot)) + return false; + + return botAI->IsRanged(bot); +} + +bool MaexxnaAttackWebWrapAction::Execute(Event /*event*/) +{ + Unit* best = nullptr; + float bestDist = std::numeric_limits::max(); + + GuidVector targets = AI_VALUE(GuidVector, "possible targets no los"); + for (ObjectGuid const& guid : targets) + { + Unit* unit = botAI->GetUnit(guid); + if (!unit) + continue; + + if (unit->GetEntry() != NaxxSpellIds::MaexxnaWebWrapEntry) + continue; + + float d = bot->GetDistance(unit); + if (!best || d < bestDist) + { + best = unit; + bestDist = d; + } + } + + if (!best) + return false; + + if (AI_VALUE(Unit*, "current target") == best) + return false; + + return Attack(best); +} + +bool MaexxnaTankSpiderlingsAction::isUseful() +{ + // Keep main tank on Maexxna; use this only for an off-tank (25-man typical). + return botAI->IsTank(bot) && !botAI->IsMainTank(bot); +} + +bool MaexxnaTankSpiderlingsAction::Execute(Event /*event*/) +{ + Unit* best = nullptr; + float bestDist = std::numeric_limits::max(); + + GuidVector attackers = AI_VALUE(GuidVector, "attackers"); + for (ObjectGuid const& guid : attackers) + { + Unit* unit = botAI->GetUnit(guid); + if (!unit) + continue; + + if (unit->GetEntry() != NaxxSpellIds::MaexxnaSpiderlingEntry) + continue; + + float d = bot->GetDistance(unit); + if (!best || d < bestDist) + { + best = unit; + bestDist = d; + } + } + + if (!best) + return false; + + if (AI_VALUE(Unit*, "current target") == best) + return false; + + return Attack(best); +} \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Noth.cpp b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Noth.cpp new file mode 100644 index 0000000000..af33e4f602 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Noth.cpp @@ -0,0 +1,217 @@ +#include "RaidNaxxActions.h" + +#include "PlayerbotAIConfig.h" +#include "Playerbots.h" +#include "RaidNaxxBossHelper.h" +#include "RaidNaxxSpellIds.h" + +bool NothChooseTargetAction::Execute(Event event) +{ + if (!helper.UpdateBossAI()) + { + return false; + } + + GuidVector attackers = context->GetValue("attackers")->Get(); + Unit* target = nullptr; + Unit* target_boss = nullptr; + Unit* target_champion = nullptr; + Unit* target_guardian = nullptr; + Unit* target_warrior = nullptr; + + for (auto i = attackers.begin(); i != attackers.end(); ++i) + { + Unit* unit = botAI->GetUnit(*i); + if (!unit || !unit->IsAlive()) + { + continue; + } + + if (botAI->EqualLowercaseName(unit->GetName(), "noth the plaguebringer")) + { + target_boss = unit; + } + else if (botAI->EqualLowercaseName(unit->GetName(), "plagued champion")) + { + if (!target_champion || bot->GetDistance2d(unit) < bot->GetDistance2d(target_champion)) + { + target_champion = unit; + } + } + else if (botAI->EqualLowercaseName(unit->GetName(), "plagued guardian")) + { + if (!target_guardian || bot->GetDistance2d(unit) < bot->GetDistance2d(target_guardian)) + { + target_guardian = unit; + } + } + else if (botAI->EqualLowercaseName(unit->GetName(), "plagued warrior")) + { + if (!target_warrior || bot->GetDistance2d(unit) < bot->GetDistance2d(target_warrior)) + { + target_warrior = unit; + } + } + } + + std::vector targets; + if (botAI->IsAssistTank(bot)) + { + Unit* warrior_needs_pickup = nullptr; + for (auto i = attackers.begin(); i != attackers.end(); ++i) + { + Unit* unit = botAI->GetUnit(*i); + if (!unit || !unit->IsAlive()) + { + continue; + } + if (!botAI->EqualLowercaseName(unit->GetName(), "plagued warrior")) + { + continue; + } + if (unit->GetVictim() && unit->GetVictim()->ToPlayer() && + !botAI->IsAssistTank(unit->GetVictim()->ToPlayer())) + { + warrior_needs_pickup = unit; + break; + } + } + if (helper.IsBalconyPhase()) + { + targets = {warrior_needs_pickup, target_warrior, target_champion, target_guardian}; + } + else + { + targets = {warrior_needs_pickup, target_warrior, target_boss}; + } + } + else if (helper.IsBalconyPhase()) + { + targets = {target_champion, target_guardian, target_warrior}; + } + else + { + targets = {target_boss}; + } + + for (Unit* t : targets) + { + if (t) + { + target = t; + break; + } + } + + if (!target || context->GetValue("current target")->Get() == target) + { + return false; + } + + return Attack(target); +} + +bool NothPositionAction::Execute(Event event) +{ + if (!helper.UpdateBossAI()) + { + return false; + } + + if (botAI->IsAssistTank(bot)) + { + GuidVector attackers = context->GetValue("attackers")->Get(); + Unit* loose_warrior = nullptr; + for (auto i = attackers.begin(); i != attackers.end(); ++i) + { + Unit* unit = botAI->GetUnit(*i); + if (!unit || !unit->IsAlive()) + { + continue; + } + if (!botAI->EqualLowercaseName(unit->GetName(), "plagued warrior")) + { + continue; + } + if (unit->GetVictim() && unit->GetVictim()->ToPlayer() && + !botAI->IsAssistTank(unit->GetVictim()->ToPlayer())) + { + loose_warrior = unit; + break; + } + } + if (loose_warrior && bot->GetDistance2d(loose_warrior) > 5.0f) + { + return MoveTo(NAXX_MAP_ID, loose_warrior->GetPositionX(), loose_warrior->GetPositionY(), + loose_warrior->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT); + } + Unit* currentTarget = AI_VALUE(Unit*, "current target"); + if (currentTarget && botAI->EqualLowercaseName(currentTarget->GetName(), "plagued warrior")) + { + GuidVector friendlyPlayers = AI_VALUE(GuidVector, "nearest friendly players"); + Unit* closestPlayer = nullptr; + float closestDistance = 0.0f; + for (ObjectGuid const& guid : friendlyPlayers) + { + Unit* member = botAI->GetUnit(guid); + if (!member || member == bot) + { + continue; + } + float distance = bot->GetDistance2d(member); + if (distance <= 5.0f && (!closestPlayer || distance < closestDistance)) + { + closestPlayer = member; + closestDistance = distance; + } + } + if (closestPlayer) + { + float angle = closestPlayer->GetAngle(bot); + float dx = closestPlayer->GetPositionX() + cos(angle) * 5.0f; + float dy = closestPlayer->GetPositionY() + sin(angle) * 5.0f; + return MoveTo(NAXX_MAP_ID, dx, dy, bot->GetPositionZ(), false, false, false, false, + MovementPriority::MOVEMENT_COMBAT); + } + } + return false; + } + + if (!helper.IsBalconyPhase() || !botAI->IsRanged(bot)) + { + return false; + } + + GuidVector attackers = context->GetValue("attackers")->Get(); + Unit* nearest_champion = nullptr; + float nearest_distance = 0.0f; + + for (auto i = attackers.begin(); i != attackers.end(); ++i) + { + Unit* unit = botAI->GetUnit(*i); + if (!unit || !unit->IsAlive()) + { + continue; + } + if (!botAI->EqualLowercaseName(unit->GetName(), "plagued champion")) + { + continue; + } + float distance = bot->GetDistance2d(unit); + if (!nearest_champion || distance < nearest_distance) + { + nearest_champion = unit; + nearest_distance = distance; + } + } + + if (nearest_champion && nearest_distance < 25.0f) + { + float angle = nearest_champion->GetAngle(bot); + float dx = nearest_champion->GetPositionX() + cos(angle) * 25.0f; + float dy = nearest_champion->GetPositionY() + sin(angle) * 25.0f; + return MoveTo(NAXX_MAP_ID, dx, dy, bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT); + } + + return false; +} \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Patchwerk.cpp b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Patchwerk.cpp new file mode 100644 index 0000000000..6ef1480cf2 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Patchwerk.cpp @@ -0,0 +1,31 @@ +#include "RaidNaxxActions.h" + +#include +#include + +bool PatchwerkRangedPositionAction::Execute(Event event) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "patchwerk"); + if (!boss) + return false; + + constexpr float minDistance = 12.0f; + constexpr float maxDistance = 15.0f; + const float distance = bot->GetExactDist2d(boss); + + if (distance >= minDistance && distance <= maxDistance) + return false; + + const float desiredDistance = std::clamp(distance, minDistance, maxDistance); + float angle = boss->GetAngle(bot); + + if (distance < 0.1f) + angle = boss->GetOrientation(); + + const float x = boss->GetPositionX() + std::cos(angle) * desiredDistance; + const float y = boss->GetPositionY() + std::sin(angle) * desiredDistance; + const float z = bot->GetPositionZ(); + + return MoveTo(boss->GetMapId(), x, y, z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, + false); +} \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Razuvious.cpp b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Razuvious.cpp new file mode 100644 index 0000000000..276545bce0 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Razuvious.cpp @@ -0,0 +1,166 @@ +#include "RaidNaxxActions.h" + +#include "ObjectGuid.h" +#include "PlayerbotAIConfig.h" +#include "Playerbots.h" +#include "SharedDefines.h" + +bool RazuviousUseObedienceCrystalAction::Execute(Event event) +{ + if (!helper.UpdateBossAI()) + { + return false; + } + // bot->GetCharm + if (Unit* charm = bot->GetCharm()) + { + Unit* target = AI_VALUE2(Unit*, "find target", "instructor razuvious"); + if (!target) + { + return false; + } + if (charm->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_ACTIVE) == NULL_MOTION_TYPE) + { + charm->GetMotionMaster()->Clear(); + charm->GetMotionMaster()->MoveChase(target); + charm->GetAI()->AttackStart(target); + } + Aura* forceObedience = botAI->GetAura("force obedience", charm); + uint32 duration_time; + if (!forceObedience) + { + forceObedience = botAI->GetAura("mind control", charm); + duration_time = 60000; + } + else + { + duration_time = 90000; + } + if (!forceObedience) + { + return false; + } + if (charm->GetDistance(target) <= 0.51f) + { + // taunt + bool tauntUseful = true; + if (forceObedience->GetDuration() <= (duration_time - 5000)) + { + if (target->GetVictim() && botAI->HasAura(29061, target->GetVictim())) + { + tauntUseful = false; + } + if (forceObedience->GetDuration() <= 3000) + { + tauntUseful = false; + } + } + if (forceObedience->GetDuration() >= (duration_time - 500)) + { + tauntUseful = false; + } + if (tauntUseful && !charm->HasSpellCooldown(29060)) + { + // shield + if (!charm->HasSpellCooldown(29061)) + { + charm->CastSpell(charm, 29061, true); + charm->AddSpellCooldown(29061, 0, 30 * 1000); + } + charm->CastSpell(target, 29060, true); + charm->AddSpellCooldown(29060, 0, 20 * 1000); + } + // strike + if (!charm->HasSpellCooldown(61696)) + { + charm->CastSpell(target, 61696, true); + charm->AddSpellCooldown(61696, 0, 4 * 1000); + } + } + } + else + { + Difficulty diff = bot->GetRaidDifficulty(); + if (diff == RAID_DIFFICULTY_10MAN_NORMAL) + { + GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs"); + for (auto i = npcs.begin(); i != npcs.end(); i++) + { + Creature* unit = botAI->GetCreature(*i); + if (!unit) + { + continue; + } + if (botAI->IsMainTank(bot) && unit->GetSpawnId() != 128352) + { + continue; + } + if (!botAI->IsMainTank(bot) && unit->GetSpawnId() != 128353) + { + continue; + } + if (MoveTo(unit, 0.0f, MovementPriority::MOVEMENT_COMBAT)) + { + return true; + } + Creature* creature = bot->GetNPCIfCanInteractWith(*i, UNIT_NPC_FLAG_SPELLCLICK); + if (!creature) + continue; + creature->HandleSpellClick(bot); + return true; + } + } + else + { + GuidVector attackers = context->GetValue("attackers")->Get(); + Unit* target = nullptr; + for (auto i = attackers.begin(); i != attackers.end(); ++i) + { + Unit* unit = botAI->GetUnit(*i); + if (!unit) + continue; + if (botAI->EqualLowercaseName(unit->GetName(), "death knight understudy")) + { + target = unit; + break; + } + } + if (target) + { + if (bot->GetDistance2d(target) > sPlayerbotAIConfig.spellDistance) + { + return MoveNear(target, sPlayerbotAIConfig.spellDistance, MovementPriority::MOVEMENT_COMBAT); + } + else + { + return botAI->CastSpell("mind control", target); + } + } + } + } + return false; +} + +bool RazuviousTargetAction::Execute(Event event) +{ + if (!helper.UpdateBossAI()) + { + return false; + } + Unit* razuvious = AI_VALUE2(Unit*, "find target", "instructor razuvious"); + Unit* understudy = AI_VALUE2(Unit*, "find target", "death knight understudy"); + Unit* target = nullptr; + if (botAI->IsTank(bot)) + { + target = understudy; + } + else + { + target = razuvious; + } + if (AI_VALUE(Unit*, "current target") == target) + { + return false; + } + return Attack(target); +} \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Sapphiron.cpp b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Sapphiron.cpp new file mode 100644 index 0000000000..082c6206ea --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Sapphiron.cpp @@ -0,0 +1,257 @@ +#include "RaidNaxxActions.h" + +#include +#include + +#include "PlayerbotAIConfig.h" +#include "Playerbots.h" +#include "RaidNaxxBossHelper.h" +#include "RaidNaxxSpellIds.h" + +bool SapphironGroundPositionAction::Execute(Event event) +{ + if (!helper.UpdateBossAI()) + { + return false; + } + if (botAI->IsHeal(bot) && helper.HasLifeDrainInGroup() && !botAI->HasStrategy("cure", BOT_STATE_COMBAT)) + { + botAI->ChangeStrategy("cure", BOT_STATE_COMBAT); + } + if (botAI->IsMainTank(bot)) + { + if (AI_VALUE2(bool, "has aggro", "current target")) + { + return MoveTo(NAXX_MAP_ID, helper.mainTankPos.first, helper.mainTankPos.second, helper.GENERIC_HEIGHT, false, false, false, + false, MovementPriority::MOVEMENT_COMBAT); + } + return false; + } + Unit* boss = AI_VALUE2(Unit*, "find target", "sapphiron"); + if (boss && helper.IsPhaseGround()) + { + bool needsSideStack = boss->isInFront(bot) || boss->isInBack(bot); + if (!needsSideStack) + { + needsSideStack = NaxxSpellIds::HasAnyAura(botAI, bot, {NaxxSpellIds::LifeDrain}) || botAI->HasAura("life drain", bot); + } + if (needsSideStack) + { + float distance; + if (botAI->IsRanged(bot) || botAI->IsHeal(bot) || + NaxxSpellIds::HasAnyAura(botAI, bot, {NaxxSpellIds::LifeDrain}) || botAI->HasAura("life drain", bot)) + { + distance = 30.0f; + } + else + { + distance = 5.0f; + } + float angle = boss->GetOrientation() + M_PI / 2; + float posX = boss->GetPositionX() + cos(angle) * distance; + float posY = boss->GetPositionY() + sin(angle) * distance; + if (MoveTo(NAXX_MAP_ID, posX, posY, helper.GENERIC_HEIGHT, false, false, false, false, MovementPriority::MOVEMENT_COMBAT)) + { + return true; + } + return MoveInside(NAXX_MAP_ID, posX, posY, helper.GENERIC_HEIGHT, 2.0f, MovementPriority::MOVEMENT_COMBAT); + } + } + if (helper.JustLanded()) + { + uint32 index = botAI->GetGroupSlotIndex(bot); + float start_angle = 0.85 * M_PI; + float offset_angle = M_PI * 0.02 * index; + float angle = start_angle + offset_angle; + float distance; + if (botAI->IsRanged(bot)) + { + distance = 35.0f; + } + else if (botAI->IsHeal(bot)) + { + distance = 30.0f; + } + else + { + distance = 5.0f; + } + float posX = helper.center.first + cos(angle) * distance; + float posY = helper.center.second + sin(angle) * distance; + if (MoveTo(NAXX_MAP_ID, posX, posY, helper.GENERIC_HEIGHT, false, false, false, false, MovementPriority::MOVEMENT_COMBAT)) + { + return true; + } + return MoveInside(NAXX_MAP_ID, posX, posY, helper.GENERIC_HEIGHT, 2.0f, MovementPriority::MOVEMENT_COMBAT); + } + else + { + std::vector dest; + if (helper.FindPosToAvoidChill(dest)) + { + return MoveTo(NAXX_MAP_ID, dest[0], dest[1], dest[2], false, false, false, false, MovementPriority::MOVEMENT_COMBAT); + } + } + return false; +} + +bool SapphironFlightPositionAction::Execute(Event event) +{ + if (!helper.UpdateBossAI()) + { + return false; + } + if (botAI->IsHeal(bot) && helper.HasLifeDrainInGroup() && !botAI->HasStrategy("cure", BOT_STATE_COMBAT)) + { + botAI->ChangeStrategy("cure", BOT_STATE_COMBAT); + } + if (NaxxSpellIds::HasAnyAura(botAI, bot, {NaxxSpellIds::Icebolt10, NaxxSpellIds::Icebolt25}) || + botAI->HasAura("icebolt", bot, false, false, -1, true)) + { + return false; + } + if (helper.WaitForExplosion()) + { + bool inShelter = MoveToNearestIcebolt(); + if (inShelter && botAI->IsHeal(bot)) + { + return false; + } + return inShelter; + } + else + { + std::vector dest; + if (helper.FindPosToAvoidChill(dest)) + { + return MoveTo(NAXX_MAP_ID, dest[0], dest[1], dest[2], false, false, false, false, MovementPriority::MOVEMENT_COMBAT); + } + } + return false; +} + +bool SapphironFlightPositionAction::MoveToNearestIcebolt() +{ + Group* group = bot->GetGroup(); + if (!group) + { + return false; + } + Unit* boss = AI_VALUE2(Unit*, "find target", "sapphiron"); + if (!boss) + { + return false; + } + /*Player* playerWithIcebolt = nullptr; + float minDistance = std::numeric_limits::max();*/ + std::vector icebolts; + icebolts.reserve(5); + Player* nearest = nullptr; + float nearestDist = std::numeric_limits::max(); + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + Player* member = ref->GetSource(); + if (!member || !member->IsAlive()) + { + continue; + } + if (NaxxSpellIds::HasAnyAura(botAI, member, {NaxxSpellIds::Icebolt10, NaxxSpellIds::Icebolt25}) || + botAI->HasAura("icebolt", member, false, false, -1, true)) + { + //if (!playerWithIcebolt || minDistance > bot->GetDistance(member)) + icebolts.push_back(member); + float d = bot->GetDistance(member); + if (!nearest || d < nearestDist) + { + /*playerWithIcebolt = member; + minDistance = bot->GetDistance(member);*/ + nearest = member; + nearestDist = d; + } + } + } + //if (playerWithIcebolt) + if (!icebolts.empty()) + { + // In 25-man the core may spawn only 3 iceblocks, so "nearest" can over-stack one block. + // Use a stable round-robin assignment by group slot to spread bots across available blocks, + // but keep a safety fallback to nearest if the assigned block is too far away. + std::sort(icebolts.begin(), icebolts.end(), [](Player* a, Player* b) + { + return a->GetGUID().GetRawValue() < b->GetGUID().GetRawValue(); + }); + + int32 slotIndex = botAI->GetGroupSlotIndex(bot); + Player* assigned = icebolts[std::max(0, slotIndex) % icebolts.size()]; + Player* playerWithIcebolt = assigned ? assigned : nearest; + + if (playerWithIcebolt && nearest && playerWithIcebolt != nearest) + { + float assignedDist = bot->GetDistance(playerWithIcebolt); + // If the assignment sends the bot across the room, prefer nearest to reduce LOS failures. + if (assignedDist > nearestDist + 20.0f) + { + playerWithIcebolt = nearest; + } + } + + constexpr float shelterDistance = 9.0f; + constexpr float shelterEpsilon = 0.35f; + constexpr float lateralOffset = 1.5f; + float angle = boss->GetAngle(playerWithIcebolt); + float posX = playerWithIcebolt->GetPositionX() + cos(angle) * shelterDistance; + float posY = playerWithIcebolt->GetPositionY() + sin(angle) * shelterDistance; + float posZ = playerWithIcebolt->GetPositionZ(); + //int32 slotIndex = botAI->GetGroupSlotIndex(bot); + float offsetSign = (slotIndex % 2 == 0) ? 1.0f : -1.0f; + float offsetAngle = angle + (M_PI / 2.0f); + float offsetX = cos(offsetAngle) * lateralOffset * offsetSign; + float offsetY = sin(offsetAngle) * lateralOffset * offsetSign; + float candidateX = posX + offsetX; + float candidateY = posY + offsetY; + float bossX = boss->GetPositionX(); + float bossY = boss->GetPositionY(); + float lineDx = candidateX - bossX; + float lineDy = candidateY - bossY; + float lineLen = sqrt(lineDx * lineDx + lineDy * lineDy); + if (lineLen > 0.1f) + { + float relX = playerWithIcebolt->GetPositionX() - bossX; + float relY = playerWithIcebolt->GetPositionY() - bossY; + float proj = (relX * lineDx + relY * lineDy) / lineLen; + float clamped = std::max(0.0f, std::min(lineLen, proj)); + float closestX = bossX + (lineDx / lineLen) * clamped; + float closestY = bossY + (lineDy / lineLen) * clamped; + float distToLine = playerWithIcebolt->GetDistance2d(closestX, closestY); + if (distToLine <= 2.0f && playerWithIcebolt->IsWithinDist2d(candidateX, candidateY, 10.0f)) + { + posX = candidateX; + posY = candidateY; + } + } + float bossDist = boss->GetDistance2d(bot); + float iceboltDist = boss->GetDistance2d(playerWithIcebolt); + if (bossDist <= iceboltDist + 0.5f) + { + posX = playerWithIcebolt->GetPositionX() + cos(angle) * (shelterDistance + 1.5f); + posY = playerWithIcebolt->GetPositionY() + sin(angle) * (shelterDistance + 1.5f); + } + float distToLosPos = bot->GetDistance2d(posX, posY); + if (distToLosPos > shelterEpsilon) + { + return MoveTo(NAXX_MAP_ID, posX, posY, posZ, false, false, false, true, + MovementPriority::MOVEMENT_FORCED); + } + if (!playerWithIcebolt->IsInBetween(boss, bot, 1.5f)) + { + return MoveTo(NAXX_MAP_ID, posX, posY, posZ, false, false, false, true, + MovementPriority::MOVEMENT_FORCED); + } + if (botAI->IsHeal(bot)) + { + bot->StopMoving(); + } + return true; + } + return false; +} \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Shared.cpp b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Shared.cpp new file mode 100644 index 0000000000..7b399db6ba --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Shared.cpp @@ -0,0 +1,18 @@ +#include "RaidNaxxActions.h" + +uint32 RotateAroundTheCenterPointAction::FindNearestWaypoint() +{ + float minDistance = 0; + int ret = -1; + for (int i = 0; i < intervals; i++) + { + float w_x = waypoints[i].first, w_y = waypoints[i].second; + float dis = bot->GetDistance2d(w_x, w_y); + if (ret == -1 || dis < minDistance) + { + ret = i; + minDistance = dis; + } + } + return ret; +} \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Thaddius.cpp b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Thaddius.cpp new file mode 100644 index 0000000000..515ee680e0 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Action/RaidNaxxActions_Thaddius.cpp @@ -0,0 +1,140 @@ +#include "RaidNaxxActions.h" + +#include "PlayerbotAIConfig.h" +#include "Playerbots.h" +#include "RaidNaxxSpellIds.h" + +bool ThaddiusAttackNearestPetAction::isUseful() +{ + if (!helper.UpdateBossAI()) + { + return false; + } + if (!helper.IsPhasePet()) + { + return false; + } + Unit* target = helper.GetNearestPet(); + if (!bot->IsWithinDistInMap(target, 50.0f)) + { + return false; + } + return true; +} + +bool ThaddiusAttackNearestPetAction::Execute(Event event) +{ + Unit* target = helper.GetNearestPet(); + if (!bot->IsWithinLOSInMap(target)) + { + return MoveTo(target, 0, MovementPriority::MOVEMENT_COMBAT); + } + if (AI_VALUE(Unit*, "current target") != target) + { + return Attack(target); + } + if (botAI->IsTank(bot) && AI_VALUE2(bool, "has aggro", "current target")) + { + std::pair posForTank = helper.PetPhaseGetPosForTank(); + return MoveTo(533, posForTank.first, posForTank.second, helper.tankPosZ, false, false, false, false, MovementPriority::MOVEMENT_COMBAT); + } + if (botAI->IsRanged(bot)) + { + std::pair posForRanged = helper.PetPhaseGetPosForRanged(); + return MoveTo(533, posForRanged.first, posForRanged.second, helper.tankPosZ, false, false, false, false, MovementPriority::MOVEMENT_COMBAT); + } + return false; +} + +bool ThaddiusMoveToPlatformAction::isUseful() { return true; } + +bool ThaddiusMoveToPlatformAction::Execute(Event event) +{ + std::vector> position = { + // high left + {3462.99f, -2918.90f}, + // high right + {3520.65f, -2976.51f}, + // low left + {3471.36f, -2910.65f}, + // low right + {3528.80f, -2967.04f}, + // center + {3512.19f, -2928.58f}, + }; + float high_z = 312.00f, low_z = 304.02f; + bool is_left = bot->GetDistance2d(position[0].first, position[0].second) < + bot->GetDistance2d(position[1].first, position[1].second); + if (bot->GetPositionZ() >= (high_z - 3.0f)) + { + if (is_left) + { + if (!MoveTo(bot->GetMapId(), position[0].first, position[0].second, high_z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT)) + { + float distance = bot->GetExactDist2d(position[0].first, position[0].second); + if (distance < sPlayerbotAIConfig.contactDistance) + JumpTo(bot->GetMapId(), position[2].first, position[2].second, low_z, MovementPriority::MOVEMENT_COMBAT); + // bot->TeleportTo(bot->GetMapId(), position[2].first, position[2].second, low_z, bot->GetOrientation()); + } + } + else + { + if (!MoveTo(bot->GetMapId(), position[1].first, position[1].second, high_z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT)) + { + float distance = bot->GetExactDist2d(position[1].first, position[1].second); + if (distance < sPlayerbotAIConfig.contactDistance) + JumpTo(bot->GetMapId(), position[3].first, position[3].second, low_z, MovementPriority::MOVEMENT_COMBAT); + // bot->TeleportTo(bot->GetMapId(), position[3].first, position[3].second, low_z, bot->GetOrientation()); + } + } + } + else + { + return MoveTo(bot->GetMapId(), position[4].first, position[4].second, low_z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT); + } + return true; +} + +bool ThaddiusMovePolarityAction::isUseful() +{ + return !botAI->IsMainTank(bot) || AI_VALUE2(bool, "has aggro", "current target"); +} + +bool ThaddiusMovePolarityAction::Execute(Event event) +{ + std::vector> position = { + // left melee + {3508.29f, -2920.12f}, + // left ranged + {3501.72f, -2913.36f}, + // right melee + {3519.74f, -2931.69f}, + // right ranged + {3524.32f, -2936.26f}, + // center melee + {3512.19f, -2928.58f}, + // center ranged + {3504.68f, -2936.68f}, + }; + uint32 idx; + if (NaxxSpellIds::HasAnyAura( + botAI, bot, + {NaxxSpellIds::NegativeCharge10, NaxxSpellIds::NegativeCharge25, NaxxSpellIds::NegativeChargeStack}) || + botAI->HasAura("negative charge", bot, false, false, -1, true)) + { + idx = 0; + } + else if (NaxxSpellIds::HasAnyAura( + botAI, bot, + {NaxxSpellIds::PositiveCharge10, NaxxSpellIds::PositiveCharge25, NaxxSpellIds::PositiveChargeStack}) || + botAI->HasAura("positive charge", bot, false, false, -1, true)) + { + idx = 1; + } + else + { + idx = 2; + } + idx = idx * 2 + botAI->IsRanged(bot); + return MoveTo(bot->GetMapId(), position[idx].first, position[idx].second, bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT); +} \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Multiplier/RaidNaxxMultipliers.cpp b/src/Ai/Raid/Naxxramas/Multiplier/RaidNaxxMultipliers.cpp new file mode 100644 index 0000000000..021b3aeb0a --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Multiplier/RaidNaxxMultipliers.cpp @@ -0,0 +1,515 @@ +#include "RaidNaxxMultipliers.h" + +#include "ChooseTargetActions.h" +#include "DKActions.h" +#include "DruidActions.h" +#include "DruidBearActions.h" +#include "FollowActions.h" +#include "GenericActions.h" +#include "GenericSpellActions.h" +#include "HunterActions.h" +#include "MageActions.h" +#include "MovementActions.h" +#include "PaladinActions.h" +#include "PriestActions.h" +#include "RaidNaxxActions.h" +#include "RaidNaxxSpellIds.h" +#include "ReachTargetActions.h" +#include "RogueActions.h" +#include "ScriptedCreature.h" +#include "ShamanActions.h" +#include "Spell.h" +#include "UseMeetingStoneAction.h" +#include "WarriorActions.h" + +float GrobbulusMultiplier::GetValue(Action* action) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "grobbulus"); + if (!boss) + { + return 1.0f; + } + if (dynamic_cast(action)) + { + return botAI->IsMainTank(bot) ? 0.0f : 1.0f; + } + if (dynamic_cast(action)) + { + return 0.0f; + } + return 1.0f; +} + +float HeiganDanceMultiplier::GetValue(Action* action) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "heigan the unclean"); + if (!boss) + { + return 1.0f; + } + bool platform_phase = boss->IsWithinDist2d(2794.26f, -3706.67f, 10.0f); + bool eruption_casting = false; + if (boss->HasUnitState(UNIT_STATE_CASTING)) + { + Spell* spell = boss->GetCurrentSpell(CURRENT_GENERIC_SPELL); + if (!spell) + { + spell = boss->GetCurrentSpell(CURRENT_CHANNELED_SPELL); + } + if (spell) + { + SpellInfo const* info = spell->GetSpellInfo(); + bool isEruption = NaxxSpellIds::MatchesAnySpellId(info, {NaxxSpellIds::Eruption10}); + if (!isEruption && info && info->SpellName[LOCALE_enUS]) + { + // Fallback to name for custom spell data. + isEruption = botAI->EqualLowercaseName(info->SpellName[LOCALE_enUS], "eruption"); + } + if (isEruption) + { + eruption_casting = true; + } + } + } + if (dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action) ) + { + return 0.0f; + } + if (!platform_phase && !eruption_casting) + { + return 1.0f; + } + if (dynamic_cast(action) || dynamic_cast(action)) + { + return 1.0f; + } + if (dynamic_cast(action) && !dynamic_cast(action)) + { + CastSpellAction* spellAction = dynamic_cast(action); + uint32 spellId = AI_VALUE2(uint32, "spell id", spellAction->getSpell()); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + if (!spellInfo) + { + return 0.0f; + } + uint32 castTime = spellInfo->CalcCastTime(); + if (castTime == 0 && !spellInfo->IsChanneled()) + { + return 1.0f; + } + } + return 0.0f; +} + +float LoathebGenericMultiplier::GetValue(Action* action) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "loatheb"); + if (!boss) + { + return 1.0f; + } + context->GetValue("neglect threat")->Set(true); + if (botAI->GetState() == BOT_STATE_COMBAT && + (dynamic_cast(action) || dynamic_cast(action) || + dynamic_cast(action) || dynamic_cast(action) || + dynamic_cast(action))) + { + return 0.0f; + } + if (!dynamic_cast(action)) + { + return 1.0f; + } + Aura* aura = NaxxSpellIds::GetAnyAura(bot, {NaxxSpellIds::NecroticAura10}); + if (!aura) + { + // Fallback to name for custom spell data. + aura = botAI->GetAura("necrotic aura", bot); + } + if (!aura || aura->GetDuration() <= 1500) + { + return 1.0f; + } + return 0.0f; +} + +float ThaddiusGenericMultiplier::GetValue(Action* action) +{ + if (!helper.UpdateBossAI()) + { + return 1.0f; + } + if (dynamic_cast(action)) + return 0.0f; + // pet phase + if (helper.IsPhasePet() && + (dynamic_cast(action) || dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action) || dynamic_cast(action))) + { + return 0.0f; + } + // die at the same time + Unit* target = AI_VALUE(Unit*, "current target"); + Unit* feugen = AI_VALUE2(Unit*, "find target", "feugen"); + Unit* stalagg = AI_VALUE2(Unit*, "find target", "stalagg"); + if (helper.IsPhasePet() && target && feugen && stalagg && target->GetHealthPct() <= 40 && + (feugen->GetHealthPct() >= target->GetHealthPct() + 3 || stalagg->GetHealthPct() >= target->GetHealthPct() + 3)) + { + if (dynamic_cast(action) && !dynamic_cast(action)) + { + return 0.0f; + } + } + // magnetic pull + // uint32 curr_timer = eventMap->GetTimer(); + // // if (curr_phase == 2 && bot->GetPositionZ() > 312.5f && dynamic_cast(action)) + // { + // if (curr_phase == 2 && (curr_timer % 20000 >= 18000 || curr_timer % 20000 <= 2000) && + // dynamic_cast(action)) + // { + // // MotionMaster *mm = bot->GetMotionMaster(); + // // mm->Clear(); + // return 0.0f; + // } + // thaddius phase + // if (curr_phase == 8 && dynamic_cast(action)) + // { + // return 0.0f; + // } + return 1.0f; +} + +float SapphironGenericMultiplier::GetValue(Action* action) +{ + if (!helper.UpdateBossAI()) + { + return 1.0f; + } + if (botAI->IsHeal(bot)) + { + if (helper.IsBreathWindow()) + { + if (dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action)) + { + return 1.0f; + } + return 0.0f; + } + if (helper.WaitForExplosion()) + { + if (dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action)) + { + return 1.0f; + } + return 0.0f; + } + if (helper.HasLifeDrainInGroup()) + { + if (dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action)) + { + return 1.0f; + } + return 0.0f; + } + } + if (dynamic_cast(action) || dynamic_cast(action)) + { + return 0.0f; + } + return 1.0f; +} + +float InstructorRazuviousGenericMultiplier::GetValue(Action* action) +{ + if (!helper.UpdateBossAI()) + { + return 1.0f; + } + context->GetValue("neglect threat")->Set(true); + if (botAI->GetState() == BOT_STATE_COMBAT && + (dynamic_cast(action) || dynamic_cast(action) || + dynamic_cast(action) || dynamic_cast(action) || + dynamic_cast(action) || dynamic_cast(action))) + { + return 0.0f; + } + return 1.0f; +} + +float KelthuzadGenericMultiplier::GetValue(Action* action) +{ + if (!helper.UpdateBossAI()) + { + return 1.0f; + } + + bool guardiansPresent = !helper.GetGuardians().empty(); + bool isOffTankForKT = botAI->IsTank(bot) && !botAI->IsMainTank(bot) && + (botAI->IsAssistTank(bot) || botAI->HasStrategy("tank assist", BOT_STATE_COMBAT)); + + if (dynamic_cast(action)) + { + Unit* target = AI_VALUE(Unit*, "current target"); + if (!target) + return 0.0f; + + if (!helper.IsWithinRoom(target, KelthuzadBossHelper::ROOM_MAX_RADIUS)) + return 0.0f; + + if (Unit* pet = bot->GetPet()) + if (!helper.IsWithinRoom(pet, KelthuzadBossHelper::ROOM_MAX_RADIUS + 2.0f)) + return 0.0f; + if (Unit* guardianPet = bot->GetGuardianPet()) + if (!helper.IsWithinRoom(guardianPet, KelthuzadBossHelper::ROOM_MAX_RADIUS + 2.0f)) + return 0.0f; + + return 1.0f; + } + + if (helper.IsPhaseTwo() && helper.IsBossCasting(NaxxSpellIds::FrostBoltSingle)) + { + std::string const name = action->getName(); + if (name == "kick" || name == "pummel" || name == "shield bash" || + name == "mind freeze" || name == "strangulate" || + name == "counterspell" || name == "wind shear" || + name == "spell lock" || name == "silencing shot" || + name == "bash" || name == "hammer of justice") + { + return 5.0f; + } + } + + if (helper.HasChains(bot)) + { + if (dynamic_cast(action)) + { + return 1.0f; + } + return 0.0f; + } + if (botAI->IsHeal(bot)) + { + if (helper.HasAuraInGroup(NaxxSpellIds::FrostBlast)) + { + if (dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action)) + { + return 1.0f; + } + return 0.0f; + } + if (helper.HasAuraInGroup(NaxxSpellIds::ChainsOfKelthuzad)) + { + if (dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action)) + { + return 1.0f; + } + return 0.0f; + } + } + if (helper.HasDetonateMana(bot)) + { + if (dynamic_cast(action) || dynamic_cast(action)) + { + return 1.0f; + } + return 0.0f; + } + + if (dynamic_cast(action)) + { + if (isOffTankForKT && guardiansPresent) + { + return 2.0f; + } + return 1.0f; + } + + if (isOffTankForKT && guardiansPresent) + { + if (dynamic_cast(action)) + return 1.0f; + } + + if ((dynamic_cast(action) || dynamic_cast(action) || + dynamic_cast(action))) + { + return 0.0f; + } + if (helper.IsPhaseOne()) + { + if (dynamic_cast(action) || dynamic_cast(action) || + dynamic_cast(action) || dynamic_cast(action) || + dynamic_cast(action) || dynamic_cast(action) || + dynamic_cast(action)) + { + return 0.0f; + } + } + if (helper.IsPhaseTwo()) + { + if (dynamic_cast(action) || dynamic_cast(action)) + { + return 0.0f; + } + } + return 1.0f; +} + +float NothGenericMultiplier::GetValue(Action* action) +{ + if (!helper.UpdateBossAI()) + { + return 1.0f; + } + if (helper.HasCurseInGroup() && (bot->getClass() == CLASS_DRUID || bot->getClass() == CLASS_SHAMAN || + bot->getClass() == CLASS_MAGE)) + { + if (dynamic_cast(action)) + { + return 2.0f; + } + if (dynamic_cast(action)) + { + return 1.0f; + } + return 0.0f; + } + if (!helper.IsBlinkWindow() || botAI->IsTank(bot)) + { + return 1.0f; + } + if (dynamic_cast(action) || dynamic_cast(action) || + dynamic_cast(action)) + { + return 0.0f; + } + if (dynamic_cast(action) && !dynamic_cast(action)) + { + return 0.0f; + } + return 1.0f; +} + +float AnubrekhanGenericMultiplier::GetValue(Action* action) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "anub'rekhan"); + if (!boss) + { + return 1.0f; + } + if (NaxxSpellIds::HasAnyAura( + botAI, boss, {NaxxSpellIds::LocustSwarm10, NaxxSpellIds::LocustSwarm10Alt, NaxxSpellIds::LocustSwarm25}) || + botAI->HasAura("locust swarm", boss)) + { + if (dynamic_cast(action)) + { + return 0.0f; + } + } + return 1.0f; +} + +float FourhorsemanGenericMultiplier::GetValue(Action* action) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "sir zeliek"); + if (!boss) + { + return 1.0f; + } + context->GetValue("neglect threat")->Set(true); + if ((dynamic_cast(action) || dynamic_cast(action))) + { + return 0.0f; + } + return 1.0f; +} + +// float GothikGenericMultiplier::GetValue(Action* action) +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", "gothik the harvester"); +// if (!boss) +// { +// return 1.0f; +// } +// BossAI* boss_ai = dynamic_cast(boss->GetAI()); +// EventMap* eventMap = boss_botAI->GetEvents(); +// uint32 curr_phase = eventMap->GetPhaseMask(); +// if (curr_phase == 1 && (dynamic_cast(action))) +// { +// return 0.0f; +// } +// if (curr_phase == 1 && (dynamic_cast(action))) +// { +// Unit* target = action->GetTarget(); +// if (target == boss) +// { +// return 0.0f; +// } +// } +// return 1.0f; +// } + +float GluthGenericMultiplier::GetValue(Action* action) +{ + if (!helper.UpdateBossAI()) + { + return 1.0f; + } + if ((dynamic_cast(action) || dynamic_cast(action) || + dynamic_cast(action) || dynamic_cast(action) || + dynamic_cast(action))) + { + return 0.0f; + } + + if (botAI->IsMainTank(bot)) + { + Aura* aura = NaxxSpellIds::GetAnyAura(bot, {NaxxSpellIds::MortalWound10, NaxxSpellIds::MortalWound25}); + if (!aura) + { + // Fallback to name for custom spell data. + aura = botAI->GetAura("mortal wound", bot, false, true); + } + if (aura && aura->GetStackAmount() >= 5) + { + if (dynamic_cast(action) || dynamic_cast(action) || + dynamic_cast(action) || dynamic_cast(action)) + { + return 0.0f; + } + } + } + if (dynamic_cast(action)) + { + Unit* target = AI_VALUE(Unit*, "current target"); + if (helper.IsZombieChow(target)) + { + return 0.0f; + } + } + return 1.0f; +} \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Multiplier/RaidNaxxMultipliers.h b/src/Ai/Raid/Naxxramas/Multiplier/RaidNaxxMultipliers.h new file mode 100644 index 0000000000..1fbc5a797c --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Multiplier/RaidNaxxMultipliers.h @@ -0,0 +1,127 @@ + +#ifndef _PLAYERRBOT_RAIDNAXXMULTIPLIERS_H_ +#define _PLAYERRBOT_RAIDNAXXMULTIPLIERS_H_ + +#include "Multiplier.h" +#include "RaidNaxxBossHelper.h" +#include "GenericSpellActions.h" + +class GrobbulusMultiplier : public Multiplier +{ +public: + GrobbulusMultiplier(PlayerbotAI* ai) : Multiplier(ai, "grobbulus") {} + +public: + virtual float GetValue(Action* action); +}; +class HeiganDanceMultiplier : public Multiplier +{ +public: + HeiganDanceMultiplier(PlayerbotAI* ai) : Multiplier(ai, "helgan dance") {} + +public: + virtual float GetValue(Action* action); +}; + +class LoathebGenericMultiplier : public Multiplier +{ +public: + LoathebGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "loatheb generic") {} + +public: + virtual float GetValue(Action* action); +}; + +class ThaddiusGenericMultiplier : public Multiplier +{ +public: + ThaddiusGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "thaddius generic"), helper(ai) {} + +public: + virtual float GetValue(Action* action); + +private: + ThaddiusBossHelper helper; +}; + +class SapphironGenericMultiplier : public Multiplier +{ +public: + SapphironGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "sapphiron generic"), helper(ai) {} + + virtual float GetValue(Action* action); + +private: + SapphironBossHelper helper; +}; + +class InstructorRazuviousGenericMultiplier : public Multiplier +{ +public: + InstructorRazuviousGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "instructor razuvious generic"), helper(ai) + { + } + virtual float GetValue(Action* action); + +private: + RazuviousBossHelper helper; +}; + +class KelthuzadGenericMultiplier : public Multiplier +{ +public: + KelthuzadGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "kelthuzad generic"), helper(ai) {} + virtual float GetValue(Action* action); + +private: + KelthuzadBossHelper helper; +}; + +class AnubrekhanGenericMultiplier : public Multiplier +{ +public: + AnubrekhanGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "anubrekhan generic") {} + +public: + virtual float GetValue(Action* action); +}; + +class FourhorsemanGenericMultiplier : public Multiplier +{ +public: + FourhorsemanGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "fourhorseman generic") {} + +public: + virtual float GetValue(Action* action); +}; + +// class GothikGenericMultiplier : public Multiplier +// { +// public: +// GothikGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "gothik generic") {} + +// public: +// virtual float GetValue(Action* action); +// }; + +class GluthGenericMultiplier : public Multiplier +{ +public: + GluthGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "gluth generic"), helper(ai) {} + float GetValue(Action* action) override; + +private: + GluthBossHelper helper; +}; + +class NothGenericMultiplier : public Multiplier +{ +public: + NothGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "noth generic"), helper(ai) {} + float GetValue(Action* action) override; + +private: + NothBossHelper helper; +}; + +#endif diff --git a/src/Ai/Raid/Naxxramas/RaidNaxxActionContext.h b/src/Ai/Raid/Naxxramas/RaidNaxxActionContext.h new file mode 100644 index 0000000000..3eaaeb0654 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/RaidNaxxActionContext.h @@ -0,0 +1,107 @@ +// /* +// * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license, you may redistribute it +// and/or modify it under version 3 of the License, or (at your option), any later version. +// */ + +#ifndef _PLAYERBOT_RAIDNAXXACTIONCONTEXT_H +#define _PLAYERBOT_RAIDNAXXACTIONCONTEXT_H + +#include "Action.h" +#include "NamedObjectContext.h" +#include "RaidNaxxActions.h" + +class RaidNaxxActionContext : public NamedObjectContext +{ +public: + RaidNaxxActionContext() + { + creators["grobbulus go behind the boss"] = &RaidNaxxActionContext::go_behind_the_boss; + creators["rotate grobbulus"] = &RaidNaxxActionContext::rotate_grobbulus; + creators["grobbulus move center"] = &RaidNaxxActionContext::grobbulus_move_center; + creators["grobbulus move away"] = &RaidNaxxActionContext::grobbulus_move_away; + + creators["heigan dance melee"] = &RaidNaxxActionContext::heigan_dance_melee; + creators["heigan dance ranged"] = &RaidNaxxActionContext::heigan_dance_ranged; + + creators["thaddius attack nearest pet"] = &RaidNaxxActionContext::thaddius_attack_nearest_pet; + creators["thaddius move to platform"] = &RaidNaxxActionContext::thaddius_move_to_platform; + creators["thaddius move polarity"] = &RaidNaxxActionContext::thaddius_move_polarity; + + creators["razuvious use obedience crystal"] = &RaidNaxxActionContext::razuvious_use_obedience_crystal; + creators["razuvious target"] = &RaidNaxxActionContext::razuvious_target; + + creators["horseman attract alternatively"] = &RaidNaxxActionContext::horseman_attract_alternatively; + creators["horseman attack in order"] = &RaidNaxxActionContext::horseman_attack_in_order; + + creators["sapphiron ground position"] = &RaidNaxxActionContext::sapphiron_ground_position; + creators["sapphiron flight position"] = &RaidNaxxActionContext::sapphiron_flight_position; + + creators["kel'thuzad choose target"] = &RaidNaxxActionContext::kelthuzad_choose_target; + creators["kel'thuzad position"] = &RaidNaxxActionContext::kelthuzad_position; + + creators["anub'rekhan choose target"] = &RaidNaxxActionContext::anubrekhan_choose_target; + creators["anub'rekhan position"] = &RaidNaxxActionContext::anubrekhan_position; + + creators["faerlina sacrifice worshipper"] = &RaidNaxxActionContext::faerlina_sacrifice_worshipper; + + creators["maexxna attack web wrap"] = &RaidNaxxActionContext::maexxna_attack_web_wrap; + creators["maexxna tank spiderlings"] = &RaidNaxxActionContext::maexxna_tank_spiderlings; + + creators["gothik move to assigned side"] = &RaidNaxxActionContext::gothik_move_to_assigned_side; + creators["gothik choose target"] = &RaidNaxxActionContext::gothik_choose_target; + + creators["gluth choose target"] = &RaidNaxxActionContext::gluth_choose_target; + creators["gluth position"] = &RaidNaxxActionContext::gluth_position; + creators["gluth slowdown"] = &RaidNaxxActionContext::gluth_slowdown; + + creators["patchwerk ranged position"] = &RaidNaxxActionContext::patchwerk_ranged_position; + + creators["loatheb position"] = &RaidNaxxActionContext::loatheb_position; + creators["loatheb choose target"] = &RaidNaxxActionContext::loatheb_choose_target; + + creators["noth position"] = &RaidNaxxActionContext::noth_position; + creators["noth choose target"] = &RaidNaxxActionContext::noth_choose_target; + } + +private: + static Action* go_behind_the_boss(PlayerbotAI* ai) { return new GrobbulusGoBehindAction(ai); } + static Action* rotate_grobbulus(PlayerbotAI* ai) { return new GrobbulusRotateAction(ai); } + static Action* grobbulus_move_center(PlayerbotAI* ai) { return new GrobblulusMoveCenterAction(ai); } + static Action* grobbulus_move_away(PlayerbotAI* ai) { return new GrobbulusMoveAwayAction(ai); } + static Action* heigan_dance_melee(PlayerbotAI* ai) { return new HeiganDanceMeleeAction(ai); } + static Action* heigan_dance_ranged(PlayerbotAI* ai) { return new HeiganDanceRangedAction(ai); } + static Action* thaddius_attack_nearest_pet(PlayerbotAI* ai) { return new ThaddiusAttackNearestPetAction(ai); } + static Action* thaddius_move_to_platform(PlayerbotAI* ai) { return new ThaddiusMoveToPlatformAction(ai); } + static Action* thaddius_move_polarity(PlayerbotAI* ai) { return new ThaddiusMovePolarityAction(ai); } + static Action* razuvious_target(PlayerbotAI* ai) { return new RazuviousTargetAction(ai); } + static Action* razuvious_use_obedience_crystal(PlayerbotAI* ai) + { + return new RazuviousUseObedienceCrystalAction(ai); + } + static Action* horseman_attract_alternatively(PlayerbotAI* ai) + { + return new HorsemanAttractAlternativelyAction(ai); + } + static Action* horseman_attack_in_order(PlayerbotAI* ai) { return new HorsemanAttactInOrderAction(ai); } + static Action* sapphiron_ground_position(PlayerbotAI* ai) { return new SapphironGroundPositionAction(ai); } + static Action* sapphiron_flight_position(PlayerbotAI* ai) { return new SapphironFlightPositionAction(ai); } + static Action* kelthuzad_choose_target(PlayerbotAI* ai) { return new KelthuzadChooseTargetAction(ai); } + static Action* kelthuzad_position(PlayerbotAI* ai) { return new KelthuzadPositionAction(ai); } + static Action* anubrekhan_choose_target(PlayerbotAI* ai) { return new AnubrekhanChooseTargetAction(ai); } + static Action* anubrekhan_position(PlayerbotAI* ai) { return new AnubrekhanPositionAction(ai); } + static Action* faerlina_sacrifice_worshipper(PlayerbotAI* ai) { return new FaerlinaSacrificeWorshipperAction(ai); } + static Action* maexxna_attack_web_wrap(PlayerbotAI* ai) { return new MaexxnaAttackWebWrapAction(ai); } + static Action* maexxna_tank_spiderlings(PlayerbotAI* ai) { return new MaexxnaTankSpiderlingsAction(ai); } + static Action* gothik_move_to_assigned_side(PlayerbotAI* ai) { return new GothikMoveToAssignedSideAction(ai); } + static Action* gothik_choose_target(PlayerbotAI* ai) { return new GothikChooseTargetAction(ai); } + static Action* gluth_choose_target(PlayerbotAI* ai) { return new GluthChooseTargetAction(ai); } + static Action* gluth_position(PlayerbotAI* ai) { return new GluthPositionAction(ai); } + static Action* gluth_slowdown(PlayerbotAI* ai) { return new GluthSlowdownAction(ai); } + static Action* patchwerk_ranged_position(PlayerbotAI* ai) { return new PatchwerkRangedPositionAction(ai); } + static Action* loatheb_position(PlayerbotAI* ai) { return new LoathebPositionAction(ai); } + static Action* loatheb_choose_target(PlayerbotAI* ai) { return new LoathebChooseTargetAction(ai); } + static Action* noth_position(PlayerbotAI* ai) { return new NothPositionAction(ai); } + static Action* noth_choose_target(PlayerbotAI* ai) { return new NothChooseTargetAction(ai); } +}; + +#endif \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/RaidNaxxBossHelper.h b/src/Ai/Raid/Naxxramas/RaidNaxxBossHelper.h new file mode 100644 index 0000000000..1addad1623 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/RaidNaxxBossHelper.h @@ -0,0 +1,1201 @@ +#ifndef _PLAYERBOT_RAIDNAXXBOSSHELPER_H +#define _PLAYERBOT_RAIDNAXXBOSSHELPER_H + +#include +#include +#include +#include +#include + +#include "AiObject.h" +#include "AiObjectContext.h" +#include "EventMap.h" +#include "Log.h" +#include "MotionMaster.h" +#include "NamedObjectContext.h" +#include "ObjectGuid.h" +#include "ObjectAccessor.h" +#include "Pet.h" +#include "Player.h" +#include "PlayerbotAI.h" +#include "Playerbots.h" +#include "ScriptedCreature.h" +#include "SharedDefines.h" +#include "Spell.h" +#include "Timer.h" +#include "RaidNaxxSpellIds.h" + +const uint32 NAXX_MAP_ID = 533; + +template +class GenericBossHelper : public AiObject +{ +public: + GenericBossHelper(PlayerbotAI* botAI, std::string name) : AiObject(botAI), _name(name) {} + virtual bool UpdateBossAI() + { + if (!bot->IsInCombat()) + { + _unit = nullptr; + } + if (_unit && (!_unit->IsInWorld() || !_unit->IsAlive())) + { + _unit = nullptr; + } + if (!_unit) + { + _unit = AI_VALUE2(Unit*, "find target", _name); + if (!_unit) + { + return false; + } + _target = _unit->ToCreature(); + if (!_target) + { + return false; + } + _ai = dynamic_cast(_target->GetAI()); + if (!_ai) + { + return false; + } + _event_map = &_ai->events; + if (!_event_map) + { + return false; + } + } + if (!_event_map) + { + return false; + } + _timer = getMSTime(); + return true; + } + virtual void Reset() + { + _unit = nullptr; + _target = nullptr; + _ai = nullptr; + _event_map = nullptr; + _timer = 0; + } + +protected: + std::string _name; + Unit* _unit = nullptr; + Creature* _target = nullptr; + BossAiType* _ai = nullptr; + EventMap* _event_map = nullptr; + uint32 _timer = 0; +}; + +class KelthuzadBossHelper : public AiObject +{ +public: + KelthuzadBossHelper(PlayerbotAI* botAI) : AiObject(botAI) {} + + static constexpr uint32 NPC_GUARDIAN_OF_ICECROWN = 16441; + + bool IsGuardian(Unit* unit) const + { + if (!unit) + return false; + if (Creature* c = unit->ToCreature()) + if (c->GetEntry() == NPC_GUARDIAN_OF_ICECROWN) + return true; + return botAI->EqualLowercaseName(unit->GetName(), "guardian of icecrown"); + } + + const std::pair center = {3716.19f, -5106.58f}; + const std::pair tank_pos = {3709.19f, -5104.86f}; + const std::pair assist_tank_pos = {3746.05f, -5112.74f}; + + static constexpr float ROOM_MIN_RADIUS = 6.0f; + static constexpr float ROOM_MAX_RADIUS = 24.0f; + static constexpr float DETONATE_MIN_RADIUS = 20.0f; + static constexpr float DETONATE_MAX_RADIUS = 24.0f; + static constexpr float TANK_HOLD_MAX_RADIUS = 20.0f; + static constexpr float PHASE1_TANK_MAX_RADIUS = 16.0f; + static constexpr float PHASE1_TANK_HOLD_RADIUS = 12.0f; + + bool UpdateBossAI() + { + if (!bot->IsInCombat()) + { + Reset(); + } + if (_unit && (!_unit->IsInWorld() || !_unit->IsAlive())) + { + Reset(); + } + if (!_unit) + { + _unit = AI_VALUE2(Unit*, "find target", "kel'thuzad"); + } + return _unit != nullptr; + } + bool IsPhaseOne() { return _unit && _unit->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE); } + bool IsPhaseTwo() { return _unit && !_unit->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE); } + + Unit* GetBoss() const { return _unit; } + + bool IsBossCasting(uint32 spellId) const + { + if (!_unit) + { + return false; + } + + if (Spell* spell = _unit->GetCurrentSpell(CURRENT_GENERIC_SPELL)) + { + if (SpellInfo const* info = spell->GetSpellInfo()) + { + return info->Id == spellId; + } + } + return false; + } + + uint32 GetRangedCount() const + { + Group* group = bot->GetGroup(); + if (!group) + { + return 0; + } + + uint32 count = 0; + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + Player* member = ref->GetSource(); + if (!member) + { + continue; + } + + if (botAI->IsRanged(member)) + { + ++count; + } + } + return count; + } + + void ClampToRoom(float& x, float& y, float minRadius = ROOM_MIN_RADIUS, float maxRadius = ROOM_MAX_RADIUS) const + { + float dx = x - center.first; + float dy = y - center.second; + float r2 = dx * dx + dy * dy; + if (r2 < 0.0001f) + { + x = center.first + minRadius; + y = center.second; + return; + } + + float r = std::sqrt(r2); + float clamped = std::clamp(r, minRadius, maxRadius); + x = center.first + dx / r * clamped; + y = center.second + dy / r * clamped; + } + + bool IsWithinRoom(WorldObject const* obj, float maxRadius = ROOM_MAX_RADIUS) const + { + return obj && obj->GetDistance2d(center.first, center.second) <= maxRadius; + } + + bool RecallControlledPetsToBot(float leashRadius = (ROOM_MAX_RADIUS + 2.0f), float followDist = 1.5f) + { + bool recalled = false; + + auto RecallUnit = [&](Unit* u) + { + if (!u) + return; + + Creature* creature = u->ToCreature(); + if (!creature) + return; + + if (creature->IsTotem()) + return; + + if (creature->GetDistance2d(center.first, center.second) <= leashRadius) + return; + + creature->AttackStop(); + + if (CharmInfo* charm = creature->GetCharmInfo()) + { + charm->SetIsCommandAttack(false); + charm->SetIsAtStay(false); + charm->SetIsFollowing(true); + charm->SetIsCommandFollow(true); + charm->SetIsReturning(false); + } + + creature->GetMotionMaster()->MoveFollow(bot, followDist, M_PI); + recalled = true; + }; + + RecallUnit(bot->GetPet()); + + for (Unit::ControlSet::const_iterator itr = bot->m_Controlled.begin(); itr != bot->m_Controlled.end(); ++itr) + { + RecallUnit(*itr); + } + + return recalled; + } + + std::pair GetAssistTankHoldPosition() const + { + float x = assist_tank_pos.first; + float y = assist_tank_pos.second; + ClampToRoom(x, y, ROOM_MIN_RADIUS, TANK_HOLD_MAX_RADIUS); + return {x, y}; + } + + std::pair GetMainTankHoldPosition() const + { + float x = tank_pos.first; + float y = tank_pos.second; + ClampToRoom(x, y, ROOM_MIN_RADIUS, TANK_HOLD_MAX_RADIUS); + return {x, y}; + } + + void ComputeRangedSpreadPosition(uint32 index, uint32 total, float& outX, float& outY) const + { + if (total == 0) + { + outX = center.first; + outY = center.second; + return; + } + + float radii[3] = {18.0f, 21.0f, 24.0f}; + uint32 ringSizes[3] = {0, 0, 0}; + uint32 rings = 1; + + if (total <= 10) + { + rings = 1; + ringSizes[0] = total; + } + else if (total <= 18) + { + rings = 2; + ringSizes[0] = (total + 1) / 2; + ringSizes[1] = total - ringSizes[0]; + } + else + { + rings = 3; + ringSizes[0] = (total + 2) / 3; + ringSizes[1] = (total + 1) / 3; + ringSizes[2] = total - ringSizes[0] - ringSizes[1]; + } + + uint32 ring = 0; + uint32 localIndex = index; + for (uint32 r = 0; r < rings; ++r) + { + if (localIndex < ringSizes[r]) + { + ring = r; + break; + } + localIndex -= ringSizes[r]; + } + + uint32 slots = std::max(1, ringSizes[ring]); + float angle = 2.0f * float(M_PI) * (float(localIndex) / float(slots)); + + angle += float(ring) * (float(M_PI) / 8.0f); + + outX = center.first + std::cos(angle) * radii[ring]; + outY = center.second + std::sin(angle) * radii[ring]; + ClampToRoom(outX, outY); + } + + Player* GetPlayerWithAura(uint32 spellId) + { + Group* group = bot->GetGroup(); + if (!group) + { + return nullptr; + } + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + Player* member = ref->GetSource(); + if (!member || !member->IsAlive()) + { + continue; + } + if (botAI->HasAura(spellId, member)) + { + return member; + } + } + return nullptr; + } + bool HasAuraInGroup(uint32 spellId) { return GetPlayerWithAura(spellId) != nullptr; } + bool HasDetonateMana(Player* player) + { + if (!player) + { + return false; + } + return botAI->HasAura(NaxxSpellIds::DetonateMana, player); + } + bool HasChains(Player* player) + { + if (!player) + { + return false; + } + return botAI->HasAura(NaxxSpellIds::ChainsOfKelthuzad, player); + } + + std::vector GetGuardians() const + { + std::vector guardians; + GuidVector targets = context->GetValue("possible targets")->Get(); + for (ObjectGuid const& guid : targets) + { + Unit* unit = botAI->GetUnit(guid); + if (!unit) + { + continue; + } + + if (!IsGuardian(unit)) + { + continue; + } + + if (unit->GetDistance2d(center.first, center.second) > (ROOM_MAX_RADIUS + 4.0f)) + { + continue; + } + + guardians.push_back(unit); + } + + return guardians; + } + + bool AllGuardiansOnAssistTank(Player* assistTank) const + { + if (!assistTank) + { + return true; + } + + std::vector guardians = GetGuardians(); + if (guardians.empty()) + { + return true; + } + + for (Unit* g : guardians) + { + if (!g) + { + continue; + } + + if (g->GetVictim() != assistTank) + { + return false; + } + } + return true; + } + + Unit* GetGuardianToPickup(Player* assistTank) const + { + if (!assistTank) + { + return nullptr; + } + + std::vector guardians = GetGuardians(); + if (guardians.empty()) + { + return nullptr; + } + + Unit* best = nullptr; + float bestDist = std::numeric_limits::max(); + for (Unit* g : guardians) + { + if (!g) + { + continue; + } + + if (g->GetVictim() == assistTank) + { + continue; + } + + float d = assistTank->GetDistance2d(g); + if (!best || d < bestDist) + { + best = g; + bestDist = d; + } + } + if (!best) + { + for (Unit* g : guardians) + { + float d = assistTank->GetDistance2d(g); + if (!best || d < bestDist) + { + best = g; + bestDist = d; + } + } + } + + return best; + } + + Unit* GetGuardian() + { + GuidVector targets = context->GetValue("possible targets")->Get(); + for (auto i = targets.begin(); i != targets.end(); ++i) + { + Unit* unit = botAI->GetUnit(*i); + if (!unit) + { + continue; + } + if (IsGuardian(unit)) + { + return unit; + } + } + return nullptr; + } + + Unit* GetGuardianForAssistTank(Player* assistTank) + { + if (!assistTank) + { + return nullptr; + } + + GuidVector targets = context->GetValue("possible targets")->Get(); + Unit* best = nullptr; + float bestScore = std::numeric_limits::max(); + + for (ObjectGuid const& guid : targets) + { + Unit* unit = botAI->GetUnit(guid); + if (!unit) + { + continue; + } + + if (!IsGuardian(unit)) + { + continue; + } + if (unit->GetDistance2d(center.first, center.second) > (ROOM_MAX_RADIUS + 4.0f)) + { + continue; + } + + Player* victimPlayer = unit->GetVictim() ? unit->GetVictim()->ToPlayer() : nullptr; + bool victimIsAssistTank = victimPlayer && botAI->IsAssistTank(victimPlayer); + + float score = unit->GetDistance2d(assistTank); + if (victimIsAssistTank) + { + score += 1000.0f; + } + + if (!best || score < bestScore) + { + best = unit; + bestScore = score; + } + } + + return best; + } + + Unit* GetAnyShadowFissure() + { + Unit* shadow_fissure = nullptr; + GuidVector units = *context->GetValue("nearest triggers"); + for (auto i = units.begin(); i != units.end(); i++) + { + Unit* unit = botAI->GetUnit(*i); + if (!unit) + continue; + if (botAI->EqualLowercaseName(unit->GetName(), "shadow fissure")) + { + shadow_fissure = unit; + } + } + return shadow_fissure; + } + +private: + void Reset() { _unit = nullptr; } + + Unit* _unit = nullptr; +}; + +class RazuviousBossHelper : public AiObject +{ +public: + RazuviousBossHelper(PlayerbotAI* botAI) : AiObject(botAI) {} + bool UpdateBossAI() + { + if (!bot->IsInCombat()) + { + Reset(); + } + if (_unit && (!_unit->IsInWorld() || !_unit->IsAlive())) + { + Reset(); + } + if (!_unit) + { + _unit = AI_VALUE2(Unit*, "find target", "instructor razuvious"); + } + return _unit != nullptr; + } + +private: + void Reset() { _unit = nullptr; } + + Unit* _unit = nullptr; +}; + +class SapphironBossHelper : public AiObject +{ +public: + const std::pair mainTankPos = {3512.07f, -5274.06f}; + const std::pair center = {3517.31f, -5253.74f}; + const float GENERIC_HEIGHT = 137.29f; + SapphironBossHelper(PlayerbotAI* botAI) : AiObject(botAI) {} + bool UpdateBossAI() + { + if (!bot->IsInCombat()) + { + Reset(); + } + if (_unit && (!_unit->IsInWorld() || !_unit->IsAlive())) + { + Reset(); + } + if (!_unit) + { + _unit = AI_VALUE2(Unit*, "find target", "sapphiron"); + if (!_unit) + { + return false; + } + } + bool now_flying = _unit->IsFlying(); + if (_was_flying && !now_flying) + { + _last_land_ms = getMSTime(); + } + _was_flying = now_flying; + UpdateIceboltState(); + return true; + } + bool IsPhaseGround() { return _unit && !_unit->IsFlying(); } + bool IsPhaseFlight() { return _unit && _unit->IsFlying(); } + bool JustLanded() + { + if (!_last_land_ms) + { + return false; + } + return getMSTime() - _last_land_ms <= POSITION_TIME_AFTER_LANDED; + } + bool WaitForExplosion() + { + if (!IsPhaseFlight()) + { + return false; + } + return HasIceboltInGroup(); + } + bool IsBreathWindow() + { + if (!IsPhaseFlight()) + { + return false; + } + if (IsBreathCasting()) + { + return true; + } + if (!_last_icebolt_ms) + { + return false; + } + uint32 elapsed = getMSTime() - _last_icebolt_ms; + return elapsed >= BREATH_MIN_MS && elapsed <= BREATH_MAX_MS; + } + bool HasLifeDrainInGroup() + { + Group* group = bot->GetGroup(); + if (!group) + { + return false; + } + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + Player* member = ref->GetSource(); + if (!member) + { + continue; + } + if (NaxxSpellIds::HasAnyAura(botAI, member, {NaxxSpellIds::LifeDrain}) || botAI->HasAura("life drain", member)) + { + return true; + } + } + return false; + } + bool FindPosToAvoidChill(std::vector& dest) + { + Aura* aura = NaxxSpellIds::GetAnyAura(bot, {NaxxSpellIds::Chill25}); + if (!aura) + { + aura = botAI->GetAura("chill", bot); + } + if (!aura) + { + return false; + } + /*DynamicObject* dyn_obj = aura->GetDynobjOwner(); + if (!dyn_obj)*/ + // Prefer the dynobject (classic ground effect), but keep a fallback for cases where + // the aura is applied by a moving caster (e.g. Blizzard NPC) without a dynobject. + WorldObject* source = aura->GetDynobjOwner(); + if (!source) + { + //return false; + if (Unit* caster = ObjectAccessor::GetUnit(*bot, aura->GetCasterGUID())) + { + source = caster; + } + } + if (!source) + { + return false; + } + Unit* currentTarget = AI_VALUE(Unit*, "current target"); + float angle = 0; + uint32 index = botAI->GetGroupSlotIndex(bot); + if (currentTarget) + { + if (botAI->IsRanged(bot)) + { + if (bot->GetExactDist2d(currentTarget) <= 45.0f) + { + angle = bot->GetAngle(source) - M_PI + (rand_norm() - 0.5) * M_PI / 2; + } + else + { + if (index % 2 == 0) + { + angle = bot->GetAngle(currentTarget) + M_PI / 2; + } + else + { + angle = bot->GetAngle(currentTarget) - M_PI / 2; + } + } + } + else + { + if (index % 3 == 0) + { + angle = bot->GetAngle(currentTarget); + } + else if (index % 3 == 1) + { + angle = bot->GetAngle(currentTarget) + M_PI / 2; + } + else + { + angle = bot->GetAngle(currentTarget) - M_PI / 2; + } + } + } + else + { + angle = bot->GetAngle(source) - M_PI + (rand_norm() - 0.5) * M_PI / 2; + } + dest = {bot->GetPositionX() + cos(angle) * 5.0f, bot->GetPositionY() + sin(angle) * 5.0f, bot->GetPositionZ()}; + return true; + } + +private: + void Reset() + { + _unit = nullptr; + _was_flying = false; + _last_land_ms = 0; + _last_icebolt_ms = 0; + } + + const uint32 POSITION_TIME_AFTER_LANDED = 5000; + const uint32 BREATH_MIN_MS = 1000; + const uint32 BREATH_MAX_MS = 12000; + bool HasIceboltInGroup() + { + Group* group = bot->GetGroup(); + if (!group) + { + return false; + } + bool hasIcebolt = false; + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + Player* member = ref->GetSource(); + if (!member) + { + continue; + } + if (NaxxSpellIds::HasAnyAura(botAI, member, {NaxxSpellIds::Icebolt10, NaxxSpellIds::Icebolt25}) || + botAI->HasAura("icebolt", member, false, false, -1, true)) + { + hasIcebolt = true; + break; + } + } + if (hasIcebolt) + { + _last_icebolt_ms = getMSTime(); + } + return hasIcebolt; + } + void UpdateIceboltState() + { + if (!IsPhaseFlight()) + { + _last_icebolt_ms = 0; + return; + } + HasIceboltInGroup(); + } + bool IsBreathCasting() + { + if (!_unit || !_unit->HasUnitState(UNIT_STATE_CASTING)) + { + return false; + } + Spell* spell = _unit->GetCurrentSpell(CURRENT_GENERIC_SPELL); + if (!spell) + { + spell = _unit->GetCurrentSpell(CURRENT_CHANNELED_SPELL); + } + if (!spell) + { + return false; + } + SpellInfo const* info = spell->GetSpellInfo(); + return NaxxSpellIds::MatchesAnySpellId(info, {NaxxSpellIds::FrostMissile, NaxxSpellIds::FrostExplosion}); + } + + Unit* _unit = nullptr; + bool _was_flying = false; + uint32 _last_land_ms = 0; + uint32 _last_icebolt_ms = 0; +}; + +class GluthBossHelper : public AiObject +{ +public: + const std::pair mainTankPos25 = {3331.48f, -3109.06f}; + const std::pair mainTankPos10 = {3278.29f, -3162.06f}; + const std::pair beforeDecimatePos = {3267.34f, -3175.68f}; + const std::pair leftSlowDownPos = {3290.68f, -3141.65f}; + const std::pair rightSlowDownPos = {3300.78f, -3151.98f}; + const std::pair rangedPos = {3301.45f, -3139.29f}; + const std::pair healPos = {3303.09f, -3135.24f}; + + const float decimatedZombiePct = 10.0f; + GluthBossHelper(PlayerbotAI* botAI) : AiObject(botAI) {} + bool UpdateBossAI() + { + if (!bot->IsInCombat()) + { + Reset(); + } + if (_unit && (!_unit->IsInWorld() || !_unit->IsAlive())) + { + Reset(); + } + if (!_unit) + { + _unit = AI_VALUE2(Unit*, "find target", "gluth"); + if (!_unit) + { + return false; + } + } + if (_unit->IsInCombat()) + { + if (_combat_start_ms == 0) + { + _combat_start_ms = getMSTime(); + } + } + else + { + _combat_start_ms = 0; + } + return true; + } + bool BeforeDecimate() + { + if (!_unit || !_unit->HasUnitState(UNIT_STATE_CASTING)) + { + return false; + } + Spell* spell = _unit->GetCurrentSpell(CURRENT_GENERIC_SPELL); + if (!spell) + { + spell = _unit->GetCurrentSpell(CURRENT_CHANNELED_SPELL); + } + if (!spell) + { + return false; + } + SpellInfo const* info = spell->GetSpellInfo(); + if (!info) + { + return false; + } + if (NaxxSpellIds::MatchesAnySpellId( + info, {NaxxSpellIds::Decimate10, NaxxSpellIds::Decimate25, NaxxSpellIds::Decimate25Alt})) + { + return true; + } + + return info->SpellName[LOCALE_enUS] && botAI->EqualLowercaseName(info->SpellName[LOCALE_enUS], "decimate"); + } + bool JustStartCombat() const { return _combat_start_ms != 0 && getMSTime() - _combat_start_ms < 10000; } + bool IsZombieChow(Unit* unit) const { return unit && botAI->EqualLowercaseName(unit->GetName(), "zombie chow"); } + +private: + void Reset() + { + _unit = nullptr; + _combat_start_ms = 0; + } + + Unit* _unit = nullptr; + uint32 _combat_start_ms = 0; +}; + +class LoathebBossHelper : public AiObject +{ +public: + const std::pair mainTankPos = {2910.1597f, -4010.0f}; + const std::pair rangePos = {2896.96f, -3980.61f}; + LoathebBossHelper(PlayerbotAI* botAI) : AiObject(botAI) {} + Unit* GetBoss() const { return _unit; } + bool UpdateBossAI() + { + if (!bot->IsInCombat()) + { + Reset(); + } + if (_unit && (!_unit->IsInWorld() || !_unit->IsAlive())) + { + Reset(); + } + if (!_unit) + { + _unit = AI_VALUE2(Unit*, "find target", "loatheb"); + } + return _unit != nullptr; + } + +private: + void Reset() { _unit = nullptr; } + + Unit* _unit = nullptr; +}; + +class NothBossHelper : public AiObject +{ +public: + const std::pair center = {2684.94f, -3502.53f}; + NothBossHelper(PlayerbotAI* botAI) : AiObject(botAI) {} + bool UpdateBossAI() + { + if (!bot->IsInCombat()) + { + Reset(); + } + if (_unit && (!_unit->IsInWorld() || !_unit->IsAlive())) + { + Reset(); + } + if (!_unit) + { + _unit = AI_VALUE2(Unit*, "find target", "noth the plaguebringer"); + } + if (!_unit) + { + return false; + } + if (_unit->HasUnitState(UNIT_STATE_CASTING)) + { + Spell* spell = _unit->GetCurrentSpell(CURRENT_GENERIC_SPELL); + if (!spell) + { + spell = _unit->GetCurrentSpell(CURRENT_CHANNELED_SPELL); + } + if (spell) + { + SpellInfo const* info = spell->GetSpellInfo(); + bool isBlink = NaxxSpellIds::MatchesAnySpellId(info, {NaxxSpellIds::Blink}); + if (!isBlink && info && info->SpellName[LOCALE_enUS]) + { + isBlink = botAI->EqualLowercaseName(info->SpellName[LOCALE_enUS], "blink"); + } + if (isBlink) + { + _last_blink_ms = getMSTime(); + } + } + } + return true; + } + bool IsBalconyPhase() const { return _unit && _unit->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE); } + bool IsBlinkWindow() const { return _last_blink_ms != 0 && getMSTime() - _last_blink_ms < 3000; } + bool HasCurseInGroup() const + { + GuidVector members = AI_VALUE(GuidVector, "group members"); + for (ObjectGuid const& guid : members) + { + Unit* member = botAI->GetUnit(guid); + if (!member) + { + continue; + } + if (NaxxSpellIds::HasAnyAura(botAI, member, {NaxxSpellIds::CurseOfThePlaguebringer}) || + botAI->HasAura("curse of the plaguebringer", member)) + { + return true; + } + } + return false; + } + +private: + void Reset() + { + _unit = nullptr; + _last_blink_ms = 0; + } + + Unit* _unit = nullptr; + uint32 _last_blink_ms = 0; +}; + +class FourhorsemanBossHelper : public AiObject +{ +public: + const float posZ = 241.27f; + const std::pair attractPos[2] = {{2502.03f, -2910.90f}, + {2484.61f, -2947.07f}}; // left (sir zeliek), right (lady blaumeux) + FourhorsemanBossHelper(PlayerbotAI* botAI) : AiObject(botAI) {} + bool UpdateBossAI() + { + if (!bot->IsInCombat()) + { + Reset(); + } + else if (_combat_start_ms == 0) + { + _combat_start_ms = getMSTime(); + } + if (_sir && (!_sir->IsInWorld() || !_sir->IsAlive())) + { + Reset(); + } + if (!_sir) + { + _sir = AI_VALUE2(Unit*, "find target", "sir zeliek"); + if (!_sir) + { + return false; + } + } + _lady = AI_VALUE2(Unit*, "find target", "lady blaumeux"); + return true; + } + void Reset() + { + _sir = nullptr; + _lady = nullptr; + _combat_start_ms = 0; + posToGo = 0; + } + bool IsAttracter(Player* bot) + { + Difficulty diff = bot->GetRaidDifficulty(); + if (diff == RAID_DIFFICULTY_25MAN_NORMAL) + { + return botAI->IsAssistRangedDpsOfIndex(bot, 0) || botAI->IsAssistHealOfIndex(bot, 0) || + botAI->IsAssistHealOfIndex(bot, 1) || botAI->IsAssistHealOfIndex(bot, 2); + } + return botAI->IsAssistRangedDpsOfIndex(bot, 0) || botAI->IsAssistHealOfIndex(bot, 0); + } + void CalculatePosToGo(Player* bot) + { + bool raid25 = bot->GetRaidDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL; + Unit* lady = _lady; + if (!lady) + { + posToGo = 0; + } + else + { + uint32 elapsed_ms = _combat_start_ms ? getMSTime() - _combat_start_ms : 0; + // Interval: 24s - 15s - 15s - ... + posToGo = !(elapsed_ms <= 9000 || ((elapsed_ms - 9000) / 67500) % 2 == 0); + if (botAI->IsAssistRangedDpsOfIndex(bot, 0) || (raid25 && botAI->IsAssistHealOfIndex(bot, 1))) + { + posToGo = 1 - posToGo; + } + } + } + std::pair CurrentAttractPos() + { + bool raid25 = bot->GetRaidDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL; + float posX = attractPos[posToGo].first, posY = attractPos[posToGo].second; + if (posToGo == 1) + { + float offset_x = 0.0f; + float offset_y = 0.0f; + float bias = 4.5f; + if (raid25) + { + offset_x = -bias; + offset_y = bias; + } + posX += offset_x; + posY += offset_y; + } + return {posX, posY}; + } + Unit* CurrentAttackTarget() + { + if (posToGo == 0) + { + return _sir; + } + return _lady; + } + +protected: + Unit* _sir = nullptr; + Unit* _lady = nullptr; + uint32 _combat_start_ms = 0; + int posToGo = 0; +}; +class ThaddiusBossHelper : public AiObject +{ +public: + const std::pair tankPosFeugen = {3522.94f, -3002.60f}; + const std::pair tankPosStalagg = {3436.14f, -2919.98f}; + const std::pair rangedPosFeugen = {3500.45f, -2997.92f}; + const std::pair rangedPosStalagg = {3441.01f, -2942.04f}; + const float tankPosZ = 312.61f; + ThaddiusBossHelper(PlayerbotAI* botAI) : AiObject(botAI) {} + bool UpdateBossAI() + { + if (!bot->IsInCombat()) + { + Reset(); + } + if (_unit && (!_unit->IsInWorld() || !_unit->IsAlive())) + { + Reset(); + } + if (!_unit) + { + _unit = AI_VALUE2(Unit*, "find target", "thaddius"); + if (!_unit) + { + return false; + } + } + feugen = AI_VALUE2(Unit*, "find target", "feugen"); + stalagg = AI_VALUE2(Unit*, "find target", "stalagg"); + return true; + } + bool IsPhasePet() { return (feugen && feugen->IsAlive()) || (stalagg && stalagg->IsAlive()); } + bool IsPhaseTransition() + { + if (IsPhasePet()) + { + return false; + } + return _unit && _unit->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + } + bool IsPhaseThaddius() { return !IsPhasePet() && !IsPhaseTransition(); } + Unit* GetNearestPet() + { + Unit* unit = nullptr; + if (feugen && feugen->IsAlive()) + { + unit = feugen; + } + if (stalagg && stalagg->IsAlive() && (!feugen || bot->GetDistance(stalagg) < bot->GetDistance(feugen))) + { + unit = stalagg; + } + return unit; + } + std::pair PetPhaseGetPosForTank() + { + if (GetNearestPet() == feugen) + { + return tankPosFeugen; + } + return tankPosStalagg; + } + std::pair PetPhaseGetPosForRanged() + { + if (GetNearestPet() == feugen) + { + return rangedPosFeugen; + } + return rangedPosStalagg; + } + +protected: + void Reset() + { + _unit = nullptr; + feugen = nullptr; + stalagg = nullptr; + } + + Unit* _unit = nullptr; + Unit* feugen = nullptr; + Unit* stalagg = nullptr; +}; + +#endif diff --git a/src/Ai/Raid/Naxxramas/RaidNaxxSpellIds.h b/src/Ai/Raid/Naxxramas/RaidNaxxSpellIds.h new file mode 100644 index 0000000000..aee430e2c7 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/RaidNaxxSpellIds.h @@ -0,0 +1,174 @@ +#ifndef _PLAYERBOT_RAIDNAXXSPELLIDS_H +#define _PLAYERBOT_RAIDNAXXSPELLIDS_H + +#include + +#include "PlayerbotAI.h" + +// use src/server/scripts/Northrend/Naxxramas/naxxramas.h for CreatureId, NaxxramasSay, NaxxramasEvent, NaxxramasMisc +namespace NaxxSpellIds +{ + // Grand Widow Faerlina + static constexpr uint32 FaerlinaFrenzy = 28798; + static constexpr uint32 FaerlinaWidowsEmbrace = 28732; + + // Maexxna + static constexpr uint32 MaexxnaWebWrapStun = 28622; + static constexpr uint32 MaexxnaWebWrapEntry = 16486; + static constexpr uint32 MaexxnaSpiderlingEntry = 17055; + + // Gothik the Harvester + static constexpr float GothikGateY = -3360.78f; + static constexpr uint32 GothikLivingTraineeEntry = 16124; + static constexpr uint32 GothikLivingKnightEntry = 16125; + static constexpr uint32 GothikLivingRiderEntry = 16126; + static constexpr uint32 GothikDeadTraineeEntry = 16127; + static constexpr uint32 GothikDeadKnightEntry = 16148; + static constexpr uint32 GothikDeadHorseEntry = 16149; + static constexpr uint32 GothikDeadRiderEntry = 16150; + + // Heigan + static constexpr uint32 Eruption10 = 29371; +/* + SPELL_SPELL_DISRUPTION = 29310, + SPELL_DECREPIT_FEVER = 29998, + SPELL_PLAGUE_CLOUD = 29350, + SPELL_TELEPORT_SELF = 30211 +*/ + + // Grobbulus + static constexpr uint32 PoisonCloud = 28240; + + // Noth the Plaguebringer + static constexpr uint32 CurseOfThePlaguebringer = 29213; + static constexpr uint32 Cripple = 29212; + static constexpr uint32 Blink = 29208; + + // Thaddius polarity + static constexpr uint32 PositiveCharge10 = 28059; + static constexpr uint32 PositiveCharge25 = 28062; + static constexpr uint32 PositiveChargeStack = 29659; + static constexpr uint32 NegativeCharge10 = 28084; + static constexpr uint32 NegativeCharge25 = 28085; + static constexpr uint32 NegativeChargeStack = 29660; +/* + SPELL_MAGNETIC_PULL = 28337, + SPELL_TESLA_SHOCK = 28099, + SPELL_SHOCK_VISUAL = 28159, + + // Stalagg + SPELL_POWER_SURGE = 54529, + SPELL_STALAGG_CHAIN = 28096, + + // Feugen + SPELL_STATIC_FIELD = 28135, + SPELL_FEUGEN_CHAIN = 28111, + + // Thaddius + SPELL_POLARITY_SHIFT = 28089, + SPELL_BALL_LIGHTNING = 28299, + SPELL_CHAIN_LIGHTNING = 28167, + SPELL_BERSERK = 27680, + SPELL_THADDIUS_VISUAL_LIGHTNING = 28136, + SPELL_THADDIUS_SPAWN_STUN = 28160, + + SPELL_POSITIVE_CHARGE = 28062, + SPELL_POSITIVE_CHARGE_STACK = 29659, + SPELL_NEGATIVE_CHARGE = 28085, + SPELL_NEGATIVE_CHARGE_STACK = 29660, + SPELL_POSITIVE_POLARITY = 28059, + SPELL_NEGATIVE_POLARITY = 28084 +*/ + // Sapphiron + static constexpr uint32 Icebolt10 = 28522; + static constexpr uint32 Icebolt25 = 28526; + //static constexpr uint32 Chill25 = 55699; + static constexpr uint32 Chill25 = 28547; + static constexpr uint32 LifeDrain = 28542; + static constexpr uint32 FrostMissile = 30101; + static constexpr uint32 FrostExplosion = 28524; + + // Kel'Thuzad + static constexpr uint32 FrostBlast = 27808; + static constexpr uint32 DetonateMana = 27819; + static constexpr uint32 ChainsOfKelthuzad = 28410; + static constexpr uint32 ShadowFissure = 27810; + static constexpr uint32 FrostBoltSingle = 28478; + static constexpr uint32 FrostBoltMulti = 28479; + + // Gluth + static constexpr uint32 Decimate10 = 28374; + static constexpr uint32 Decimate25 = 54426; + static constexpr uint32 Decimate25Alt = 28375; + static constexpr uint32 MortalWound10 = 25646; + static constexpr uint32 MortalWound25 = 54378; +/* + SPELL_MORTAL_WOUND = 25646, + SPELL_ENRAGE = 28371, + SPELL_DECIMATE = 28374, + SPELL_DECIMATE_DAMAGE = 28375, + SPELL_BERSERK = 26662, + SPELL_INFECTED_WOUND = 29306, + SPELL_CHOW_SEARCHER = 28404 +*/ + // Anub'Rekhan + static constexpr uint32 LocustSwarm10 = 28785; + static constexpr uint32 LocustSwarm10Alt = 28786; + static constexpr uint32 LocustSwarm25 = 54021; // 25-man Locust Swarm + + // Loatheb + static constexpr uint32 NecroticAura10 = 55593; + + inline bool HasAnyAura(PlayerbotAI* botAI, Unit* unit, std::initializer_list spellIds) + { + if (!botAI || !unit) + { + return false; + } + + for (uint32 spellId : spellIds) + { + if (botAI->HasAura(spellId, unit)) + { + return true; + } + } + return false; + } + + inline Aura* GetAnyAura(Unit* unit, std::initializer_list spellIds) + { + if (!unit) + { + return nullptr; + } + + for (uint32 spellId : spellIds) + { + if (Aura* aura = unit->GetAura(spellId)) + { + return aura; + } + } + return nullptr; + } + + inline bool MatchesAnySpellId(SpellInfo const* info, std::initializer_list spellIds) + { + if (!info) + { + return false; + } + + for (uint32 spellId : spellIds) + { + if (info->Id == spellId) + { + return true; + } + } + return false; + } +} // namespace NaxxSpellIds + +#endif \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/RaidNaxxTriggerContext.h b/src/Ai/Raid/Naxxramas/RaidNaxxTriggerContext.h new file mode 100644 index 0000000000..5295b5fa08 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/RaidNaxxTriggerContext.h @@ -0,0 +1,103 @@ +// /* +// * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license, you may redistribute it +// and/or modify it under version 3 of the License, or (at your option), any later version. +// */ + +#ifndef _PLAYERBOT_RAIDNAXXTRIGGERCONTEXT_H +#define _PLAYERBOT_RAIDNAXXTRIGGERCONTEXT_H + +#include "AiObjectContext.h" +#include "NamedObjectContext.h" +#include "RaidNaxxTriggers.h" + +class RaidNaxxTriggerContext : public NamedObjectContext +{ +public: + RaidNaxxTriggerContext() + { + creators["mutating injection melee"] = &RaidNaxxTriggerContext::mutating_injection_melee; + creators["mutating injection ranged"] = &RaidNaxxTriggerContext::mutating_injection_ranged; + creators["mutating injection removed"] = &RaidNaxxTriggerContext::mutating_injection_removed; + creators["grobbulus cloud"] = &RaidNaxxTriggerContext::grobbulus_cloud; + + creators["heigan melee"] = &RaidNaxxTriggerContext::heigan_melee; + creators["heigan ranged"] = &RaidNaxxTriggerContext::heigan_ranged; + + creators["thaddius phase pet"] = &RaidNaxxTriggerContext::thaddius_phase_pet; + creators["thaddius phase pet lose aggro"] = &RaidNaxxTriggerContext::thaddius_phase_pet_lose_aggro; + creators["thaddius phase transition"] = &RaidNaxxTriggerContext::thaddius_phase_transition; + creators["thaddius phase thaddius"] = &RaidNaxxTriggerContext::thaddius_phase_thaddius; + + creators["razuvious tank"] = &RaidNaxxTriggerContext::razuvious_tank; + creators["razuvious nontank"] = &RaidNaxxTriggerContext::razuvious_nontank; + + creators["horseman attractors"] = &RaidNaxxTriggerContext::horseman_attractors; + creators["horseman except attractors"] = &RaidNaxxTriggerContext::horseman_except_attractors; + + creators["sapphiron ground"] = &RaidNaxxTriggerContext::sapphiron_ground; + creators["sapphiron flight"] = &RaidNaxxTriggerContext::sapphiron_flight; + + creators["kel'thuzad"] = &RaidNaxxTriggerContext::kelthuzad; + + creators["anub'rekhan"] = &RaidNaxxTriggerContext::anubrekhan; + + creators["faerlina"] = &RaidNaxxTriggerContext::faerlina; + creators["faerlina frenzy"] = &RaidNaxxTriggerContext::faerlina_frenzy; + + creators["maexxna"] = &RaidNaxxTriggerContext::maexxna; + creators["maexxna web wrap"] = &RaidNaxxTriggerContext::maexxna_web_wrap; + creators["maexxna spiderlings"] = &RaidNaxxTriggerContext::maexxna_spiderlings; + + creators["gothik move to assigned side"] = &RaidNaxxTriggerContext::gothik_move_to_assigned_side; + creators["gothik choose target"] = &RaidNaxxTriggerContext::gothik_choose_target; + + creators["patchwerk tank"] = &RaidNaxxTriggerContext::patchwerk_tank; + creators["patchwerk non-tank"] = &RaidNaxxTriggerContext::patchwerk_non_tank; + creators["patchwerk ranged"] = &RaidNaxxTriggerContext::patchwerk_ranged; + + creators["gluth"] = &RaidNaxxTriggerContext::gluth; + creators["gluth main tank mortal wound"] = &RaidNaxxTriggerContext::gluth_main_tank_mortal_wound; + + creators["loatheb"] = &RaidNaxxTriggerContext::loatheb; + creators["noth"] = &RaidNaxxTriggerContext::noth; + } + +private: + static Trigger* mutating_injection_melee(PlayerbotAI* ai) { return new MutatingInjectionMeleeTrigger(ai); } + static Trigger* mutating_injection_ranged(PlayerbotAI* ai) { return new MutatingInjectionRangedTrigger(ai); } + static Trigger* mutating_injection_removed(PlayerbotAI* ai) { return new MutatingInjectionRemovedTrigger(ai); } + static Trigger* grobbulus_cloud(PlayerbotAI* ai) { return new GrobbulusCloudTrigger(ai); } + static Trigger* heigan_melee(PlayerbotAI* ai) { return new HeiganMeleeTrigger(ai); } + static Trigger* heigan_ranged(PlayerbotAI* ai) { return new HeiganRangedTrigger(ai); } + + static Trigger* thaddius_phase_pet(PlayerbotAI* ai) { return new ThaddiusPhasePetTrigger(ai); } + static Trigger* thaddius_phase_pet_lose_aggro(PlayerbotAI* ai) { return new ThaddiusPhasePetLoseAggroTrigger(ai); } + static Trigger* thaddius_phase_transition(PlayerbotAI* ai) { return new ThaddiusPhaseTransitionTrigger(ai); } + static Trigger* thaddius_phase_thaddius(PlayerbotAI* ai) { return new ThaddiusPhaseThaddiusTrigger(ai); } + static Trigger* razuvious_tank(PlayerbotAI* ai) { return new RazuviousTankTrigger(ai); } + static Trigger* razuvious_nontank(PlayerbotAI* ai) { return new RazuviousNontankTrigger(ai); } + + static Trigger* horseman_attractors(PlayerbotAI* ai) { return new HorsemanAttractorsTrigger(ai); } + static Trigger* horseman_except_attractors(PlayerbotAI* ai) { return new HorsemanExceptAttractorsTrigger(ai); } + + static Trigger* sapphiron_ground(PlayerbotAI* ai) { return new SapphironGroundTrigger(ai); } + static Trigger* sapphiron_flight(PlayerbotAI* ai) { return new SapphironFlightTrigger(ai); } + static Trigger* kelthuzad(PlayerbotAI* ai) { return new KelthuzadTrigger(ai); } + static Trigger* anubrekhan(PlayerbotAI* ai) { return new AnubrekhanTrigger(ai); } + static Trigger* faerlina(PlayerbotAI* ai) { return new FaerlinaTrigger(ai); } + static Trigger* faerlina_frenzy(PlayerbotAI* ai) { return new FaerlinaFrenzyTrigger(ai); } + static Trigger* maexxna(PlayerbotAI* ai) { return new MaexxnaTrigger(ai); } + static Trigger* maexxna_web_wrap(PlayerbotAI* ai) { return new MaexxnaWebWrapTrigger(ai); } + static Trigger* maexxna_spiderlings(PlayerbotAI* ai) { return new MaexxnaSpiderlingsTrigger(ai); } + static Trigger* gothik_move_to_assigned_side(PlayerbotAI* ai) { return new GothikMoveToAssignedSideTrigger(ai); } + static Trigger* gothik_choose_target(PlayerbotAI* ai) { return new GothikChooseTargetTrigger(ai); } + static Trigger* patchwerk_tank(PlayerbotAI* ai) { return new PatchwerkTankTrigger(ai); } + static Trigger* patchwerk_non_tank(PlayerbotAI* ai) { return new PatchwerkNonTankTrigger(ai); } + static Trigger* patchwerk_ranged(PlayerbotAI* ai) { return new PatchwerkRangedTrigger(ai); } + static Trigger* gluth(PlayerbotAI* ai) { return new GluthTrigger(ai); } + static Trigger* gluth_main_tank_mortal_wound(PlayerbotAI* ai) { return new GluthMainTankMortalWoundTrigger(ai); } + static Trigger* loatheb(PlayerbotAI* ai) { return new LoathebTrigger(ai); } + static Trigger* noth(PlayerbotAI* ai) { return new NothTrigger(ai); } +}; + +#endif \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Strategy/RaidNaxxStrategy.cpp b/src/Ai/Raid/Naxxramas/Strategy/RaidNaxxStrategy.cpp new file mode 100644 index 0000000000..7021d84441 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Strategy/RaidNaxxStrategy.cpp @@ -0,0 +1,191 @@ +#include "RaidNaxxStrategy.h" + +#include "RaidNaxxMultipliers.h" + +void RaidNaxxStrategy::InitTriggers(std::vector& triggers) +{ + // Grobbulus + triggers.push_back(new TriggerNode("mutating injection melee", + { NextAction("grobbulus move away", ACTION_RAID + 2) } + )); + + triggers.push_back(new TriggerNode("mutating injection ranged", + { NextAction("grobbulus go behind the boss", ACTION_RAID + 2) } + )); + + triggers.push_back(new TriggerNode("mutating injection removed", + { NextAction("grobbulus move center", ACTION_RAID + 1) } + )); + + triggers.push_back(new TriggerNode("grobbulus cloud", + { NextAction("rotate grobbulus", ACTION_RAID + 1) } + )); + + // Heigan the Unclean + triggers.push_back(new TriggerNode("heigan melee", + { NextAction("heigan dance melee", ACTION_RAID + 1) } + )); + + triggers.push_back(new TriggerNode("heigan ranged", + { NextAction("heigan dance ranged", ACTION_RAID + 1) } + )); + + // Kel'Thuzad + triggers.push_back( + new TriggerNode("kel'thuzad", + { + NextAction("kel'thuzad position", ACTION_RAID + 2), + NextAction("kel'thuzad choose target", ACTION_RAID + 1) + }) + ); + + // Anub'Rekhan + triggers.push_back(new TriggerNode("anub'rekhan", + { + NextAction("anub'rekhan position", ACTION_RAID + 2), + NextAction("anub'rekhan choose target", ACTION_RAID + 1) + } + )); + + // Grand Widow Faerlina + triggers.push_back(new TriggerNode("faerlina", + { NextAction("avoid aoe", ACTION_RAID + 1) } + )); + + triggers.push_back(new TriggerNode("faerlina frenzy", + { + NextAction("tranquilizing shot", ACTION_RAID + 4), + NextAction("faerlina sacrifice worshipper", ACTION_RAID + 3) + } + )); + + // Maexxna + triggers.push_back(new TriggerNode("maexxna web wrap", + { NextAction("maexxna attack web wrap", ACTION_RAID + 5) } + )); + + triggers.push_back(new TriggerNode("maexxna spiderlings", + { NextAction("maexxna tank spiderlings", ACTION_RAID + 2) } + )); + + triggers.push_back( + new TriggerNode("maexxna", + { + NextAction("rear flank", ACTION_RAID + 1), + NextAction("avoid aoe", ACTION_RAID + 1) + }) + ); + + // Gothik the Harvester + triggers.push_back(new TriggerNode("gothik move to assigned side", + { NextAction("gothik move to assigned side", ACTION_RAID + 4) } + )); + + triggers.push_back(new TriggerNode("gothik choose target", + { NextAction("gothik choose target", ACTION_RAID + 1) } + )); + + // Patchwerk + triggers.push_back(new TriggerNode("patchwerk tank", + { NextAction("tank face", ACTION_RAID + 2) } + )); + + triggers.push_back(new TriggerNode("patchwerk ranged", + { NextAction("patchwerk ranged position", ACTION_RAID + 2) } + )); + + triggers.push_back(new TriggerNode("patchwerk non-tank", + { NextAction("rear flank", ACTION_RAID + 1) } + )); + + // Thaddius + triggers.push_back(new TriggerNode("thaddius phase pet", + { NextAction("thaddius attack nearest pet", ACTION_RAID + 1) } + )); + + triggers.push_back(new TriggerNode("thaddius phase pet lose aggro", + { NextAction("taunt spell", ACTION_RAID + 2) } + )); + + triggers.push_back(new TriggerNode("thaddius phase transition", + { NextAction("thaddius move to platform", ACTION_RAID + 1) } + )); + + triggers.push_back(new TriggerNode("thaddius phase thaddius", + { NextAction("thaddius move polarity", ACTION_RAID + 1) } + )); + + // Instructor Razuvious + triggers.push_back(new TriggerNode("razuvious tank", + { NextAction("razuvious use obedience crystal", ACTION_RAID + 1) } + )); + + triggers.push_back(new TriggerNode("razuvious nontank", + { NextAction("razuvious target", ACTION_RAID + 1) } + )); + + // four horseman + triggers.push_back(new TriggerNode("horseman attractors", + { NextAction("horseman attract alternatively", ACTION_RAID + 1) } + )); + + triggers.push_back(new TriggerNode("horseman except attractors", + { NextAction("horseman attack in order", ACTION_RAID + 1) } + )); + + // sapphiron + triggers.push_back(new TriggerNode("sapphiron ground", + { NextAction("sapphiron ground position", ACTION_RAID + 1) } + )); + + triggers.push_back(new TriggerNode("sapphiron flight", + { NextAction("sapphiron flight position", ACTION_RAID + 1) } + )); + + // Gluth + triggers.push_back( + new TriggerNode("gluth", + { + NextAction("gluth choose target", ACTION_RAID + 1), + NextAction("gluth position", ACTION_RAID + 1), + NextAction("gluth slowdown", ACTION_RAID) + }) + ); + + triggers.push_back(new TriggerNode("gluth main tank mortal wound", + { NextAction("taunt spell", ACTION_RAID + 1) } + )); + + // Loatheb + triggers.push_back( + new TriggerNode("loatheb", + { + NextAction("loatheb position", ACTION_RAID + 1), + NextAction("loatheb choose target", ACTION_RAID + 1) + }) + ); + + // Noth the Plaguebringer + triggers.push_back( + new TriggerNode("noth", + { + NextAction("noth position", ACTION_RAID + 1), + NextAction("noth choose target", ACTION_RAID + 1) + }) + ); +} + +void RaidNaxxStrategy::InitMultipliers(std::vector& multipliers) +{ + multipliers.push_back(new GrobbulusMultiplier(botAI)); + multipliers.push_back(new HeiganDanceMultiplier(botAI)); + multipliers.push_back(new LoathebGenericMultiplier(botAI)); + multipliers.push_back(new ThaddiusGenericMultiplier(botAI)); + multipliers.push_back(new SapphironGenericMultiplier(botAI)); + multipliers.push_back(new InstructorRazuviousGenericMultiplier(botAI)); + multipliers.push_back(new KelthuzadGenericMultiplier(botAI)); + multipliers.push_back(new AnubrekhanGenericMultiplier(botAI)); + multipliers.push_back(new FourhorsemanGenericMultiplier(botAI)); + multipliers.push_back(new GluthGenericMultiplier(botAI)); + multipliers.push_back(new NothGenericMultiplier(botAI)); +} diff --git a/src/Ai/Raid/Naxxramas/Strategy/RaidNaxxStrategy.h b/src/Ai/Raid/Naxxramas/Strategy/RaidNaxxStrategy.h new file mode 100644 index 0000000000..dee1720bd8 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Strategy/RaidNaxxStrategy.h @@ -0,0 +1,18 @@ + +#ifndef _PLAYERBOT_RAIDNAXXSTRATEGY_H +#define _PLAYERBOT_RAIDNAXXSTRATEGY_H + +#include "AiObjectContext.h" +#include "Multiplier.h" +#include "Strategy.h" + +class RaidNaxxStrategy : public Strategy +{ +public: + RaidNaxxStrategy(PlayerbotAI* ai) : Strategy(ai) {} + virtual std::string const getName() override { return "naxx"; } + virtual void InitTriggers(std::vector& triggers) override; + virtual void InitMultipliers(std::vector& multipliers) override; +}; + +#endif \ No newline at end of file diff --git a/src/Ai/Raid/Naxxramas/Triggers/RaidNaxxTriggers.cpp b/src/Ai/Raid/Naxxramas/Triggers/RaidNaxxTriggers.cpp new file mode 100644 index 0000000000..59f0bb4e3d --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Triggers/RaidNaxxTriggers.cpp @@ -0,0 +1,395 @@ +#include "RaidNaxxTriggers.h" + +#include "Playerbots.h" +#include "RaidNaxxSpellIds.h" +#include "Timer.h" +#include "Trigger.h" + +bool MutatingInjectionMeleeTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "grobbulus"); + if (!boss) + { + return false; + } + return MutatingInjectionTrigger::IsActive() && !botAI->IsRanged(bot); +} + +bool MutatingInjectionRangedTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "grobbulus"); + if (!boss) + { + return false; + } + return MutatingInjectionTrigger::IsActive() && botAI->IsRanged(bot); +} + +bool AuraRemovedTrigger::IsActive() +{ + bool check = botAI->HasAura(name, bot, false, false, -1, true); + bool ret = false; + if (prev_check && !check) + { + ret = true; + } + prev_check = check; + return ret; +} + +bool MutatingInjectionRemovedTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "grobbulus"); + if (!boss) + { + return false; + } + return HasNoAuraTrigger::IsActive() && botAI->GetState() == BOT_STATE_COMBAT && botAI->IsRanged(bot); +} + +bool GrobbulusCloudTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "grobbulus"); + if (!boss) + { + return false; + } + if (!botAI->IsMainTank(bot)) + { + return false; + } + // bot->Yell("has aggro on " + boss->GetName() + " : " + to_string(AI_VALUE2(bool, "has aggro", "boss target")), + // LANG_UNIVERSAL); + if (!AI_VALUE2(bool, "has aggro", "boss target")) + { + return false; + } + uint32 now = getMSTime(); + bool poison_cloud_casting = false; + if (boss->HasUnitState(UNIT_STATE_CASTING)) + { + Spell* spell = boss->GetCurrentSpell(CURRENT_GENERIC_SPELL); + if (!spell) + { + spell = boss->GetCurrentSpell(CURRENT_CHANNELED_SPELL); + } + if (spell) + { + poison_cloud_casting = NaxxSpellIds::MatchesAnySpellId(spell->GetSpellInfo(), {NaxxSpellIds::PoisonCloud}); + } + } + if (!poison_cloud_casting && last_cloud_ms != 0 && now - last_cloud_ms < CloudRotationDelayMs) + { + return false; + } + last_cloud_ms = now; + return true; +} + +bool HeiganMeleeTrigger::IsActive() +{ + Unit* heigan = AI_VALUE2(Unit*, "find target", "heigan the unclean"); + if (!heigan) + { + return false; + } + return !botAI->IsRanged(bot); +} + +bool HeiganRangedTrigger::IsActive() +{ + Unit* heigan = AI_VALUE2(Unit*, "find target", "heigan the unclean"); + if (!heigan) + { + return false; + } + return botAI->IsRanged(bot); +} + +bool RazuviousTankTrigger::IsActive() +{ + Difficulty diff = bot->GetRaidDifficulty(); + if (diff == RAID_DIFFICULTY_10MAN_NORMAL) + { + return helper.UpdateBossAI() && botAI->IsTank(bot); + } + return helper.UpdateBossAI() && bot->getClass() == CLASS_PRIEST; +} + +bool RazuviousNontankTrigger::IsActive() +{ + Difficulty diff = bot->GetRaidDifficulty(); + if (diff == RAID_DIFFICULTY_10MAN_NORMAL) + { + return helper.UpdateBossAI() && !(botAI->IsTank(bot)); + } + return helper.UpdateBossAI() && !(bot->getClass() == CLASS_PRIEST); +} + +bool HorsemanAttractorsTrigger::IsActive() +{ + if (!helper.UpdateBossAI()) + { + return false; + } + return helper.IsAttracter(bot); +} + +bool HorsemanExceptAttractorsTrigger::IsActive() +{ + if (!helper.UpdateBossAI()) + { + return false; + } + return !helper.IsAttracter(bot); +} + +bool SapphironGroundTrigger::IsActive() +{ + if (!helper.UpdateBossAI()) + { + return false; + } + return helper.IsPhaseGround(); +} + +bool SapphironFlightTrigger::IsActive() +{ + if (!helper.UpdateBossAI()) + { + return false; + } + return helper.IsPhaseFlight(); +} + +bool GluthTrigger::IsActive() { return helper.UpdateBossAI(); } + +bool GluthMainTankMortalWoundTrigger::IsActive() +{ + if (!helper.UpdateBossAI()) + { + return false; + } + if (!botAI->IsAssistTankOfIndex(bot, 0)) + { + return false; + } + Unit* mt = AI_VALUE(Unit*, "main tank"); + if (!mt) + { + return false; + } + Aura* aura = NaxxSpellIds::GetAnyAura(mt, {NaxxSpellIds::MortalWound10, NaxxSpellIds::MortalWound25}); + if (!aura) + { + aura = botAI->GetAura("mortal wound", mt, false, true); + } + if (!aura || aura->GetStackAmount() < 5) + { + return false; + } + return true; +} + +bool KelthuzadTrigger::IsActive() { return helper.UpdateBossAI(); } + +bool AnubrekhanTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "anub'rekhan"); + if (!boss) + return false; + + return bot->IsInCombat() || boss->IsInCombat(); +} + +bool FaerlinaTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "grand widow faerlina"); + if (!boss) + { + return false; + } + return true; +} + +bool FaerlinaFrenzyTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "grand widow faerlina"); + if (!boss) + { + return false; + } + + // Only relevant during the actual encounter. + if (!bot->IsInCombat() && !boss->IsInCombat()) + { + return false; + } + + // Frenzy is handled either via a sacrifice (Widow's Embrace) or by removing the enrage. + if (boss->HasAura(NaxxSpellIds::FaerlinaWidowsEmbrace)) + { + return false; + } + + return boss->HasAura(NaxxSpellIds::FaerlinaFrenzy); +} + +bool MaexxnaTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "maexxna"); + if (!boss) + { + return false; + } + return !botAI->IsTank(bot); +} + +bool MaexxnaWebWrapTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "maexxna"); + if (!boss) + { + return false; + } + + // Only relevant during the actual encounter. + if (!bot->IsInCombat() && !boss->IsInCombat()) + { + return false; + } + + // Prefer ranged DPS/casters to break cocoons with minimal movement. + if (botAI->IsTank(bot) || botAI->IsHeal(bot) || !botAI->IsRanged(bot)) + { + return false; + } + + // If any member is web-wrapped, we want to break it. + if (Group* group = bot->GetGroup()) + { + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + Player* member = ref->GetSource(); + if (!member || !member->IsAlive()) + continue; + + if (botAI->HasAura(NaxxSpellIds::MaexxnaWebWrapStun, member)) + return true; + } + } + + // Or if the cocoon NPC exists in our target list. + static constexpr uint32 MaexxnaWebWrapEntry = 16486; + GuidVector targets = AI_VALUE(GuidVector, "possible targets no los"); + for (ObjectGuid const& guid : targets) + { + Unit* unit = botAI->GetUnit(guid); + if (unit && unit->GetEntry() == NaxxSpellIds::MaexxnaWebWrapEntry) + return true; + } + + return false; +} + +bool MaexxnaSpiderlingsTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "maexxna"); + if (!boss) + return false; + + if (!bot->IsInCombat() && !boss->IsInCombat()) + return false; + + if (!botAI->IsTank(bot) || botAI->IsMainTank(bot)) + return false; + + GuidVector attackers = AI_VALUE(GuidVector, "attackers"); + for (ObjectGuid const& guid : attackers) + { + Unit* unit = botAI->GetUnit(guid); + if (unit && unit->GetEntry() == NaxxSpellIds::MaexxnaSpiderlingEntry) + return true; + } + + return false; +} + +bool GothikMoveToAssignedSideTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "gothik the harvester"); + if (!boss) + return false; + + return bot->GetDistance(boss) <= 160.0f; +} + +bool GothikChooseTargetTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "gothik the harvester"); + if (!boss) + return false; + + return boss->IsInCombat() || bot->IsInCombat(); +} + +bool PatchwerkTankTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "patchwerk"); + if (!boss) + { + return false; + } + return !botAI->IsTank(bot) && !botAI->IsRanged(bot); +} + +bool PatchwerkRangedTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "patchwerk"); + if (!boss) + { + return false; + } + return !botAI->IsTank(bot) && botAI->IsRanged(bot); +} + +bool PatchwerkNonTankTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "patchwerk"); + if (!boss) + { + return false; + } + return !botAI->IsTank(bot); +} + +bool LoathebTrigger::IsActive() { return helper.UpdateBossAI(); } + +bool NothTrigger::IsActive() { return helper.UpdateBossAI(); } + +bool ThaddiusPhasePetTrigger::IsActive() +{ + if (!helper.UpdateBossAI()) + { + return false; + } + return helper.IsPhasePet(); +} + +bool ThaddiusPhaseTransitionTrigger::IsActive() +{ + if (!helper.UpdateBossAI()) + { + return false; + } + return helper.IsPhaseTransition(); +} + +bool ThaddiusPhaseThaddiusTrigger::IsActive() +{ + if (!helper.UpdateBossAI()) + { + return false; + } + return helper.IsPhaseThaddius(); +} diff --git a/src/Ai/Raid/Naxxramas/Triggers/RaidNaxxTriggers.h b/src/Ai/Raid/Naxxramas/Triggers/RaidNaxxTriggers.h new file mode 100644 index 0000000000..f14166edf7 --- /dev/null +++ b/src/Ai/Raid/Naxxramas/Triggers/RaidNaxxTriggers.h @@ -0,0 +1,303 @@ + +#ifndef _PLAYERBOT_RAIDNAXXTRIGGERS_H +#define _PLAYERBOT_RAIDNAXXTRIGGERS_H + +#include "EventMap.h" +#include "GenericTriggers.h" +#include "PlayerbotAIConfig.h" +#include "RaidNaxxBossHelper.h" +#include "Trigger.h" + +class MutatingInjectionTrigger : public HasAuraTrigger +{ +public: + MutatingInjectionTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "mutating injection", 1) {} +}; + +class MutatingInjectionMeleeTrigger : public MutatingInjectionTrigger +{ +public: + MutatingInjectionMeleeTrigger(PlayerbotAI* ai) : MutatingInjectionTrigger(ai) {} + bool IsActive() override; +}; + +class MutatingInjectionRangedTrigger : public MutatingInjectionTrigger +{ +public: + MutatingInjectionRangedTrigger(PlayerbotAI* ai) : MutatingInjectionTrigger(ai) {} + bool IsActive() override; +}; + +class AuraRemovedTrigger : public Trigger +{ +public: + AuraRemovedTrigger(PlayerbotAI* botAI, std::string name) : Trigger(botAI, name, 1) { this->prev_check = false; } + virtual bool IsActive() override; + +protected: + bool prev_check; +}; + +class MutatingInjectionRemovedTrigger : public HasNoAuraTrigger +{ +public: + MutatingInjectionRemovedTrigger(PlayerbotAI* ai) : HasNoAuraTrigger(ai, "mutating injection") {} + virtual bool IsActive(); +}; + +class GrobbulusCloudTrigger : public Trigger +{ +public: + GrobbulusCloudTrigger(PlayerbotAI* ai) : Trigger(ai, "grobbulus cloud event"), last_cloud_ms(0) {} + bool IsActive() override; + +private: + uint32 last_cloud_ms; + static constexpr uint32 CloudRotationDelayMs = 15000; +}; + +class HeiganMeleeTrigger : public Trigger +{ +public: + HeiganMeleeTrigger(PlayerbotAI* ai) : Trigger(ai, "heigan melee") {} + virtual bool IsActive(); +}; + +class HeiganRangedTrigger : public Trigger +{ +public: + HeiganRangedTrigger(PlayerbotAI* ai) : Trigger(ai, "heigan ranged") {} + bool IsActive() override; +}; + +class RazuviousTankTrigger : public Trigger +{ +public: + RazuviousTankTrigger(PlayerbotAI* ai) : Trigger(ai, "instructor razuvious tank"), helper(ai) {} + bool IsActive() override; + +private: + RazuviousBossHelper helper; +}; + +class RazuviousNontankTrigger : public Trigger +{ +public: + RazuviousNontankTrigger(PlayerbotAI* ai) : Trigger(ai, "instructor razuvious non-tank"), helper(ai) {} + bool IsActive() override; + +private: + RazuviousBossHelper helper; +}; + +class KelthuzadTrigger : public Trigger +{ +public: + KelthuzadTrigger(PlayerbotAI* ai) : Trigger(ai, "kel'thuzad trigger"), helper(ai) {} + bool IsActive() override; + +private: + KelthuzadBossHelper helper; +}; + +class AnubrekhanTrigger : public Trigger +{ +public: + AnubrekhanTrigger(PlayerbotAI* ai) : Trigger(ai, "anub'rekhan") {} + bool IsActive() override; +}; + + class FaerlinaTrigger : public Trigger + { + public: + FaerlinaTrigger(PlayerbotAI* ai) : Trigger(ai, "faerlina") {} + bool IsActive() override; + }; + +class FaerlinaFrenzyTrigger : public Trigger +{ +public: + FaerlinaFrenzyTrigger(PlayerbotAI* ai) : Trigger(ai, "faerlina frenzy") {} + bool IsActive() override; +}; + +class MaexxnaTrigger : public Trigger +{ +public: + MaexxnaTrigger(PlayerbotAI* ai) : Trigger(ai, "maexxna") {} + bool IsActive() override; +}; + +class MaexxnaWebWrapTrigger : public Trigger +{ +public: + MaexxnaWebWrapTrigger(PlayerbotAI* ai) : Trigger(ai, "maexxna web wrap") {} + bool IsActive() override; +}; + +class MaexxnaSpiderlingsTrigger : public Trigger +{ +public: + MaexxnaSpiderlingsTrigger(PlayerbotAI* ai) : Trigger(ai, "maexxna spiderlings") {} + bool IsActive() override; +}; + +class GothikMoveToAssignedSideTrigger : public Trigger +{ +public: + GothikMoveToAssignedSideTrigger(PlayerbotAI* ai) : Trigger(ai, "gothik move to assigned side") {} + bool IsActive() override; +}; + +class GothikChooseTargetTrigger : public Trigger +{ +public: + GothikChooseTargetTrigger(PlayerbotAI* ai) : Trigger(ai, "gothik choose target") {} + bool IsActive() override; +}; + +class PatchwerkTankTrigger : public Trigger +{ +public: + PatchwerkTankTrigger(PlayerbotAI* ai) : Trigger(ai, "patchwerk tank") {} + bool IsActive() override; +}; + +class PatchwerkNonTankTrigger : public Trigger +{ +public: + PatchwerkNonTankTrigger(PlayerbotAI* ai) : Trigger(ai, "patchwerk non-tank") {} + bool IsActive() override; +}; + +class PatchwerkRangedTrigger : public Trigger +{ +public: + PatchwerkRangedTrigger(PlayerbotAI* ai) : Trigger(ai, "patchwerk ranged") {} + bool IsActive() override; +}; + +class ThaddiusPhasePetTrigger : public Trigger +{ +public: + ThaddiusPhasePetTrigger(PlayerbotAI* ai) : Trigger(ai, "thaddius phase pet"), helper(ai) {} + bool IsActive() override; + +private: + ThaddiusBossHelper helper; +}; + +class ThaddiusPhasePetLoseAggroTrigger : public ThaddiusPhasePetTrigger +{ +public: + ThaddiusPhasePetLoseAggroTrigger(PlayerbotAI* ai) : ThaddiusPhasePetTrigger(ai) {} + virtual bool IsActive() + { + Unit* target = AI_VALUE(Unit*, "current target"); + return ThaddiusPhasePetTrigger::IsActive() && botAI->IsTank(bot) && target && target->GetVictim() != bot; + } +}; + +class ThaddiusPhaseTransitionTrigger : public Trigger +{ +public: + ThaddiusPhaseTransitionTrigger(PlayerbotAI* ai) : Trigger(ai, "thaddius phase transition"), helper(ai) {} + bool IsActive() override; + +private: + ThaddiusBossHelper helper; +}; + +class ThaddiusPhaseThaddiusTrigger : public Trigger +{ +public: + ThaddiusPhaseThaddiusTrigger(PlayerbotAI* ai) : Trigger(ai, "thaddius phase thaddius"), helper(ai) {} + bool IsActive() override; + +private: + ThaddiusBossHelper helper; +}; + +class HorsemanAttractorsTrigger : public Trigger +{ +public: + HorsemanAttractorsTrigger(PlayerbotAI* ai) : Trigger(ai, "fourhorsemen attractors"), helper(ai) {} + bool IsActive() override; + +private: + FourhorsemanBossHelper helper; +}; + +class HorsemanExceptAttractorsTrigger : public Trigger +{ +public: + HorsemanExceptAttractorsTrigger(PlayerbotAI* ai) : Trigger(ai, "fourhorsemen except attractors"), helper(ai) {} + bool IsActive() override; + +private: + FourhorsemanBossHelper helper; +}; + +class SapphironGroundTrigger : public Trigger +{ +public: + SapphironGroundTrigger(PlayerbotAI* ai) : Trigger(ai, "sapphiron ground"), helper(ai) {} + bool IsActive() override; + +private: + SapphironBossHelper helper; +}; + +class SapphironFlightTrigger : public Trigger +{ +public: + SapphironFlightTrigger(PlayerbotAI* ai) : Trigger(ai, "sapphiron flight"), helper(ai) {} + bool IsActive() override; + +private: + SapphironBossHelper helper; +}; + +class GluthTrigger : public Trigger +{ +public: + GluthTrigger(PlayerbotAI* ai) : Trigger(ai, "gluth trigger"), helper(ai) {} + bool IsActive() override; + +private: + GluthBossHelper helper; +}; + +class GluthMainTankMortalWoundTrigger : public Trigger +{ +public: + GluthMainTankMortalWoundTrigger(PlayerbotAI* ai) : Trigger(ai, "gluth main tank mortal wound trigger"), helper(ai) + { + } + bool IsActive() override; + +private: + GluthBossHelper helper; +}; + +class LoathebTrigger : public Trigger +{ +public: + LoathebTrigger(PlayerbotAI* ai) : Trigger(ai, "loatheb"), helper(ai) {} + bool IsActive() override; + +private: + LoathebBossHelper helper; +}; + +class NothTrigger : public Trigger +{ +public: + NothTrigger(PlayerbotAI* ai) : Trigger(ai, "noth"), helper(ai) {} + bool IsActive() override; + +private: + NothBossHelper helper; +}; + +#endif diff --git a/src/Ai/Raid/ObsidianSanctum/Action/RaidOsActions.cpp b/src/Ai/Raid/ObsidianSanctum/Action/RaidOsActions.cpp index 724b91902f..2ee68bca4b 100644 --- a/src/Ai/Raid/ObsidianSanctum/Action/RaidOsActions.cpp +++ b/src/Ai/Raid/ObsidianSanctum/Action/RaidOsActions.cpp @@ -243,4 +243,4 @@ bool ExitTwilightPortalAction::Execute(Event event) bot->GetSession()->HandleGameObjectUseOpcode(data1); return true; -} \ No newline at end of file +} diff --git a/src/Ai/Raid/ObsidianSanctum/Trigger/RaidOsTriggers.cpp b/src/Ai/Raid/ObsidianSanctum/Trigger/RaidOsTriggers.cpp index 2c3758856d..710e3cac10 100644 --- a/src/Ai/Raid/ObsidianSanctum/Trigger/RaidOsTriggers.cpp +++ b/src/Ai/Raid/ObsidianSanctum/Trigger/RaidOsTriggers.cpp @@ -78,19 +78,19 @@ bool SartharionMeleePositioningTrigger::IsActive() bool TwilightPortalEnterTrigger::IsActive() { - if (botAI->IsMainTank(bot) || botAI->IsHealAssistantOfIndex(bot, 0)) { return false; } + if (botAI->IsMainTank(bot) || botAI->IsAssistHealOfIndex(bot, 0)) { return false; } // In 25-man, take two healers in. Otherwise just take one // if (bot->GetRaidDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) // { - // if (botAI->IsHealAssistantOfIndex(bot, 0) || botAI->IsHealAssistantOfIndex(bot, 1)) + // if (botAI->IsAssistHealOfIndex(bot, 0) || botAI->IsAssistHealOfIndex(bot, 1)) // { // return false; // } // } // else // { - // if (botAI->IsHealAssistantOfIndex(bot, 0)) + // if (botAI->IsAssistHealOfIndex(bot, 0)) // { // return false; // } diff --git a/src/Ai/Raid/Onyxia/Action/RaidOnyxiaActions.cpp b/src/Ai/Raid/Onyxia/Action/RaidOnyxiaActions.cpp index c0cd4bebab..9fa4612bf6 100644 --- a/src/Ai/Raid/Onyxia/Action/RaidOnyxiaActions.cpp +++ b/src/Ai/Raid/Onyxia/Action/RaidOnyxiaActions.cpp @@ -45,8 +45,19 @@ bool RaidOnyxiaSpreadOutAction::Execute(Event event) if (!boss) return false; - Player* target = boss->GetCurrentSpell(CURRENT_GENERIC_SPELL)->m_targets.GetUnitTarget()->ToPlayer(); - if (target != bot) + // Trigger may fire on one tick, but the action can execute on a later tick. + // By that time the cast may have finished, so current spell can be null. + Spell* currentSpell = boss->GetCurrentSpell(CURRENT_GENERIC_SPELL); + if (!currentSpell || !currentSpell->m_spellInfo) + return false; + + // Fireball + if (currentSpell->m_spellInfo->Id != 18392) + return false; + + Unit* unitTarget = currentSpell->m_targets.GetUnitTarget(); + Player* target = unitTarget ? unitTarget->ToPlayer() : nullptr; + if (!target || target != bot) return false; // bot->Yell("Spreading out — I'm the Fireball target!", LANG_UNIVERSAL); @@ -60,7 +71,7 @@ bool RaidOnyxiaMoveToSafeZoneAction::Execute(Event event) return false; Spell* currentSpell = boss->GetCurrentSpell(CURRENT_GENERIC_SPELL); - if (!currentSpell) + if (!currentSpell || !currentSpell->m_spellInfo) return false; uint32 spellId = currentSpell->m_spellInfo->Id; diff --git a/src/Ai/Raid/Onyxia/Trigger/RaidOnyxiaTriggers.cpp b/src/Ai/Raid/Onyxia/Trigger/RaidOnyxiaTriggers.cpp index aed3a82619..56486ebf96 100644 --- a/src/Ai/Raid/Onyxia/Trigger/RaidOnyxiaTriggers.cpp +++ b/src/Ai/Raid/Onyxia/Trigger/RaidOnyxiaTriggers.cpp @@ -17,7 +17,7 @@ bool OnyxiaDeepBreathTrigger::IsActive() // Check if Onyxia is casting Spell* currentSpell = boss->GetCurrentSpell(CURRENT_GENERIC_SPELL); - if (!currentSpell) + if (!currentSpell || !currentSpell->m_spellInfo) return false; uint32 spellId = currentSpell->m_spellInfo->Id; @@ -65,7 +65,7 @@ bool RaidOnyxiaFireballSplashTrigger::IsActive() // Check if Onyxia is casting Fireball Spell* currentSpell = boss->GetCurrentSpell(CURRENT_GENERIC_SPELL); - if (!currentSpell || currentSpell->m_spellInfo->Id != 18392) // 18392 is the classic Fireball ID + if (!currentSpell || !currentSpell->m_spellInfo || currentSpell->m_spellInfo->Id != 18392) // 18392 is the classic Fireball ID // 18392 is the classic Fireball ID return false; GuidVector nearbyUnits = AI_VALUE(GuidVector, "nearest friendly players"); diff --git a/src/Ai/Raid/RaidStrategyContext.h b/src/Ai/Raid/RaidStrategyContext.h index 4f7a63c7ad..ee2bac3270 100644 --- a/src/Ai/Raid/RaidStrategyContext.h +++ b/src/Ai/Raid/RaidStrategyContext.h @@ -8,6 +8,7 @@ #include "RaidKarazhanStrategy.h" #include "RaidMagtheridonStrategy.h" #include "RaidGruulsLairStrategy.h" +#include "RaidNaxxStrategy.h" #include "RaidOsStrategy.h" #include "RaidEoEStrategy.h" #include "RaidVoAStrategy.h" @@ -26,6 +27,7 @@ class RaidStrategyContext : public NamedObjectContext creators["karazhan"] = &RaidStrategyContext::karazhan; creators["magtheridon"] = &RaidStrategyContext::magtheridon; creators["gruulslair"] = &RaidStrategyContext::gruulslair; + creators["naxx"] = &RaidStrategyContext::naxx; creators["wotlk-os"] = &RaidStrategyContext::wotlk_os; creators["wotlk-eoe"] = &RaidStrategyContext::wotlk_eoe; creators["voa"] = &RaidStrategyContext::voa; @@ -41,6 +43,7 @@ class RaidStrategyContext : public NamedObjectContext static Strategy* karazhan(PlayerbotAI* botAI) { return new RaidKarazhanStrategy(botAI); } static Strategy* magtheridon(PlayerbotAI* botAI) { return new RaidMagtheridonStrategy(botAI); } static Strategy* gruulslair(PlayerbotAI* botAI) { return new RaidGruulsLairStrategy(botAI); } + static Strategy* naxx(PlayerbotAI* botAI) { return new RaidNaxxStrategy(botAI); } static Strategy* wotlk_os(PlayerbotAI* botAI) { return new RaidOsStrategy(botAI); } static Strategy* wotlk_eoe(PlayerbotAI* botAI) { return new RaidEoEStrategy(botAI); } static Strategy* voa(PlayerbotAI* botAI) { return new RaidVoAStrategy(botAI); } diff --git a/src/Ai/Raid/Ulduar/Action/RaidUlduarActions.cpp b/src/Ai/Raid/Ulduar/Action/RaidUlduarActions.cpp index b7c3723bb3..b20425d224 100644 --- a/src/Ai/Raid/Ulduar/Action/RaidUlduarActions.cpp +++ b/src/Ai/Raid/Ulduar/Action/RaidUlduarActions.cpp @@ -2964,7 +2964,7 @@ bool YoggSaronMoveToEnterPortalAction::Execute(Event event) { return MoveNear(bot->GetMapId(), assignedPortalPosition.GetPositionX(), assignedPortalPosition.GetPositionY(), - assignedPortalPosition.GetPositionZ(), sPlayerbotAIConfig->contactDistance, + assignedPortalPosition.GetPositionZ(), sPlayerbotAIConfig.contactDistance, MovementPriority::MOVEMENT_FORCED); } } diff --git a/src/Ai/Raid/Ulduar/Multiplier/RaidUlduarMultipliers.cpp b/src/Ai/Raid/Ulduar/Multiplier/RaidUlduarMultipliers.cpp index 16df9c9af2..0a51ca407b 100644 --- a/src/Ai/Raid/Ulduar/Multiplier/RaidUlduarMultipliers.cpp +++ b/src/Ai/Raid/Ulduar/Multiplier/RaidUlduarMultipliers.cpp @@ -25,4 +25,4 @@ float FlameLeviathanMultiplier::GetValue(Action* action) // if (dynamic_cast(action)) // return 0.0f; return 1.0f; -} \ No newline at end of file +} diff --git a/src/Ai/Raid/Ulduar/Multiplier/RaidUlduarMultipliers.h b/src/Ai/Raid/Ulduar/Multiplier/RaidUlduarMultipliers.h index 736d9483b2..6c9a468fcd 100644 --- a/src/Ai/Raid/Ulduar/Multiplier/RaidUlduarMultipliers.h +++ b/src/Ai/Raid/Ulduar/Multiplier/RaidUlduarMultipliers.h @@ -14,4 +14,4 @@ class FlameLeviathanMultiplier : public Multiplier virtual float GetValue(Action* action); }; -#endif \ No newline at end of file +#endif diff --git a/src/Ai/Raid/Ulduar/Strategy/RaidUlduarStrategy.h b/src/Ai/Raid/Ulduar/Strategy/RaidUlduarStrategy.h index 6538845c2e..81bb93c3a5 100644 --- a/src/Ai/Raid/Ulduar/Strategy/RaidUlduarStrategy.h +++ b/src/Ai/Raid/Ulduar/Strategy/RaidUlduarStrategy.h @@ -15,4 +15,4 @@ class RaidUlduarStrategy : public Strategy virtual void InitMultipliers(std::vector& multipliers) override; }; -#endif \ No newline at end of file +#endif diff --git a/src/Ai/Raid/Ulduar/Trigger/RaidUlduarTriggers.cpp b/src/Ai/Raid/Ulduar/Trigger/RaidUlduarTriggers.cpp index 89ad7ac5fb..a4bc2cf9a2 100644 --- a/src/Ai/Raid/Ulduar/Trigger/RaidUlduarTriggers.cpp +++ b/src/Ai/Raid/Ulduar/Trigger/RaidUlduarTriggers.cpp @@ -765,9 +765,13 @@ bool FreyaMoveToHealingSporeTrigger::IsActive() bool ThorimUnbalancingStrikeTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "thorim"); + if (!boss || !boss->IsInWorld() || boss->IsDuringRemoveFromWorld()) + return false; - // Check boss and it is alive - if (!boss || !boss->IsAlive() || !boss->IsHostileTo(bot)) + if (!boss->IsAlive()) + return false; + + if (!boss->IsHostileTo(bot)) return false; return bot->HasAura(SPELL_UNBALANCING_STRIKE); @@ -804,8 +808,13 @@ bool ThorimMarkDpsTargetTrigger::IsActive() Unit* boss = AI_VALUE2(Unit*, "find target", "thorim"); - // Check boss and it is alive - if (!boss || !boss->IsAlive() || !boss->IsHostileTo(bot)) + if (!boss || !boss->IsInWorld() || boss->IsDuringRemoveFromWorld()) + return false; + + if (!boss->IsAlive()) + return false; + + if (!boss->IsHostileTo(bot)) return false; if (boss->GetPositionZ() < ULDUAR_THORIM_AXIS_Z_FLOOR_THRESHOLD && (!currentSkullUnit || !currentSkullUnit->IsAlive())) @@ -982,9 +991,13 @@ bool ThorimGauntletPositioningTrigger::IsActive() bool ThorimArenaPositioningTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "thorim"); + if (!boss || !boss->IsInWorld() || boss->IsDuringRemoveFromWorld()) + return false; - // Check boss and it is alive - if (!boss || !boss->IsAlive() || !boss->IsHostileTo(bot)) + if (!boss->IsAlive()) + return false; + + if (!boss->IsHostileTo(bot)) return false; if (boss->GetPositionZ() < ULDUAR_THORIM_AXIS_Z_FLOOR_THRESHOLD) @@ -1080,9 +1093,13 @@ bool ThorimPhase2PositioningTrigger::IsActive() return false; Unit* boss = AI_VALUE2(Unit*, "find target", "thorim"); + if (!boss || !boss->IsInWorld() || boss->IsDuringRemoveFromWorld()) + return false; - // Check boss and it is alive - if (!boss || !boss->IsAlive() || !boss->IsHostileTo(bot)) + if (!boss->IsAlive()) + return false; + + if (!boss->IsHostileTo(bot)) return false; if (boss->GetPositionZ() > ULDUAR_THORIM_AXIS_Z_FLOOR_THRESHOLD) @@ -1604,7 +1621,7 @@ bool VezaxCheatTrigger::IsActive() return false; } - return AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig->lowMana; + return AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig.lowMana; } bool VezaxShadowCrashTrigger::IsActive() diff --git a/src/Ai/World/Rpg/Action/NewRpgAction.cpp b/src/Ai/World/Rpg/Action/NewRpgAction.cpp index 01595edf79..41fec2291c 100644 --- a/src/Ai/World/Rpg/Action/NewRpgAction.cpp +++ b/src/Ai/World/Rpg/Action/NewRpgAction.cpp @@ -440,4 +440,4 @@ bool NewRpgTravelFlightAction::Execute(Event event) botAI->rpgInfo.ChangeToIdle(); } return true; -} \ No newline at end of file +} diff --git a/src/Ai/World/Rpg/Action/NewRpgAction.h b/src/Ai/World/Rpg/Action/NewRpgAction.h index 7669253743..0e621fc406 100644 --- a/src/Ai/World/Rpg/Action/NewRpgAction.h +++ b/src/Ai/World/Rpg/Action/NewRpgAction.h @@ -103,4 +103,4 @@ class NewRpgTravelFlightAction : public NewRpgBaseAction bool Execute(Event event) override; }; -#endif \ No newline at end of file +#endif diff --git a/src/Ai/World/Rpg/Action/NewRpgBaseAction.cpp b/src/Ai/World/Rpg/Action/NewRpgBaseAction.cpp index 4898d7e36c..0204a21331 100644 --- a/src/Ai/World/Rpg/Action/NewRpgBaseAction.cpp +++ b/src/Ai/World/Rpg/Action/NewRpgBaseAction.cpp @@ -866,7 +866,7 @@ bool NewRpgBaseAction::GetQuestPOIPosAndObjectiveIdx(uint32 questId, std::vector WorldPosition NewRpgBaseAction::SelectRandomGrindPos(Player* bot) { - const std::vector& locs = sRandomPlayerbotMgr->locsPerLevelCache[bot->GetLevel()]; + const std::vector& locs = sRandomPlayerbotMgr.locsPerLevelCache[bot->GetLevel()]; float hiRange = 500.0f; float loRange = 2500.0f; if (bot->GetLevel() < 5) @@ -925,8 +925,8 @@ WorldPosition NewRpgBaseAction::SelectRandomGrindPos(Player* bot) WorldPosition NewRpgBaseAction::SelectRandomCampPos(Player* bot) { const std::vector& locs = IsAlliance(bot->getRace()) - ? sRandomPlayerbotMgr->allianceStarterPerLevelCache[bot->GetLevel()] - : sRandomPlayerbotMgr->hordeStarterPerLevelCache[bot->GetLevel()]; + ? sRandomPlayerbotMgr.allianceStarterPerLevelCache[bot->GetLevel()] + : sRandomPlayerbotMgr.hordeStarterPerLevelCache[bot->GetLevel()]; bool inCity = false; @@ -969,7 +969,7 @@ WorldPosition NewRpgBaseAction::SelectRandomCampPos(Player* bot) bool NewRpgBaseAction::SelectRandomFlightTaxiNode(ObjectGuid& flightMaster, uint32& fromNode, uint32& toNode) { - Creature* nearestFlightMaster = sFlightMasterCache->GetNearestFlightMaster(bot); + Creature* nearestFlightMaster = FlightMasterCache::Instance().GetNearestFlightMaster(bot); if (!nearestFlightMaster || bot->GetDistance(nearestFlightMaster) > 500.0f) return false; @@ -1015,8 +1015,8 @@ bool NewRpgBaseAction::SelectRandomFlightTaxiNode(ObjectGuid& flightMaster, uint capital = zone->flags & AREA_FLAG_CAPITAL; } - auto itr = sRandomPlayerbotMgr->zone2LevelBracket.find(nodeZoneId); - if (!capital && itr == sRandomPlayerbotMgr->zone2LevelBracket.end()) + auto itr = sRandomPlayerbotMgr.zone2LevelBracket.find(nodeZoneId); + if (!capital && itr == sRandomPlayerbotMgr.zone2LevelBracket.end()) continue; if (!capital && (bot->GetLevel() < itr->second.low || bot->GetLevel() > itr->second.high)) @@ -1040,13 +1040,13 @@ bool NewRpgBaseAction::RandomChangeStatus(std::vector candidateSta uint32 probSum = 0; for (NewRpgStatus status : candidateStatus) { - if (sPlayerbotAIConfig->RpgStatusProbWeight[status] == 0) + if (sPlayerbotAIConfig.RpgStatusProbWeight[status] == 0) continue; if (CheckRpgStatusAvailable(status)) { availableStatus.push_back(status); - probSum += sPlayerbotAIConfig->RpgStatusProbWeight[status]; + probSum += sPlayerbotAIConfig.RpgStatusProbWeight[status]; } } // Safety check. Default to "rest" if all RPG weights = 0 @@ -1061,7 +1061,7 @@ bool NewRpgBaseAction::RandomChangeStatus(std::vector candidateSta NewRpgStatus chosenStatus = RPG_STATUS_END; for (NewRpgStatus status : availableStatus) { - accumulate += sPlayerbotAIConfig->RpgStatusProbWeight[status]; + accumulate += sPlayerbotAIConfig.RpgStatusProbWeight[status]; if (accumulate >= rand) { chosenStatus = status; diff --git a/src/Ai/World/Rpg/Action/NewRpgBaseAction.h b/src/Ai/World/Rpg/Action/NewRpgBaseAction.h index 0d2a96fbca..910e5f4942 100644 --- a/src/Ai/World/Rpg/Action/NewRpgBaseAction.h +++ b/src/Ai/World/Rpg/Action/NewRpgBaseAction.h @@ -64,4 +64,4 @@ class NewRpgBaseAction : public MovementAction const uint32 stuckTime = 5 * 60 * 1000; }; -#endif \ No newline at end of file +#endif diff --git a/src/Ai/World/Rpg/NewRpgInfo.cpp b/src/Ai/World/Rpg/NewRpgInfo.cpp index ff830464a5..889fb1ff92 100644 --- a/src/Ai/World/Rpg/NewRpgInfo.cpp +++ b/src/Ai/World/Rpg/NewRpgInfo.cpp @@ -136,4 +136,4 @@ std::string NewRpgInfo::ToString() out << "UNKNOWN"; } return out.str(); -} \ No newline at end of file +} diff --git a/src/Ai/World/Rpg/NewRpgInfo.h b/src/Ai/World/Rpg/NewRpgInfo.h index 5c14f70d17..20f801bf73 100644 --- a/src/Ai/World/Rpg/NewRpgInfo.h +++ b/src/Ai/World/Rpg/NewRpgInfo.h @@ -130,4 +130,4 @@ struct NewRpgStatistic // not sure is it necessary but keep it for now #define RPG_INFO(x, y) botAI->rpgInfo.x.y -#endif \ No newline at end of file +#endif diff --git a/src/Ai/World/Rpg/Trigger/NewRpgTrigger.cpp b/src/Ai/World/Rpg/Trigger/NewRpgTrigger.cpp index 6635409229..0804320ad9 100644 --- a/src/Ai/World/Rpg/Trigger/NewRpgTrigger.cpp +++ b/src/Ai/World/Rpg/Trigger/NewRpgTrigger.cpp @@ -1,4 +1,4 @@ #include "NewRpgTriggers.h" #include "PlayerbotAI.h" -bool NewRpgStatusTrigger::IsActive() { return status == botAI->rpgInfo.status; } \ No newline at end of file +bool NewRpgStatusTrigger::IsActive() { return status == botAI->rpgInfo.status; } diff --git a/src/Bot/Cmd/PlayerbotCommandServer.cpp b/src/Bot/Cmd/PlayerbotCommandServer.cpp index 83931229a0..1532cc0543 100644 --- a/src/Bot/Cmd/PlayerbotCommandServer.cpp +++ b/src/Bot/Cmd/PlayerbotCommandServer.cpp @@ -48,7 +48,7 @@ void session(socket_ptr sock) std::string buffer, request; while (ReadLine(sock, &buffer, &request)) { - std::string const response = sRandomPlayerbotMgr->HandleRemoteCommand(request) + "\n"; + std::string const response = sRandomPlayerbotMgr.HandleRemoteCommand(request) + "\n"; boost::asio::write(*sock, boost::asio::buffer(response.c_str(), response.size())); request = ""; } @@ -72,19 +72,19 @@ void server(Acore::Asio::IoContext& io_service, short port) void Run() { - if (!sPlayerbotAIConfig->commandServerPort) + if (!sPlayerbotAIConfig.commandServerPort) { return; } std::ostringstream s; - s << "Starting Playerbots Command Server on port " << sPlayerbotAIConfig->commandServerPort; + s << "Starting Playerbots Command Server on port " << sPlayerbotAIConfig.commandServerPort; LOG_INFO("playerbots", "{}", s.str().c_str()); try { Acore::Asio::IoContext io_service; - server(io_service, sPlayerbotAIConfig->commandServerPort); + server(io_service, sPlayerbotAIConfig.commandServerPort); } catch (std::exception& e) diff --git a/src/Bot/Cmd/PlayerbotCommandServer.h b/src/Bot/Cmd/PlayerbotCommandServer.h index e1b93a338e..eb410c644c 100644 --- a/src/Bot/Cmd/PlayerbotCommandServer.h +++ b/src/Bot/Cmd/PlayerbotCommandServer.h @@ -9,17 +9,24 @@ class PlayerbotCommandServer { public: - PlayerbotCommandServer() {} - virtual ~PlayerbotCommandServer() {} - static PlayerbotCommandServer* instance() + static PlayerbotCommandServer& instance() { static PlayerbotCommandServer instance; - return &instance; + + return instance; } void Start(); -}; -#define sPlayerbotCommandServer PlayerbotCommandServer::instance() +private: + PlayerbotCommandServer() = default; + ~PlayerbotCommandServer() = default; + + PlayerbotCommandServer(const PlayerbotCommandServer&) = delete; + PlayerbotCommandServer& operator=(const PlayerbotCommandServer&) = delete; + + PlayerbotCommandServer(PlayerbotCommandServer&&) = delete; + PlayerbotCommandServer& operator=(PlayerbotCommandServer&&) = delete; +}; #endif diff --git a/src/Bot/Debug/PerfMonitor.cpp b/src/Bot/Debug/PerfMonitor.cpp index c6d134edb9..82eece916f 100644 --- a/src/Bot/Debug/PerfMonitor.cpp +++ b/src/Bot/Debug/PerfMonitor.cpp @@ -10,7 +10,7 @@ PerfMonitorOperation* PerfMonitor::start(PerformanceMetric metric, std::string const name, PerformanceStack* stack) { - if (!sPlayerbotAIConfig->perfMonEnabled) + if (!sPlayerbotAIConfig.perfMonEnabled) return nullptr; std::string stackName = name; diff --git a/src/Bot/Debug/PerfMonitor.h b/src/Bot/Debug/PerfMonitor.h index 0d3eb8aad1..156392ee21 100644 --- a/src/Bot/Debug/PerfMonitor.h +++ b/src/Bot/Debug/PerfMonitor.h @@ -11,17 +11,16 @@ #include #include #include - -#include "Common.h" +#include typedef std::vector PerformanceStack; struct PerformanceData { - uint64 minTime; - uint64 maxTime; - uint64 totalTime; - uint32 count; + uint64_t minTime; + uint64_t maxTime; + uint64_t totalTime; + uint32_t count; std::mutex lock; }; @@ -50,21 +49,28 @@ class PerfMonitorOperation class PerfMonitor { public: - PerfMonitor(){}; - virtual ~PerfMonitor(){}; - static PerfMonitor* instance() + static PerfMonitor& instance() { static PerfMonitor instance; - return &instance; + + return instance; } -public: PerfMonitorOperation* start(PerformanceMetric metric, std::string const name, PerformanceStack* stack = nullptr); void PrintStats(bool perTick = false, bool fullStack = false); void Reset(); private: + PerfMonitor() = default; + virtual ~PerfMonitor() = default; + + PerfMonitor(const PerfMonitor&) = delete; + PerfMonitor& operator=(const PerfMonitor&) = delete; + + PerfMonitor(PerfMonitor&&) = delete; + PerfMonitor& operator=(PerfMonitor&&) = delete; + std::map > data; std::mutex lock; }; diff --git a/src/Bot/Engine/AiObjectContext.cpp b/src/Bot/Engine/AiObjectContext.cpp index b6d5f7de0d..1100e1a835 100644 --- a/src/Bot/Engine/AiObjectContext.cpp +++ b/src/Bot/Engine/AiObjectContext.cpp @@ -43,6 +43,8 @@ #include "Ai/Raid/Magtheridon/RaidMagtheridonTriggerContext.h" #include "Ai/Raid/GruulsLair/RaidGruulsLairActionContext.h" #include "Ai/Raid/GruulsLair/RaidGruulsLairTriggerContext.h" +#include "Ai/Raid/Naxxramas/RaidNaxxActionContext.h" +#include "Ai/Raid/Naxxramas/RaidNaxxTriggerContext.h" #include "Ai/Raid/EyeOfEternity/RaidEoEActionContext.h" #include "Ai/Raid/EyeOfEternity/RaidEoETriggerContext.h" #include "Ai/Raid/VaultOfArchavon/RaidVoAActionContext.h" @@ -115,6 +117,7 @@ void AiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextListlogValuesPerTick) + if (sPlayerbotAIConfig.logValuesPerTick) LogValues(); bool actionExecuted = false; @@ -154,7 +154,7 @@ bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal) PushDefaultActions(); uint32 iterations = 0; - uint32 iterationsPerTick = queue.Size() * (minimal ? 2 : sPlayerbotAIConfig->iterationsPerTick); + uint32 iterationsPerTick = queue.Size() * (minimal ? 2 : sPlayerbotAIConfig.iterationsPerTick); while (++iterations <= iterationsPerTick) { @@ -204,7 +204,7 @@ bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal) } } - PerfMonitorOperation* pmo = sPerfMonitor->start(PERF_MON_ACTION, action->getName(), &aiObjectContext->performanceStack); + PerfMonitorOperation* pmo = sPerfMonitor.start(PERF_MON_ACTION, action->getName(), &aiObjectContext->performanceStack); actionExecuted = ListenAndExecute(action, event); if (pmo) pmo->finish(); @@ -457,7 +457,7 @@ void Engine::ProcessTriggers(bool minimal) continue; PerfMonitorOperation* pmo = - sPerfMonitor->start(PERF_MON_TRIGGER, trigger->getName(), &aiObjectContext->performanceStack); + sPerfMonitor.start(PERF_MON_TRIGGER, trigger->getName(), &aiObjectContext->performanceStack); Event event = trigger->Check(); if (pmo) pmo->finish(); @@ -599,7 +599,7 @@ bool Engine::ListenAndExecute(Action* action, Event event) void Engine::LogAction(char const* format, ...) { Player* bot = botAI->GetBot(); - if (sPlayerbotAIConfig->logInGroupOnly && (!bot->GetGroup() || !botAI->HasRealPlayerMaster()) && !testMode) + if (sPlayerbotAIConfig.logInGroupOnly && (!bot->GetGroup() || !botAI->HasRealPlayerMaster()) && !testMode) return; char buf[1024]; @@ -661,7 +661,7 @@ void Engine::LogValues() return; Player* bot = botAI->GetBot(); - if (sPlayerbotAIConfig->logInGroupOnly && (!bot->GetGroup() || !botAI->HasRealPlayerMaster())) + if (sPlayerbotAIConfig.logInGroupOnly && (!bot->GetGroup() || !botAI->HasRealPlayerMaster())) return; std::string const text = botAI->GetAiObjectContext()->FormatValues(); diff --git a/src/Bot/Engine/PlayerbotAIBase.cpp b/src/Bot/Engine/PlayerbotAIBase.cpp index c034979340..cf4ad172cc 100644 --- a/src/Bot/Engine/PlayerbotAIBase.cpp +++ b/src/Bot/Engine/PlayerbotAIBase.cpp @@ -14,7 +14,7 @@ void PlayerbotAIBase::UpdateAI(uint32 elapsed, bool minimal) if (totalPmo) totalPmo->finish(); - totalPmo = sPerfMonitor->start(PERF_MON_TOTAL, "PlayerbotAIBase::FullTick"); + totalPmo = sPerfMonitor.start(PERF_MON_TOTAL, "PlayerbotAIBase::FullTick"); if (nextAICheckDelay > elapsed) nextAICheckDelay -= elapsed; @@ -35,7 +35,7 @@ void PlayerbotAIBase::SetNextCheckDelay(uint32 const delay) nextAICheckDelay = delay; - // if (nextAICheckDelay > sPlayerbotAIConfig->globalCoolDown) + // if (nextAICheckDelay > sPlayerbotAIConfig.globalCoolDown) // LOG_DEBUG("playerbots", "std::set next check delay: {}", nextAICheckDelay); } @@ -43,7 +43,7 @@ void PlayerbotAIBase::IncreaseNextCheckDelay(uint32 delay) { nextAICheckDelay += delay; - // if (nextAICheckDelay > sPlayerbotAIConfig->globalCoolDown) + // if (nextAICheckDelay > sPlayerbotAIConfig.globalCoolDown) // LOG_DEBUG("playerbots", "increase next check delay: {}", nextAICheckDelay); } @@ -55,6 +55,6 @@ void PlayerbotAIBase::YieldThread(uint32 delay) nextAICheckDelay = delay; } -bool PlayerbotAIBase::IsActive() { return nextAICheckDelay < sPlayerbotAIConfig->maxWaitForMove; } +bool PlayerbotAIBase::IsActive() { return nextAICheckDelay < sPlayerbotAIConfig.maxWaitForMove; } bool PlayerbotAIBase::IsBotAI() const { return _isBotAI; } diff --git a/src/Bot/Engine/PlayerbotAIBase.h b/src/Bot/Engine/PlayerbotAIBase.h index 03c762a58f..d0e0b775b2 100644 --- a/src/Bot/Engine/PlayerbotAIBase.h +++ b/src/Bot/Engine/PlayerbotAIBase.h @@ -17,7 +17,7 @@ class PlayerbotAIBase bool CanUpdateAI(); void SetNextCheckDelay(uint32 const delay); void IncreaseNextCheckDelay(uint32 delay); - void YieldThread(uint32 delay = sPlayerbotAIConfig->reactDelay); + void YieldThread(uint32 delay = sPlayerbotAIConfig.reactDelay); virtual void UpdateAI(uint32 elapsed, bool minimal = false); virtual void UpdateAIInternal(uint32 elapsed, bool minimal = false) = 0; bool IsActive(); diff --git a/src/Bot/Engine/Value/Value.cpp b/src/Bot/Engine/Value/Value.cpp index c559e03816..a9235a8e9f 100644 --- a/src/Bot/Engine/Value/Value.cpp +++ b/src/Bot/Engine/Value/Value.cpp @@ -123,7 +123,7 @@ Unit* UnitCalculatedValue::Get() { if (checkInterval < 2) { - PerfMonitorOperation* pmo = sPerfMonitor->start( + PerfMonitorOperation* pmo = sPerfMonitor.start( PERF_MON_VALUE, this->getName(), this->context ? &this->context->performanceStack : nullptr); value = Calculate(); if (pmo) @@ -135,7 +135,7 @@ Unit* UnitCalculatedValue::Get() if (!lastCheckTime || now - lastCheckTime >= checkInterval) { lastCheckTime = now; - PerfMonitorOperation* pmo = sPerfMonitor->start( + PerfMonitorOperation* pmo = sPerfMonitor.start( PERF_MON_VALUE, this->getName(), this->context ? &this->context->performanceStack : nullptr); value = Calculate(); if (pmo) @@ -154,4 +154,4 @@ Unit* UnitManualSetValue::Get() if (value && value->IsInWorld()) return value; return nullptr; -} \ No newline at end of file +} diff --git a/src/Bot/Engine/Value/Value.h b/src/Bot/Engine/Value/Value.h index b37e162050..fe84bb4d79 100644 --- a/src/Bot/Engine/Value/Value.h +++ b/src/Bot/Engine/Value/Value.h @@ -72,7 +72,7 @@ class CalculatedValue : public UntypedValue, public Value { if (checkInterval < 2) { - // PerfMonitorOperation* pmo = sPerfMonitor->start(PERF_MON_VALUE, this->getName(), + // PerfMonitorOperation* pmo = sPerfMonitor.start(PERF_MON_VALUE, this->getName(), // this->context ? &this->context->performanceStack : nullptr); value = Calculate(); // if (pmo) @@ -84,7 +84,7 @@ class CalculatedValue : public UntypedValue, public Value if (!lastCheckTime || now - lastCheckTime >= checkInterval) { lastCheckTime = now; - // PerfMonitorOperation* pmo = sPerfMonitor->start(PERF_MON_VALUE, this->getName(), + // PerfMonitorOperation* pmo = sPerfMonitor.start(PERF_MON_VALUE, this->getName(), // this->context ? &this->context->performanceStack : nullptr); value = Calculate(); // if (pmo) @@ -105,7 +105,7 @@ class CalculatedValue : public UntypedValue, public Value { if (checkInterval < 2) { - // PerfMonitorOperation* pmo = sPerfMonitor->start(PERF_MON_VALUE, this->getName(), + // PerfMonitorOperation* pmo = sPerfMonitor.start(PERF_MON_VALUE, this->getName(), // this->context ? &this->context->performanceStack : nullptr); value = Calculate(); // if (pmo) @@ -117,7 +117,7 @@ class CalculatedValue : public UntypedValue, public Value if (!lastCheckTime || now - lastCheckTime >= checkInterval) { lastCheckTime = now; - // PerfMonitorOperation* pmo = sPerfMonitor->start(PERF_MON_VALUE, this->getName(), + // PerfMonitorOperation* pmo = sPerfMonitor.start(PERF_MON_VALUE, this->getName(), // this->context ? &this->context->performanceStack : nullptr); value = Calculate(); // if (pmo) @@ -154,7 +154,7 @@ class SingleCalculatedValue : public CalculatedValue { this->lastCheckTime = now; - PerfMonitorOperation* pmo = sPerfMonitor->start( + PerfMonitorOperation* pmo = sPerfMonitor.start( PERF_MON_VALUE, this->getName(), this->context ? &this->context->performanceStack : nullptr); this->value = this->Calculate(); if (pmo) diff --git a/src/Bot/Factory/AiFactory.cpp b/src/Bot/Factory/AiFactory.cpp index 8ca3534b1d..84b3a7dc53 100644 --- a/src/Bot/Factory/AiFactory.cpp +++ b/src/Bot/Factory/AiFactory.cpp @@ -281,7 +281,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa if (!player->InBattleground()) engine->addStrategiesNoInit("racials", "chat", "default", "cast time", "potions", "duel", "boost", nullptr); - if (sPlayerbotAIConfig->autoAvoidAoe && facade->HasRealPlayerMaster()) + if (sPlayerbotAIConfig.autoAvoidAoe && facade->HasRealPlayerMaster()) engine->addStrategy("avoid aoe", false); engine->addStrategy("formation", false); @@ -399,13 +399,13 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa if (PlayerbotAI::IsHeal(player, true)) { - if (sPlayerbotAIConfig->autoSaveMana) + if (sPlayerbotAIConfig.autoSaveMana) engine->addStrategy("save mana", false); - if (!sPlayerbotAIConfig->IsRestrictedHealerDPSMap(player->GetMapId())) + if (!sPlayerbotAIConfig.IsRestrictedHealerDPSMap(player->GetMapId())) engine->addStrategy("healer dps", false); } - if (facade->IsRealPlayer() || sRandomPlayerbotMgr->IsRandomBot(player)) + if (facade->IsRealPlayer() || sRandomPlayerbotMgr.IsRandomBot(player)) { if (!player->GetGroup()) { @@ -448,10 +448,10 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa } } } - if (sRandomPlayerbotMgr->IsRandomBot(player)) - engine->ChangeStrategy(sPlayerbotAIConfig->randomBotCombatStrategies); + if (sRandomPlayerbotMgr.IsRandomBot(player)) + engine->ChangeStrategy(sPlayerbotAIConfig.randomBotCombatStrategies); else - engine->ChangeStrategy(sPlayerbotAIConfig->combatStrategies); + engine->ChangeStrategy(sPlayerbotAIConfig.combatStrategies); // Battleground switch if (player->InBattleground() && player->GetBattleground()) @@ -586,10 +586,10 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const "gather", "duel", "pvp", "buff", "mount", "emote", nullptr); } - if (sPlayerbotAIConfig->autoSaveMana && PlayerbotAI::IsHeal(player, true)) + if (sPlayerbotAIConfig.autoSaveMana && PlayerbotAI::IsHeal(player, true)) nonCombatEngine->addStrategy("save mana", false); - if ((sRandomPlayerbotMgr->IsRandomBot(player)) && !player->InBattleground()) + if ((sRandomPlayerbotMgr.IsRandomBot(player)) && !player->InBattleground()) { Player* master = facade->GetMaster(); @@ -597,7 +597,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const if (!urand(0, 3)) nonCombatEngine->addStrategy("start duel", false); - if (sPlayerbotAIConfig->randomBotJoinLfg) + if (sPlayerbotAIConfig.randomBotJoinLfg) nonCombatEngine->addStrategy("lfg", false); if (!player->GetGroup() || player->GetGroup()->GetLeaderGUID() == player->GetGUID()) @@ -612,9 +612,9 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const // nonCombatEngine->addStrategy("guild"); nonCombatEngine->addStrategy("grind", false); - if (sPlayerbotAIConfig->enableNewRpgStrategy) + if (sPlayerbotAIConfig.enableNewRpgStrategy) nonCombatEngine->addStrategy("new rpg", false); - else if (sPlayerbotAIConfig->autoDoQuests) + else if (sPlayerbotAIConfig.autoDoQuests) { // nonCombatEngine->addStrategy("travel"); nonCombatEngine->addStrategy("rpg", false); @@ -622,13 +622,13 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const else nonCombatEngine->addStrategy("move random", false); - if (sPlayerbotAIConfig->randomBotJoinBG) + if (sPlayerbotAIConfig.randomBotJoinBG) nonCombatEngine->addStrategy("bg", false); // if (!master || GET_PLAYERBOT_AI(master)) // nonCombatEngine->addStrategy("maintenance"); - nonCombatEngine->ChangeStrategy(sPlayerbotAIConfig->randomBotNonCombatStrategies); + nonCombatEngine->ChangeStrategy(sPlayerbotAIConfig.randomBotNonCombatStrategies); } else { @@ -637,14 +637,14 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const if (master) { PlayerbotAI* masterBotAI = GET_PLAYERBOT_AI(master); - if (masterBotAI || sRandomPlayerbotMgr->IsRandomBot(player)) + if (masterBotAI || sRandomPlayerbotMgr.IsRandomBot(player)) { // nonCombatEngine->addStrategy("pvp", false); // nonCombatEngine->addStrategy("collision"); // nonCombatEngine->addStrategy("group"); // nonCombatEngine->addStrategy("guild"); - // if (sPlayerbotAIConfig->autoDoQuests) + // if (sPlayerbotAIConfig.autoDoQuests) // { // // nonCombatEngine->addStrategy("travel"); // nonCombatEngine->addStrategy("rpg"); @@ -657,19 +657,19 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const // if (masterBotAI) // nonCombatEngine->addStrategy("maintenance"); - nonCombatEngine->ChangeStrategy(sPlayerbotAIConfig->randomBotNonCombatStrategies); + nonCombatEngine->ChangeStrategy(sPlayerbotAIConfig.randomBotNonCombatStrategies); } else { // nonCombatEngine->addStrategy("pvp", false); - nonCombatEngine->ChangeStrategy(sPlayerbotAIConfig->nonCombatStrategies); + nonCombatEngine->ChangeStrategy(sPlayerbotAIConfig.nonCombatStrategies); } } } } } else - nonCombatEngine->ChangeStrategy(sPlayerbotAIConfig->nonCombatStrategies); + nonCombatEngine->ChangeStrategy(sPlayerbotAIConfig.nonCombatStrategies); // Battleground switch if (player->InBattleground() && player->GetBattleground()) @@ -726,7 +726,7 @@ void AiFactory::AddDefaultDeadStrategies(Player* player, PlayerbotAI* const faca (void)facade; // unused and remove warning deadEngine->addStrategiesNoInit("dead", "stay", "chat", "default", "follow", nullptr); - if (sRandomPlayerbotMgr->IsRandomBot(player) && !player->GetGroup()) + if (sRandomPlayerbotMgr.IsRandomBot(player) && !player->GetGroup()) deadEngine->removeStrategy("follow", false); } diff --git a/src/Bot/Factory/PlayerbotFactory.cpp b/src/Bot/Factory/PlayerbotFactory.cpp index 67f5909c11..dfefd323c2 100644 --- a/src/Bot/Factory/PlayerbotFactory.cpp +++ b/src/Bot/Factory/PlayerbotFactory.cpp @@ -68,18 +68,18 @@ PlayerbotFactory::PlayerbotFactory(Player* bot, uint32 level, uint32 itemQuality botAI = GET_PLAYERBOT_AI(bot); if (!this->itemQuality) { - uint32 gs = sPlayerbotAIConfig->randomGearScoreLimit == 0 + uint32 gs = sPlayerbotAIConfig.randomGearScoreLimit == 0 ? 0 - : PlayerbotFactory::CalcMixedGearScore(sPlayerbotAIConfig->randomGearScoreLimit, - sPlayerbotAIConfig->randomGearQualityLimit); - this->itemQuality = sPlayerbotAIConfig->randomGearQualityLimit; + : PlayerbotFactory::CalcMixedGearScore(sPlayerbotAIConfig.randomGearScoreLimit, + sPlayerbotAIConfig.randomGearQualityLimit); + this->itemQuality = sPlayerbotAIConfig.randomGearQualityLimit; this->gearScoreLimit = gs; } } void PlayerbotFactory::Init() { - if (sPlayerbotAIConfig->randomBotPreQuests) + if (sPlayerbotAIConfig.randomBotPreQuests) { ObjectMgr::QuestMap const& questTemplates = sObjectMgr->GetQuestTemplates(); for (ObjectMgr::QuestMap::const_iterator i = questTemplates.begin(); i != questTemplates.end(); ++i) @@ -111,8 +111,8 @@ void PlayerbotFactory::Init() } } - for (std::vector::iterator i = sPlayerbotAIConfig->randomBotQuestIds.begin(); - i != sPlayerbotAIConfig->randomBotQuestIds.end(); ++i) + for (std::vector::iterator i = sPlayerbotAIConfig.randomBotQuestIds.begin(); + i != sPlayerbotAIConfig.randomBotQuestIds.end(); ++i) { uint32 questId = *i; AddPrevQuests(questId, specialQuestIds); @@ -190,7 +190,7 @@ void PlayerbotFactory::Init() continue; } - if (sRandomItemMgr->IsTestItem(gemId)) + if (sRandomItemMgr.IsTestItem(gemId)) { continue; } @@ -218,12 +218,12 @@ void PlayerbotFactory::Prepare() { bot->SetUInt32Value(PLAYER_XP, 0); } - if (!sPlayerbotAIConfig->randomBotShowHelmet || !urand(0, 4)) + if (!sPlayerbotAIConfig.randomBotShowHelmet || !urand(0, 4)) { bot->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM); } - if (!sPlayerbotAIConfig->randomBotShowCloak || !urand(0, 4)) + if (!sPlayerbotAIConfig.randomBotShowCloak || !urand(0, 4)) { bot->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK); } @@ -231,7 +231,7 @@ void PlayerbotFactory::Prepare() void PlayerbotFactory::Randomize(bool incremental) { - // if (sPlayerbotAIConfig->disableRandomLevels) + // if (sPlayerbotAIConfig.disableRandomLevels) // { // return; // } @@ -240,8 +240,8 @@ void PlayerbotFactory::Randomize(bool incremental) // LOG_DEBUG("playerbots", "Preparing to {} randomize...", (incremental ? "incremental" : "full")); Prepare(); LOG_DEBUG("playerbots", "Resetting player..."); - PerfMonitorOperation* pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Reset"); - if (!sPlayerbotAIConfig->equipmentPersistence || level < sPlayerbotAIConfig->equipmentPersistenceLevel) + PerfMonitorOperation* pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Reset"); + if (!sPlayerbotAIConfig.equipmentPersistence || level < sPlayerbotAIConfig.equipmentPersistenceLevel) { bot->resetTalents(true); } @@ -250,7 +250,7 @@ void PlayerbotFactory::Randomize(bool incremental) ClearSkills(); ClearSpells(); ResetQuests(); - if (!sPlayerbotAIConfig->equipmentPersistence || level < sPlayerbotAIConfig->equipmentPersistenceLevel) + if (!sPlayerbotAIConfig.equipmentPersistence || level < sPlayerbotAIConfig.equipmentPersistenceLevel) { ClearAllItems(); } @@ -266,15 +266,15 @@ void PlayerbotFactory::Randomize(bool incremental) if (pmo) pmo->finish(); - // pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Immersive"); + // pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Immersive"); // LOG_INFO("playerbots", "Initializing immersive..."); // InitImmersive(); // if (pmo) // pmo->finish(); - if (sPlayerbotAIConfig->randomBotPreQuests) + if (sPlayerbotAIConfig.randomBotPreQuests) { - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Quests"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Quests"); InitInstanceQuests(); InitAttunementQuests(); if (pmo) @@ -282,157 +282,157 @@ void PlayerbotFactory::Randomize(bool incremental) } else { - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Quests"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Quests"); InitAttunementQuests(); if (pmo) pmo->finish(); } LOG_DEBUG("playerbots", "Initializing skills (step 1)..."); - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Skills1"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Skills1"); bot->LearnDefaultSkills(); InitSkills(); if (pmo) pmo->finish(); - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Spells1"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Spells1"); LOG_DEBUG("playerbots", "Initializing spells (step 1)..."); InitClassSpells(); InitAvailableSpells(); if (pmo) pmo->finish(); - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Talents"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Talents"); LOG_DEBUG("playerbots", "Initializing talents..."); - if (!incremental || !sPlayerbotAIConfig->equipmentPersistence || - bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel) + if (!incremental || !sPlayerbotAIConfig.equipmentPersistence || + bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel) { InitTalentsTree(); } - sRandomPlayerbotMgr->SetValue(bot->GetGUID().GetCounter(), "specNo", 0); + sRandomPlayerbotMgr.SetValue(bot->GetGUID().GetCounter(), "specNo", 0); if (botAI) { - sPlayerbotRepository->Reset(botAI); + PlayerbotRepository::instance().Reset(botAI); // botAI->DoSpecificAction("auto talents"); botAI->ResetStrategies(false); // fix wrong stored strategy } if (pmo) pmo->finish(); - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Spells2"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Spells2"); LOG_DEBUG("playerbots", "Initializing spells (step 2)..."); InitAvailableSpells(); if (pmo) pmo->finish(); - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Reputation"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Reputation"); LOG_DEBUG("playerbots", "Initializing reputation..."); InitReputation(); if (pmo) pmo->finish(); LOG_DEBUG("playerbots", "Initializing special spells..."); - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Spells3"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Spells3"); InitSpecialSpells(); if (pmo) pmo->finish(); - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Mounts"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Mounts"); LOG_DEBUG("playerbots", "Initializing mounts..."); InitMounts(); // bot->SaveToDB(false, false); if (pmo) pmo->finish(); - // pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Skills2"); + // pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Skills2"); // LOG_INFO("playerbots", "Initializing skills (step 2)..."); // UpdateTradeSkills(); // if (pmo) // pmo->finish(); - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Equip"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Equip"); LOG_DEBUG("playerbots", "Initializing equipmemt..."); - if (!incremental || !sPlayerbotAIConfig->equipmentPersistence || - bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel) + if (!incremental || !sPlayerbotAIConfig.equipmentPersistence || + bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel) { - if (sPlayerbotAIConfig->incrementalGearInit || !incremental) - InitEquipment(incremental, incremental ? false : sPlayerbotAIConfig->twoRoundsGearInit); + if (sPlayerbotAIConfig.incrementalGearInit || !incremental) + InitEquipment(incremental, incremental ? false : sPlayerbotAIConfig.twoRoundsGearInit); } // bot->SaveToDB(false, false); if (pmo) pmo->finish(); - // if (bot->GetLevel() >= sPlayerbotAIConfig->minEnchantingBotLevel) + // if (bot->GetLevel() >= sPlayerbotAIConfig.minEnchantingBotLevel) // { - // pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Enchant"); + // pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Enchant"); // LOG_INFO("playerbots", "Initializing enchant templates..."); // LoadEnchantContainer(); // if (pmo) // pmo->finish(); // } - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Bags"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Bags"); LOG_DEBUG("playerbots", "Initializing bags..."); InitBags(); // bot->SaveToDB(false, false); if (pmo) pmo->finish(); - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Ammo"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Ammo"); LOG_DEBUG("playerbots", "Initializing ammo..."); InitAmmo(); if (pmo) pmo->finish(); - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Food"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Food"); LOG_DEBUG("playerbots", "Initializing food..."); InitFood(); if (pmo) pmo->finish(); - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Potions"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Potions"); LOG_DEBUG("playerbots", "Initializing potions..."); InitPotions(); if (pmo) pmo->finish(); - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Reagents"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Reagents"); LOG_DEBUG("playerbots", "Initializing reagents..."); InitReagents(); if (pmo) pmo->finish(); - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Keys"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Keys"); LOG_DEBUG("playerbots", "Initializing keys..."); InitKeyring(); if (pmo) pmo->finish(); - // pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_EqSets"); + // pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_EqSets"); // LOG_DEBUG("playerbots", "Initializing second equipment set..."); // InitSecondEquipmentSet(); // if (pmo) // pmo->finish(); - if (bot->GetLevel() >= sPlayerbotAIConfig->minEnchantingBotLevel) + if (bot->GetLevel() >= sPlayerbotAIConfig.minEnchantingBotLevel) { ApplyEnchantAndGemsNew(); } // { - // pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_EnchantTemplate"); + // pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_EnchantTemplate"); // LOG_INFO("playerbots", "Initializing enchant templates..."); // ApplyEnchantTemplate(); // if (pmo) // pmo->finish(); // } - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Inventory"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Inventory"); LOG_DEBUG("playerbots", "Initializing inventory..."); // InitInventory(); if (pmo) pmo->finish(); - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Consumable"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Consumable"); LOG_DEBUG("playerbots", "Initializing consumables..."); InitConsumables(); if (pmo) @@ -442,9 +442,9 @@ void PlayerbotFactory::Randomize(bool incremental) InitGlyphs(); // bot->SaveToDB(false, false); - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Guilds"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Guilds"); // bot->SaveToDB(false, false); - if (sPlayerbotAIConfig->randomBotGuildCount > 0) + if (sPlayerbotAIConfig.randomBotGuildCount > 0) { LOG_DEBUG("playerbots", "Initializing guilds..."); InitGuild(); @@ -455,7 +455,7 @@ void PlayerbotFactory::Randomize(bool incremental) if (bot->GetLevel() >= 70) { - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Arenas"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Arenas"); // LOG_INFO("playerbots", "Initializing arena teams..."); InitArenaTeam(); if (pmo) @@ -470,7 +470,7 @@ void PlayerbotFactory::Randomize(bool incremental) } if (bot->GetLevel() >= 10) { - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Pet"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Pet"); LOG_DEBUG("playerbots", "Initializing pet..."); InitPet(); // bot->SaveToDB(false, false); @@ -479,7 +479,7 @@ void PlayerbotFactory::Randomize(bool incremental) pmo->finish(); } - pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Save"); + pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Save"); LOG_DEBUG("playerbots", "Saving to DB..."); bot->SetMoney(urand(level * 100000, level * 5 * 100000)); bot->SetHealth(bot->GetMaxHealth()); @@ -493,7 +493,7 @@ void PlayerbotFactory::Randomize(bool incremental) void PlayerbotFactory::Refresh() { // Prepare(); - // if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel) + // if (!sPlayerbotAIConfig.equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel) // { // InitEquipment(true); // } @@ -513,11 +513,11 @@ void PlayerbotFactory::Refresh() InitSpecialSpells(); InitMounts(); InitKeyring(); - if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel) + if (!sPlayerbotAIConfig.equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel) { InitTalentsTree(true, true, true); } - if (bot->GetLevel() >= sPlayerbotAIConfig->minEnchantingBotLevel) + if (bot->GetLevel() >= sPlayerbotAIConfig.minEnchantingBotLevel) { ApplyEnchantAndGemsNew(); } @@ -746,7 +746,7 @@ void PlayerbotFactory::InitConsumables() void PlayerbotFactory::InitPetTalents() { - if (bot->GetLevel() <= 70 && sPlayerbotAIConfig->limitTalentsExpansion) + if (bot->GetLevel() <= 70 && sPlayerbotAIConfig.limitTalentsExpansion) return; Pet* pet = bot->GetPet(); @@ -794,7 +794,7 @@ void PlayerbotFactory::InitPetTalents() } std::vector> order = - sPlayerbotAIConfig->parsedHunterPetLinkOrder[pet_family->petTalentType][20]; + sPlayerbotAIConfig.parsedHunterPetLinkOrder[pet_family->petTalentType][20]; uint32 maxTalentPoints = pet->GetMaxTalentPointsForLevel(pet->GetLevel()); if (order.empty()) @@ -842,16 +842,16 @@ void PlayerbotFactory::InitPetTalents() uint32 spec = pet_family->petTalentType; uint32 startPoints = pet->GetMaxTalentPointsForLevel(pet->GetLevel()); while (startPoints > 1 && startPoints < 20 && - sPlayerbotAIConfig->parsedHunterPetLinkOrder[spec][startPoints].size() == 0) + sPlayerbotAIConfig.parsedHunterPetLinkOrder[spec][startPoints].size() == 0) { startPoints--; } for (uint32 points = startPoints; points <= 20; points++) { - if (sPlayerbotAIConfig->parsedHunterPetLinkOrder[spec][points].size() == 0) + if (sPlayerbotAIConfig.parsedHunterPetLinkOrder[spec][points].size() == 0) continue; - for (std::vector& p : sPlayerbotAIConfig->parsedHunterPetLinkOrder[spec][points]) + for (std::vector& p : sPlayerbotAIConfig.parsedHunterPetLinkOrder[spec][points]) { uint32 row = p[0], col = p[1], lvl = p[2]; uint32 talentID = 0; @@ -924,17 +924,17 @@ void PlayerbotFactory::InitPet() if (itr->second.minlevel > bot->GetLevel()) continue; - bool onlyWolf = sPlayerbotAIConfig->hunterWolfPet == 2 || - (sPlayerbotAIConfig->hunterWolfPet == 1 && + bool onlyWolf = sPlayerbotAIConfig.hunterWolfPet == 2 || + (sPlayerbotAIConfig.hunterWolfPet == 1 && bot->GetLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)); // Wolf only (for higher dps) if (onlyWolf && itr->second.family != CREATURE_FAMILY_WOLF) continue; // Exclude configured pet families - if (std::find(sPlayerbotAIConfig->excludedHunterPetFamilies.begin(), - sPlayerbotAIConfig->excludedHunterPetFamilies.end(), - itr->second.family) != sPlayerbotAIConfig->excludedHunterPetFamilies.end()) + if (std::find(sPlayerbotAIConfig.excludedHunterPetFamilies.begin(), + sPlayerbotAIConfig.excludedHunterPetFamilies.end(), + itr->second.family) != sPlayerbotAIConfig.excludedHunterPetFamilies.end()) continue; ids.push_back(itr->first); @@ -1123,8 +1123,8 @@ void PlayerbotFactory::InitTalentsTree(bool increment /*false*/, bool use_templa bool isCat = !bot->HasAura(16931); if (!isCat && bot->GetLevel() == 20) { - uint32 bearP = sPlayerbotAIConfig->randomClassSpecProb[cls][1]; - uint32 catP = sPlayerbotAIConfig->randomClassSpecProb[cls][3]; + uint32 bearP = sPlayerbotAIConfig.randomClassSpecProb[cls][1]; + uint32 catP = sPlayerbotAIConfig.randomClassSpecProb[cls][3]; if (urand(1, bearP + catP) <= catP) isCat = true; } @@ -1139,14 +1139,14 @@ void PlayerbotFactory::InitTalentsTree(bool increment /*false*/, bool use_templa uint32 pointSum = 0; for (int i = 0; i < MAX_SPECNO; i++) { - pointSum += sPlayerbotAIConfig->randomClassSpecProb[cls][i]; + pointSum += sPlayerbotAIConfig.randomClassSpecProb[cls][i]; } uint32 point = urand(1, pointSum); uint32 currentP = 0; int i; for (i = 0; i < MAX_SPECNO; i++) { - currentP += sPlayerbotAIConfig->randomClassSpecProb[cls][i]; + currentP += sPlayerbotAIConfig.randomClassSpecProb[cls][i]; if (point <= currentP) { specTab = i; @@ -1204,17 +1204,17 @@ void PlayerbotFactory::InitTalentsBySpecNo(Player* bot, int specNo, bool reset) spells_row[talentInfo->Row].push_back(talentInfo); } while (startLevel > 1 && startLevel < 80 && - sPlayerbotAIConfig->parsedSpecLinkOrder[cls][specNo][startLevel].size() == 0) + sPlayerbotAIConfig.parsedSpecLinkOrder[cls][specNo][startLevel].size() == 0) { startLevel--; } for (int level = startLevel; level <= 80; level++) { - if (sPlayerbotAIConfig->parsedSpecLinkOrder[cls][specNo][level].size() == 0) + if (sPlayerbotAIConfig.parsedSpecLinkOrder[cls][specNo][level].size() == 0) { continue; } - for (std::vector& p : sPlayerbotAIConfig->parsedSpecLinkOrder[cls][specNo][level]) + for (std::vector& p : sPlayerbotAIConfig.parsedSpecLinkOrder[cls][specNo][level]) { uint32 tab = p[0], row = p[1], col = p[2], lvl = p[3]; uint32 talentID = -1; @@ -1341,7 +1341,7 @@ class DestroyItemsVisitor : public IterateItemsVisitor if (keep.find(id) != keep.end()) return false; - if (sPlayerbotAIConfig->IsInRandomQuestItemList(id)) + if (sPlayerbotAIConfig.IsInRandomQuestItemList(id)) return true; return false; @@ -1603,7 +1603,7 @@ void Shuffle(std::vector& items) // bool noItem = false; // uint32 quality = urand(ITEM_QUALITY_UNCOMMON, ITEM_QUALITY_EPIC); // uint32 attempts = 10; -// if (urand(0, 100) < 100 * sPlayerbotAIConfig->randomGearLoweringChance && quality > ITEM_QUALITY_NORMAL) +// if (urand(0, 100) < 100 * sPlayerbotAIConfig.randomGearLoweringChance && quality > ITEM_QUALITY_NORMAL) // { // quality--; // } @@ -1614,11 +1614,11 @@ void Shuffle(std::vector& items) // uint32 itemInSlot = isUpgrade ? oldItem->GetTemplate()->ItemId : 0; -// uint32 maxLevel = sPlayerbotAIConfig->randomBotMaxLevel; +// uint32 maxLevel = sPlayerbotAIConfig.randomBotMaxLevel; // if (maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) // maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); -// uint32 minLevel = sPlayerbotAIConfig->randomBotMinLevel; +// uint32 minLevel = sPlayerbotAIConfig.randomBotMinLevel; // if (minLevel < sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL)) // minLevel = sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL); @@ -1627,7 +1627,7 @@ void Shuffle(std::vector& items) // { // if (isUpgrade) // { -// std::vector ids = sRandomItemMgr->GetUpgradeList(bot, specName, slot, 0, itemInSlot); +// std::vector ids = sRandomItemMgr.GetUpgradeList(bot, specName, slot, 0, itemInSlot); // if (!ids.empty()) // Shuffle(ids); @@ -1667,7 +1667,7 @@ void Shuffle(std::vector& items) // } // else // { -// std::vector ids = sRandomItemMgr->GetUpgradeList(bot, specName, slot, quality, itemInSlot); +// std::vector ids = sRandomItemMgr.GetUpgradeList(bot, specName, slot, quality, itemInSlot); // if (!ids.empty()) // Shuffle(ids); @@ -1706,7 +1706,7 @@ void Shuffle(std::vector& items) void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance) { - if (incremental && !sPlayerbotAIConfig->incrementalGearInit) + if (incremental && !sPlayerbotAIConfig.incrementalGearInit) return; if (level < 5) @@ -1786,7 +1786,7 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance) oldItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot); int32 desiredQuality = itemQuality; - if (urand(0, 100) < 100 * sPlayerbotAIConfig->randomGearLoweringChance && desiredQuality > ITEM_QUALITY_NORMAL) + if (urand(0, 100) < 100 * sPlayerbotAIConfig.randomGearLoweringChance && desiredQuality > ITEM_QUALITY_NORMAL) { desiredQuality--; } @@ -1797,7 +1797,7 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance) { for (InventoryType inventoryType : GetPossibleInventoryTypeListBySlot((EquipmentSlots)slot)) { - for (uint32 itemId : sRandomItemMgr->GetCachedEquipments(requiredLevel, inventoryType)) + for (uint32 itemId : sRandomItemMgr.GetCachedEquipments(requiredLevel, inventoryType)) { if (itemId == 46978) // shaman earth ring totem { @@ -1808,10 +1808,10 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance) continue; // disable next expansion gear - if (sPlayerbotAIConfig->limitGearExpansion && bot->GetLevel() <= 60 && itemId >= 23728) + if (sPlayerbotAIConfig.limitGearExpansion && bot->GetLevel() <= 60 && itemId >= 23728) continue; - if (sPlayerbotAIConfig->limitGearExpansion && bot->GetLevel() <= 70 && itemId >= 35570 && + if (sPlayerbotAIConfig.limitGearExpansion && bot->GetLevel() <= 70 && itemId >= 35570 && itemId != 36737 && itemId != 37739 && itemId != 37740) // transition point from TBC -> WOTLK isn't as clear, and there are other // wearable TBC items above 35570 but nothing of significance @@ -2009,7 +2009,7 @@ bool PlayerbotFactory::IsDesiredReplacement(Item* item) } // if (!requiredLevel) // { - // requiredLevel = sRandomItemMgr->GetMinLevelFromCache(proto->ItemId); + // requiredLevel = sRandomItemMgr.GetMinLevelFromCache(proto->ItemId); // } uint32 delta = 1 + (80 - bot->GetLevel()) / 10; @@ -2039,7 +2039,7 @@ inline Item* StoreNewItemInInventorySlot(Player* player, uint32 newItemId, uint3 // std::map> items; // uint32 desiredQuality = itemQuality; -// while (urand(0, 100) < 100 * sPlayerbotAIConfig->randomGearLoweringChance && desiredQuality > +// while (urand(0, 100) < 100 * sPlayerbotAIConfig.randomGearLoweringChance && desiredQuality > // ITEM_QUALITY_NORMAL) // { // desiredQuality--; @@ -2061,9 +2061,9 @@ inline Item* StoreNewItemInInventorySlot(Player* player, uint32 newItemId, uint3 // //if (!CanEquipWeapon(proto)) // // continue; -// if (sRandomItemMgr->HasStatWeight(proto->ItemId)) +// if (sRandomItemMgr.HasStatWeight(proto->ItemId)) // { -// if (!sRandomItemMgr->GetLiveStatWeight(bot, proto->ItemId)) +// if (!sRandomItemMgr.GetLiveStatWeight(bot, proto->ItemId)) // continue; // } @@ -2096,9 +2096,9 @@ inline Item* StoreNewItemInInventorySlot(Player* player, uint32 newItemId, uint3 // //if (!CanEquipArmor(proto)) // // continue; -// if (sRandomItemMgr->HasStatWeight(proto->ItemId)) +// if (sRandomItemMgr.HasStatWeight(proto->ItemId)) // { -// if (!sRandomItemMgr->GetLiveStatWeight(bot, proto->ItemId)) +// if (!sRandomItemMgr.GetLiveStatWeight(bot, proto->ItemId)) // continue; // } @@ -2173,10 +2173,10 @@ void PlayerbotFactory::InitBags(bool destroyOld) void PlayerbotFactory::EnchantItem(Item* item) { - if (bot->GetLevel() < sPlayerbotAIConfig->minEnchantingBotLevel) + if (bot->GetLevel() < sPlayerbotAIConfig.minEnchantingBotLevel) return; - if (urand(0, 100) < 100 * sPlayerbotAIConfig->randomGearLoweringChance) + if (urand(0, 100) < 100 * sPlayerbotAIConfig.randomGearLoweringChance) return; ItemTemplate const* proto = item->GetTemplate(); @@ -2279,8 +2279,8 @@ bool PlayerbotFactory::CanEquipUnseenItem(uint8 slot, uint16& dest, uint32 item) void PlayerbotFactory::InitTradeSkills() { - uint16 firstSkill = sRandomPlayerbotMgr->GetValue(bot, "firstSkill"); - uint16 secondSkill = sRandomPlayerbotMgr->GetValue(bot, "secondSkill"); + uint16 firstSkill = sRandomPlayerbotMgr.GetValue(bot, "firstSkill"); + uint16 secondSkill = sRandomPlayerbotMgr.GetValue(bot, "secondSkill"); if (!firstSkill || !secondSkill) { std::vector firstSkills; @@ -2332,8 +2332,8 @@ void PlayerbotFactory::InitTradeSkills() break; } - sRandomPlayerbotMgr->SetValue(bot, "firstSkill", firstSkill); - sRandomPlayerbotMgr->SetValue(bot, "secondSkill", secondSkill); + sRandomPlayerbotMgr.SetValue(bot, "firstSkill", firstSkill); + sRandomPlayerbotMgr.SetValue(bot, "secondSkill", secondSkill); } SetRandomSkill(SKILL_FIRST_AID); @@ -2359,13 +2359,13 @@ void PlayerbotFactory::InitSkills() bot->UpdateSkillsForLevel(); bot->SetSkill(SKILL_RIDING, 0, 0, 0); - if (bot->GetLevel() >= sPlayerbotAIConfig->useGroundMountAtMinLevel) + if (bot->GetLevel() >= sPlayerbotAIConfig.useGroundMountAtMinLevel) bot->learnSpell(33388); - if (bot->GetLevel() >= sPlayerbotAIConfig->useFastGroundMountAtMinLevel) + if (bot->GetLevel() >= sPlayerbotAIConfig.useFastGroundMountAtMinLevel) bot->learnSpell(33391); - if (bot->GetLevel() >= sPlayerbotAIConfig->useFlyMountAtMinLevel) + if (bot->GetLevel() >= sPlayerbotAIConfig.useFlyMountAtMinLevel) bot->learnSpell(34090); - if (bot->GetLevel() >= sPlayerbotAIConfig->useFastFlyMountAtMinLevel) + if (bot->GetLevel() >= sPlayerbotAIConfig.useFastFlyMountAtMinLevel) bot->learnSpell(34091); uint32 skillLevel = bot->GetLevel() < 40 ? 0 : 1; @@ -2680,8 +2680,8 @@ void PlayerbotFactory::InitClassSpells() void PlayerbotFactory::InitSpecialSpells() { - for (std::vector::iterator i = sPlayerbotAIConfig->randomBotSpellIds.begin(); - i != sPlayerbotAIConfig->randomBotSpellIds.end(); ++i) + for (std::vector::iterator i = sPlayerbotAIConfig.randomBotSpellIds.begin(); + i != sPlayerbotAIConfig.randomBotSpellIds.end(); ++i) { uint32 spellId = *i; bot->learnSpell(spellId); @@ -2752,13 +2752,13 @@ void PlayerbotFactory::InitTalents(uint32 specNo) void PlayerbotFactory::InitTalentsByTemplate(uint32 specTab) { - // if (sPlayerbotAIConfig->parsedSpecLinkOrder[bot->getClass()][specNo][80].size() == 0) + // if (sPlayerbotAIConfig.parsedSpecLinkOrder[bot->getClass()][specNo][80].size() == 0) // { // return; // } uint32 cls = bot->getClass(); int startLevel = bot->GetLevel(); - uint32 specIndex = sPlayerbotAIConfig->randomClassSpecIndex[cls][specTab]; + uint32 specIndex = sPlayerbotAIConfig.randomClassSpecIndex[cls][specTab]; uint32 classMask = bot->getClassMask(); std::unordered_map> spells_row; for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i) @@ -2777,23 +2777,23 @@ void PlayerbotFactory::InitTalentsByTemplate(uint32 specTab) spells_row[talentInfo->Row].push_back(talentInfo); } while (startLevel > 1 && startLevel < 80 && - sPlayerbotAIConfig->parsedSpecLinkOrder[cls][specIndex][startLevel].size() == 0) + sPlayerbotAIConfig.parsedSpecLinkOrder[cls][specIndex][startLevel].size() == 0) { startLevel--; } for (int level = startLevel; level <= 80; level++) { - if (sPlayerbotAIConfig->parsedSpecLinkOrder[cls][specIndex][level].size() == 0) + if (sPlayerbotAIConfig.parsedSpecLinkOrder[cls][specIndex][level].size() == 0) { continue; } - for (std::vector& p : sPlayerbotAIConfig->parsedSpecLinkOrder[cls][specIndex][level]) + for (std::vector& p : sPlayerbotAIConfig.parsedSpecLinkOrder[cls][specIndex][level]) { uint32 tab = p[0], row = p[1], col = p[2], lvl = p[3]; - if (sPlayerbotAIConfig->limitTalentsExpansion && bot->GetLevel() <= 60 && (row > 6 || (row == 6 && col != 1))) + if (sPlayerbotAIConfig.limitTalentsExpansion && bot->GetLevel() <= 60 && (row > 6 || (row == 6 && col != 1))) continue; - if (sPlayerbotAIConfig->limitTalentsExpansion && bot->GetLevel() <= 70 && (row > 8 || (row == 8 && col != 1))) + if (sPlayerbotAIConfig.limitTalentsExpansion && bot->GetLevel() <= 70 && (row > 8 || (row == 8 && col != 1))) continue; uint32 talentID = 0; @@ -2848,8 +2848,8 @@ void PlayerbotFactory::InitTalentsByTemplate(uint32 specTab) ObjectGuid PlayerbotFactory::GetRandomBot() { GuidVector guids; - for (std::vector::iterator i = sPlayerbotAIConfig->randomBotAccounts.begin(); - i != sPlayerbotAIConfig->randomBotAccounts.end(); i++) + for (std::vector::iterator i = sPlayerbotAIConfig.randomBotAccounts.begin(); + i != sPlayerbotAIConfig.randomBotAccounts.end(); i++) { uint32 accountId = *i; if (!AccountMgr::GetCharactersCount(accountId)) @@ -2981,7 +2981,7 @@ void PlayerbotFactory::InitAmmo() if (!subClass) return; - std::vector ammoEntryList = sRandomItemMgr->GetAmmo(level, subClass); + std::vector ammoEntryList = sRandomItemMgr.GetAmmo(level, subClass); uint32 entry = 0; for (uint32 tEntry : ammoEntryList) { @@ -2990,10 +2990,10 @@ void PlayerbotFactory::InitAmmo() continue; // disable next expansion ammo - if (sPlayerbotAIConfig->limitGearExpansion && bot->GetLevel() <= 60 && tEntry >= 23728) + if (sPlayerbotAIConfig.limitGearExpansion && bot->GetLevel() <= 60 && tEntry >= 23728) continue; - if (sPlayerbotAIConfig->limitGearExpansion && bot->GetLevel() <= 70 && tEntry >= 35570) + if (sPlayerbotAIConfig.limitGearExpansion && bot->GetLevel() <= 70 && tEntry >= 35570) continue; entry = tEntry; @@ -3023,10 +3023,10 @@ uint32 PlayerbotFactory::CalcMixedGearScore(uint32 gs, uint32 quality) void PlayerbotFactory::InitMounts() { - uint32 firstmount = sPlayerbotAIConfig->useGroundMountAtMinLevel; - uint32 secondmount = sPlayerbotAIConfig->useFastGroundMountAtMinLevel; - uint32 thirdmount = sPlayerbotAIConfig->useFlyMountAtMinLevel; - uint32 fourthmount = sPlayerbotAIConfig->useFastFlyMountAtMinLevel; + uint32 firstmount = sPlayerbotAIConfig.useGroundMountAtMinLevel; + uint32 secondmount = sPlayerbotAIConfig.useFastGroundMountAtMinLevel; + uint32 thirdmount = sPlayerbotAIConfig.useFlyMountAtMinLevel; + uint32 fourthmount = sPlayerbotAIConfig.useFastFlyMountAtMinLevel; if (bot->GetLevel() < firstmount) return; @@ -3165,7 +3165,7 @@ void PlayerbotFactory::InitPotions() if (!visitor.GetResult().empty()) continue; - uint32 itemId = sRandomItemMgr->GetRandomPotion(level, effect); + uint32 itemId = sRandomItemMgr.GetRandomPotion(level, effect); if (!itemId) { // LOG_INFO("playerbots", "No potions (type {}) available for bot {} ({} level)", effect, @@ -3499,7 +3499,7 @@ void PlayerbotFactory::InitGlyphs(bool increment) } } - if (sPlayerbotAIConfig->limitTalentsExpansion && bot->GetLevel() <= 70) + if (sPlayerbotAIConfig.limitTalentsExpansion && bot->GetLevel() <= 70) { bot->SendTalentsInfoData(false); return; @@ -3722,10 +3722,10 @@ void PlayerbotFactory::InitGlyphs(bool increment) // GlyphSlotEntry const *gs = sGlyphSlotStore.LookupEntry(slot); // if (!gs) // continue; - if (sPlayerbotAIConfig->parsedSpecGlyph[cls][tab].size() > slotIndex && - sPlayerbotAIConfig->parsedSpecGlyph[cls][tab][slotIndex] != 0) + if (sPlayerbotAIConfig.parsedSpecGlyph[cls][tab].size() > slotIndex && + sPlayerbotAIConfig.parsedSpecGlyph[cls][tab][slotIndex] != 0) { - uint32 itemId = sPlayerbotAIConfig->parsedSpecGlyph[cls][tab][slotIndex]; + uint32 itemId = sPlayerbotAIConfig.parsedSpecGlyph[cls][tab][slotIndex]; ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId); if (proto->Class != ITEM_CLASS_GLYPH) continue; @@ -3859,7 +3859,7 @@ Item* PlayerbotFactory::StoreItem(uint32 itemId, uint32 count) void PlayerbotFactory::InitInventoryTrade() { - uint32 itemId = sRandomItemMgr->GetRandomTrade(level); + uint32 itemId = sRandomItemMgr.GetRandomTrade(level); if (!itemId) { LOG_ERROR("playerbots", "No trade items available for bot {} ({} level)", bot->GetName().c_str(), @@ -3895,7 +3895,7 @@ void PlayerbotFactory::InitInventoryEquip() std::vector ids; uint32 desiredQuality = itemQuality; - if (urand(0, 100) < 100 * sPlayerbotAIConfig->randomGearLoweringChance && desiredQuality > ITEM_QUALITY_NORMAL) + if (urand(0, 100) < 100 * sPlayerbotAIConfig.randomGearLoweringChance && desiredQuality > ITEM_QUALITY_NORMAL) { desiredQuality--; } @@ -3949,21 +3949,21 @@ void PlayerbotFactory::InitGuild() return; } - std::string guildName = sPlayerbotGuildMgr->AssignToGuild(bot); + std::string guildName = PlayerbotGuildMgr::instance().AssignToGuild(bot); if (guildName.empty()) return; Guild* guild = sGuildMgr->GetGuildByName(guildName); if (!guild) { - if (!sPlayerbotGuildMgr->CreateGuild(bot, guildName)) + if (!PlayerbotGuildMgr::instance().CreateGuild(bot, guildName)) LOG_ERROR("playerbots","Failed to create guild {} for bot {}", guildName, bot->GetName()); return; } else { if (guild->AddMember(bot->GetGUID(),urand(GR_OFFICER, GR_INITIATE))) - sPlayerbotGuildMgr->OnGuildUpdate(guild); + PlayerbotGuildMgr::instance().OnGuildUpdate(guild); else LOG_ERROR("playerbots","Bot {} failed to join guild {}.", bot->GetName(), guildName); } @@ -3985,7 +3985,7 @@ void PlayerbotFactory::InitImmersive() std::ostringstream name; name << "immersive_stat_" << i; - uint32 value = sRandomPlayerbotMgr->GetValue(owner, name.str()); + uint32 value = sRandomPlayerbotMgr.GetValue(owner, name.str()); if (value) initialized = true; @@ -4058,7 +4058,7 @@ void PlayerbotFactory::InitImmersive() std::ostringstream name; name << "immersive_stat_" << i; - sRandomPlayerbotMgr->SetValue(owner, name.str(), percentMap[type]); + sRandomPlayerbotMgr.SetValue(owner, name.str(), percentMap[type]); } } } @@ -4066,15 +4066,15 @@ void PlayerbotFactory::InitImmersive() void PlayerbotFactory::InitArenaTeam() { - if (!sPlayerbotAIConfig->IsInRandomAccountList(bot->GetSession()->GetAccountId())) + if (!sPlayerbotAIConfig.IsInRandomAccountList(bot->GetSession()->GetAccountId())) return; // Currently the teams are only remade after a server restart and if deleteRandomBotArenaTeams = 1 // This is because randomBotArenaTeams is only empty on server restart. // A manual reinitalization (.playerbots rndbot init) is also required after the teams have been deleted. - if (sPlayerbotAIConfig->randomBotArenaTeams.empty()) + if (sPlayerbotAIConfig.randomBotArenaTeams.empty()) { - if (sPlayerbotAIConfig->deleteRandomBotArenaTeams) + if (sPlayerbotAIConfig.deleteRandomBotArenaTeams) { LOG_INFO("playerbots", "Deleting random bot arena teams..."); @@ -4099,14 +4099,14 @@ void PlayerbotFactory::InitArenaTeam() LOG_INFO("playerbots", "Random bot arena teams deleted"); } - RandomPlayerbotFactory::CreateRandomArenaTeams(ARENA_TYPE_2v2, sPlayerbotAIConfig->randomBotArenaTeam2v2Count); - RandomPlayerbotFactory::CreateRandomArenaTeams(ARENA_TYPE_3v3, sPlayerbotAIConfig->randomBotArenaTeam3v3Count); - RandomPlayerbotFactory::CreateRandomArenaTeams(ARENA_TYPE_5v5, sPlayerbotAIConfig->randomBotArenaTeam5v5Count); + RandomPlayerbotFactory::CreateRandomArenaTeams(ARENA_TYPE_2v2, sPlayerbotAIConfig.randomBotArenaTeam2v2Count); + RandomPlayerbotFactory::CreateRandomArenaTeams(ARENA_TYPE_3v3, sPlayerbotAIConfig.randomBotArenaTeam3v3Count); + RandomPlayerbotFactory::CreateRandomArenaTeams(ARENA_TYPE_5v5, sPlayerbotAIConfig.randomBotArenaTeam5v5Count); } std::vector arenateams; - for (std::vector::iterator i = sPlayerbotAIConfig->randomBotArenaTeams.begin(); - i != sPlayerbotAIConfig->randomBotArenaTeams.end(); ++i) + for (std::vector::iterator i = sPlayerbotAIConfig.randomBotArenaTeams.begin(); + i != sPlayerbotAIConfig.randomBotArenaTeams.end(); ++i) arenateams.push_back(*i); if (arenateams.empty()) @@ -4300,7 +4300,7 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destroyOld) if (!gemProperties) continue; - if (sPlayerbotAIConfig->limitEnchantExpansion && bot->GetLevel() <= 70 && enchantGem >= 39900) + if (sPlayerbotAIConfig.limitEnchantExpansion && bot->GetLevel() <= 70 && enchantGem >= 39900) continue; uint32 requiredLevel = gemTemplate->ItemLevel; @@ -4363,10 +4363,10 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destroyOld) } // disable next expansion enchantments - if (sPlayerbotAIConfig->limitEnchantExpansion && bot->GetLevel() <= 60 && enchantSpell >= 27899) + if (sPlayerbotAIConfig.limitEnchantExpansion && bot->GetLevel() <= 60 && enchantSpell >= 27899) continue; - if (sPlayerbotAIConfig->limitEnchantExpansion && bot->GetLevel() <= 70 && enchantSpell >= 44483) + if (sPlayerbotAIConfig.limitEnchantExpansion && bot->GetLevel() <= 70 && enchantSpell >= 44483) continue; for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j) diff --git a/src/Bot/Factory/RandomPlayerbotFactory.cpp b/src/Bot/Factory/RandomPlayerbotFactory.cpp index 5a4672f5eb..0fd7e90e21 100644 --- a/src/Bot/Factory/RandomPlayerbotFactory.cpp +++ b/src/Bot/Factory/RandomPlayerbotFactory.cpp @@ -317,14 +317,14 @@ uint32 RandomPlayerbotFactory::CalculateTotalAccountCount() { // Reset account types if features are disabled // Reset is done here to precede needed accounts calculations - if (sPlayerbotAIConfig->maxRandomBots == 0 || sPlayerbotAIConfig->addClassAccountPoolSize == 0) + if (sPlayerbotAIConfig.maxRandomBots == 0 || sPlayerbotAIConfig.addClassAccountPoolSize == 0) { - if (sPlayerbotAIConfig->maxRandomBots == 0) + if (sPlayerbotAIConfig.maxRandomBots == 0) { PlayerbotsDatabase.Execute("UPDATE playerbots_account_type SET account_type = 0 WHERE account_type = 1"); LOG_INFO("playerbots", "MaxRandomBots set to 0, any RNDbot accounts (type 1) will be unassigned (type 0)"); } - if (sPlayerbotAIConfig->addClassAccountPoolSize == 0) + if (sPlayerbotAIConfig.addClassAccountPoolSize == 0) { PlayerbotsDatabase.Execute("UPDATE playerbots_account_type SET account_type = 0 WHERE account_type = 2"); LOG_INFO("playerbots", "AddClassAccountPoolSize set to 0, any AddClass accounts (type 2) will be unassigned (type 0)"); @@ -334,8 +334,8 @@ uint32 RandomPlayerbotFactory::CalculateTotalAccountCount() for (int waited = 0; waited < 1000; waited += 50) { QueryResult res = PlayerbotsDatabase.Query("SELECT COUNT(*) FROM playerbots_account_type WHERE account_type IN ({}, {})", - sPlayerbotAIConfig->maxRandomBots == 0 ? 1 : -1, - sPlayerbotAIConfig->addClassAccountPoolSize == 0 ? 2 : -1); + sPlayerbotAIConfig.maxRandomBots == 0 ? 1 : -1, + sPlayerbotAIConfig.addClassAccountPoolSize == 0 ? 2 : -1); if (!res || res->Fetch()[0].Get() == 0) { @@ -347,8 +347,8 @@ uint32 RandomPlayerbotFactory::CalculateTotalAccountCount() } // Checks if randomBotAccountCount is set, otherwise calculate it dynamically. - if (sPlayerbotAIConfig->randomBotAccountCount > 0) - return sPlayerbotAIConfig->randomBotAccountCount; + if (sPlayerbotAIConfig.randomBotAccountCount > 0) + return sPlayerbotAIConfig.randomBotAccountCount; // Check existing account types uint32 existingRndBotAccounts = 0; @@ -374,17 +374,17 @@ uint32 RandomPlayerbotFactory::CalculateTotalAccountCount() int divisor = CalculateAvailableCharsPerAccount(); // Calculate max bots - int maxBots = sPlayerbotAIConfig->maxRandomBots; + int maxBots = sPlayerbotAIConfig.maxRandomBots; // Take periodic online - offline into account - if (sPlayerbotAIConfig->enablePeriodicOnlineOffline) + if (sPlayerbotAIConfig.enablePeriodicOnlineOffline) { - maxBots *= sPlayerbotAIConfig->periodicOnlineOfflineRatio; + maxBots *= sPlayerbotAIConfig.periodicOnlineOfflineRatio; } // Calculate number of accounts needed for RNDbots // Result is rounded up for maxBots not cleanly divisible by the divisor uint32 neededRndBotAccounts = (maxBots + divisor - 1) / divisor; - uint32 neededAddClassAccounts = sPlayerbotAIConfig->addClassAccountPoolSize; + uint32 neededAddClassAccounts = sPlayerbotAIConfig.addClassAccountPoolSize; // Start with existing total uint32 existingTotal = existingRndBotAccounts + existingAddClassAccounts + existingUnassignedAccounts; @@ -425,12 +425,12 @@ uint32 RandomPlayerbotFactory::CalculateTotalAccountCount() uint32 RandomPlayerbotFactory::CalculateAvailableCharsPerAccount() { - bool noDK = sPlayerbotAIConfig->disableDeathKnightLogin || sWorld->getIntConfig(CONFIG_EXPANSION) != EXPANSION_WRATH_OF_THE_LICH_KING; + bool noDK = sPlayerbotAIConfig.disableDeathKnightLogin || sWorld->getIntConfig(CONFIG_EXPANSION) != EXPANSION_WRATH_OF_THE_LICH_KING; uint32 availableChars = noDK ? 9 : 10; - uint32 hordeRatio = sPlayerbotAIConfig->randomBotHordeRatio; - uint32 allianceRatio = sPlayerbotAIConfig->randomBotAllianceRatio; + uint32 hordeRatio = sPlayerbotAIConfig.randomBotHordeRatio; + uint32 allianceRatio = sPlayerbotAIConfig.randomBotAllianceRatio; // horde : alliance = 50 : 50 -> 0% // horde : alliance = 0 : 50 -> 50% @@ -451,7 +451,7 @@ void RandomPlayerbotFactory::CreateRandomBots() { /* multi-thread here is meaningless? since the async db operations */ - if (sPlayerbotAIConfig->deleteRandomBotAccounts) + if (sPlayerbotAIConfig.deleteRandomBotAccounts) { std::vector botAccounts; std::vector botFriends; @@ -462,7 +462,7 @@ void RandomPlayerbotFactory::CreateRandomBots() for (uint32 accountNumber = 0; accountNumber < totalAccountCount; ++accountNumber) { std::ostringstream out; - out << sPlayerbotAIConfig->randomBotAccountPrefix << accountNumber; + out << sPlayerbotAIConfig.randomBotAccountPrefix << accountNumber; std::string const accountName = out.str(); if (uint32 accountId = AccountMgr::GetId(accountName)) @@ -482,7 +482,7 @@ void RandomPlayerbotFactory::CreateRandomBots() // Delete all characters from bot accounts CharacterDatabase.Execute("DELETE FROM characters WHERE account IN (SELECT id FROM " + loginDBName + ".account WHERE username LIKE '{}%%')", - sPlayerbotAIConfig->randomBotAccountPrefix.c_str()); + sPlayerbotAIConfig.randomBotAccountPrefix.c_str()); // Wait for the characters to be deleted before proceeding to dependent deletes while (CharacterDatabase.QueueSize()) @@ -496,7 +496,7 @@ void RandomPlayerbotFactory::CreateRandomBots() // Clean up orphaned entries in playerbots_db_store PlayerbotsDatabase.Execute("DELETE FROM playerbots_db_store WHERE guid NOT IN (SELECT guid FROM " + characterDBName + ".characters WHERE account IN (SELECT id FROM " + loginDBName + ".account WHERE username NOT LIKE '{}%%'))", - sPlayerbotAIConfig->randomBotAccountPrefix.c_str()); + sPlayerbotAIConfig.randomBotAccountPrefix.c_str()); // Clean up orphaned records in character-related tables CharacterDatabase.Execute("DELETE FROM arena_team_member WHERE guid NOT IN (SELECT guid FROM characters)"); @@ -551,7 +551,7 @@ void RandomPlayerbotFactory::CreateRandomBots() // Finally, delete the bot accounts themselves LOG_INFO("playerbots", "Deleting random bot accounts..."); QueryResult results = LoginDatabase.Query("SELECT id FROM account WHERE username LIKE '{}%%'", - sPlayerbotAIConfig->randomBotAccountPrefix.c_str()); + sPlayerbotAIConfig.randomBotAccountPrefix.c_str()); int32 deletion_count = 0; if (results) { @@ -601,7 +601,7 @@ void RandomPlayerbotFactory::CreateRandomBots() for (uint32 accountNumber = 0; accountNumber < totalAccountCount; ++accountNumber) { std::ostringstream out; - out << sPlayerbotAIConfig->randomBotAccountPrefix << accountNumber; + out << sPlayerbotAIConfig.randomBotAccountPrefix << accountNumber; std::string const accountName = out.str(); LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ID_BY_USERNAME); @@ -613,7 +613,7 @@ void RandomPlayerbotFactory::CreateRandomBots() } account_creation++; std::string password = ""; - if (sPlayerbotAIConfig->randomBotRandomPassword) + if (sPlayerbotAIConfig.randomBotRandomPassword) { for (int i = 0; i < 10; i++) { @@ -649,7 +649,7 @@ void RandomPlayerbotFactory::CreateRandomBots() for (uint32 accountNumber = 0; accountNumber < totalAccountCount; ++accountNumber) { std::ostringstream out; - out << sPlayerbotAIConfig->randomBotAccountPrefix << accountNumber; + out << sPlayerbotAIConfig.randomBotAccountPrefix << accountNumber; std::string const accountName = out.str(); LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ID_BY_USERNAME); @@ -661,7 +661,7 @@ void RandomPlayerbotFactory::CreateRandomBots() Field* fields = result->Fetch(); uint32 accountId = fields[0].Get(); - sPlayerbotAIConfig->randomBotAccounts.push_back(accountId); + sPlayerbotAIConfig.randomBotAccounts.push_back(accountId); uint32 count = AccountMgr::GetCharactersCount(accountId); if (count >= 10) @@ -746,13 +746,13 @@ void RandomPlayerbotFactory::CreateRandomBots() for (WorldSession* session : sessionBots) delete session; - for (uint32 accountId : sPlayerbotAIConfig->randomBotAccounts) + for (uint32 accountId : sPlayerbotAIConfig.randomBotAccounts) { totalRandomBotChars += AccountMgr::GetCharactersCount(accountId); } LOG_INFO("server.loading", ">> {} random bot accounts with {} characters available", - sPlayerbotAIConfig->randomBotAccounts.size(), totalRandomBotChars); + sPlayerbotAIConfig.randomBotAccounts.size(), totalRandomBotChars); } std::string const RandomPlayerbotFactory::CreateRandomGuildName() @@ -811,7 +811,7 @@ void RandomPlayerbotFactory::CreateRandomArenaTeams(ArenaType type, uint32 count if (arenateam) { ++arenaTeamNumber; - sPlayerbotAIConfig->randomBotArenaTeams.push_back(arenateam->GetId()); + sPlayerbotAIConfig.randomBotArenaTeams.push_back(arenateam->GetId()); } else { @@ -872,7 +872,7 @@ void RandomPlayerbotFactory::CreateRandomArenaTeams(ArenaType type, uint32 count // set random rating arenateam->SetRatingForAll( - urand(sPlayerbotAIConfig->randomBotArenaTeamMinRating, sPlayerbotAIConfig->randomBotArenaTeamMaxRating)); + urand(sPlayerbotAIConfig.randomBotArenaTeamMinRating, sPlayerbotAIConfig.randomBotArenaTeamMaxRating)); // set random emblem uint32 backgroundColor = urand(0xFF000000, 0xFFFFFFFF); @@ -891,7 +891,7 @@ void RandomPlayerbotFactory::CreateRandomArenaTeams(ArenaType type, uint32 count arenateam->SaveToDB(); sArenaTeamMgr->AddArenaTeam(arenateam); - sPlayerbotAIConfig->randomBotArenaTeams.push_back(arenateam->GetId()); + sPlayerbotAIConfig.randomBotArenaTeams.push_back(arenateam->GetId()); } LOG_DEBUG("playerbots", "{} random bot {}vs{} arena teams available", arenaTeamNumber, type, type); diff --git a/src/Bot/PlayerbotAI.cpp b/src/Bot/PlayerbotAI.cpp index 49efe09275..b5b59c3b1b 100644 --- a/src/Bot/PlayerbotAI.cpp +++ b/src/Bot/PlayerbotAI.cpp @@ -16,7 +16,6 @@ #include "CharacterPackets.h" #include "ChatHelper.h" #include "Common.h" -#include "CreatureAIImpl.h" #include "CreatureData.h" #include "EmoteAction.h" #include "Engine.h" @@ -33,7 +32,6 @@ #include "LootObjectStack.h" #include "MapMgr.h" #include "MotionMaster.h" -#include "MoveSpline.h" #include "MoveSplineInit.h" #include "NewRpgStrategy.h" #include "ObjectGuid.h" @@ -45,7 +43,6 @@ #include "PlayerbotMgr.h" #include "PlayerbotGuildMgr.h" #include "Playerbots.h" -#include "PointMovementGenerator.h" #include "PositionValue.h" #include "RandomPlayerbotMgr.h" #include "SayAction.h" @@ -153,7 +150,7 @@ PlayerbotAI::PlayerbotAI(Player* bot) engines[BOT_STATE_COMBAT] = AiFactory::createCombatEngine(bot, this, aiObjectContext); engines[BOT_STATE_NON_COMBAT] = AiFactory::createNonCombatEngine(bot, this, aiObjectContext); engines[BOT_STATE_DEAD] = AiFactory::createDeadEngine(bot, this, aiObjectContext); - if (sPlayerbotAIConfig->applyInstanceStrategies) + if (sPlayerbotAIConfig.applyInstanceStrategies) ApplyInstanceStrategies(bot->GetMapId()); currentEngine = engines[BOT_STATE_NON_COMBAT]; currentState = BOT_STATE_NON_COMBAT; @@ -233,7 +230,7 @@ PlayerbotAI::~PlayerbotAI() delete aiObjectContext; if (bot) - sPlayerbotsMgr->RemovePlayerBotData(bot->GetGUID(), true); + PlayerbotsMgr::instance().RemovePlayerBotData(bot->GetGUID(), true); } void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal) @@ -251,7 +248,7 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal) // Handle cheat options (set bot health and power if cheats are enabled) if (bot->IsAlive() && - (static_cast(GetCheat()) > 0 || static_cast(sPlayerbotAIConfig->botCheatMask) > 0)) + (static_cast(GetCheat()) > 0 || static_cast(sPlayerbotAIConfig.botCheatMask) > 0)) { if (HasCheat(BotCheatMask::health)) bot->SetFullHealth(); @@ -332,7 +329,7 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal) if (spellTarget && !bot->HasInArc(CAST_ANGLE_IN_FRONT, spellTarget) && (spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT)) { - sServerFacade->SetFacingTo(bot, spellTarget); + ServerFacade::instance().SetFacingTo(bot, spellTarget); } // Wait for spell cast @@ -387,7 +384,7 @@ void PlayerbotAI::UpdateAIGroupMaster() Group* group = bot->GetGroup(); - bool IsRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot); + bool IsRandomBot = sRandomPlayerbotMgr.IsRandomBot(bot); // If bot is not in group verify that for is RandomBot before clearing master and resetting. if (!group) @@ -451,7 +448,7 @@ void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal std::string const mapString = WorldPosition(bot).isOverworld() ? std::to_string(bot->GetMapId()) : "I"; PerfMonitorOperation* pmo = - sPerfMonitor->start(PERF_MON_TOTAL, "PlayerbotAI::UpdateAIInternal " + mapString); + sPerfMonitor.start(PERF_MON_TOTAL, "PlayerbotAI::UpdateAIInternal " + mapString); ExternalEventHelper helper(aiObjectContext); // chat replies @@ -503,12 +500,12 @@ void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal } else { - sRandomPlayerbotMgr->LogoutPlayerBot(bot->GetGUID()); + sRandomPlayerbotMgr.LogoutPlayerBot(bot->GetGUID()); } return; } - SetNextCheckDelay(sPlayerbotAIConfig->reactDelay); + SetNextCheckDelay(sPlayerbotAIConfig.reactDelay); return; } @@ -583,10 +580,10 @@ void PlayerbotAI::HandleCommand(uint32 type, const std::string& text, Player& fr if (type == CHAT_MSG_SYSTEM) return; - if (filtered.find(sPlayerbotAIConfig->commandSeparator) != std::string::npos) + if (filtered.find(sPlayerbotAIConfig.commandSeparator) != std::string::npos) { std::vector commands; - split(commands, filtered, sPlayerbotAIConfig->commandSeparator.c_str()); + split(commands, filtered, sPlayerbotAIConfig.commandSeparator.c_str()); for (std::vector::iterator i = commands.begin(); i != commands.end(); ++i) { HandleCommand(type, *i, fromPlayer); @@ -594,12 +591,12 @@ void PlayerbotAI::HandleCommand(uint32 type, const std::string& text, Player& fr return; } - if (!sPlayerbotAIConfig->commandPrefix.empty()) + if (!sPlayerbotAIConfig.commandPrefix.empty()) { - if (filtered.find(sPlayerbotAIConfig->commandPrefix) != 0) + if (filtered.find(sPlayerbotAIConfig.commandPrefix) != 0) return; - filtered = filtered.substr(sPlayerbotAIConfig->commandPrefix.size()); + filtered = filtered.substr(sPlayerbotAIConfig.commandPrefix.size()); } if (chatMap.empty()) @@ -631,7 +628,7 @@ void PlayerbotAI::HandleCommand(uint32 type, const std::string& text, Player& fr WorldPacket data; ChatHandler::BuildChatPacket(data, CHAT_MSG_ADDON, response.c_str(), LANG_ADDON, CHAT_TAG_NONE, bot->GetGUID(), bot->GetName()); - sServerFacade->SendPacket(&fromPlayer, &data); + ServerFacade::instance().SendPacket(&fromPlayer, &data); return; } @@ -761,10 +758,10 @@ void PlayerbotAI::HandleTeleportAck() } // apply instance-related strategies after map attach - if (sPlayerbotAIConfig->applyInstanceStrategies) + if (sPlayerbotAIConfig.applyInstanceStrategies) ApplyInstanceStrategies(bot->GetMapId(), true); - if (sPlayerbotAIConfig->restrictHealerDPS) + if (sPlayerbotAIConfig.restrictHealerDPS) EvaluateHealerDpsStrategy(); // reset AI state after teleport @@ -855,7 +852,7 @@ void PlayerbotAI::Reset(bool full) aiObjectContext->GetValue("last taxi")->Get().Set(nullptr); aiObjectContext->GetValue("travel target") ->Get() - ->setTarget(sTravelMgr->nullTravelDestination, sTravelMgr->nullWorldPosition, true); + ->setTarget(TravelMgr::instance().nullTravelDestination, TravelMgr::instance().nullWorldPosition, true); aiObjectContext->GetValue("travel target")->Get()->setStatus(TRAVEL_STATUS_EXPIRED); aiObjectContext->GetValue("travel target")->Get()->setExpireIn(1000); rpgInfo = NewRpgInfo(); @@ -895,6 +892,7 @@ bool PlayerbotAI::IsAllowedCommand(std::string const text) unsecuredCommands.insert("invite"); unsecuredCommands.insert("leave"); unsecuredCommands.insert("lfg"); + unsecuredCommands.insert("pvp stats"); unsecuredCommands.insert("rpg status"); } @@ -920,10 +918,10 @@ void PlayerbotAI::HandleCommand(uint32 type, std::string const text, Player* fro if (type == CHAT_MSG_SYSTEM) return; - if (text.find(sPlayerbotAIConfig->commandSeparator) != std::string::npos) + if (text.find(sPlayerbotAIConfig.commandSeparator) != std::string::npos) { std::vector commands; - split(commands, text, sPlayerbotAIConfig->commandSeparator.c_str()); + split(commands, text, sPlayerbotAIConfig.commandSeparator.c_str()); for (std::vector::iterator i = commands.begin(); i != commands.end(); ++i) { HandleCommand(type, *i, fromPlayer); @@ -933,12 +931,12 @@ void PlayerbotAI::HandleCommand(uint32 type, std::string const text, Player* fro } std::string filtered = text; - if (!sPlayerbotAIConfig->commandPrefix.empty()) + if (!sPlayerbotAIConfig.commandPrefix.empty()) { - if (filtered.find(sPlayerbotAIConfig->commandPrefix) != 0) + if (filtered.find(sPlayerbotAIConfig.commandPrefix) != 0) return; - filtered = filtered.substr(sPlayerbotAIConfig->commandPrefix.size()); + filtered = filtered.substr(sPlayerbotAIConfig.commandPrefix.size()); } if (chatMap.empty()) @@ -1100,7 +1098,7 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet) } case SMSG_MESSAGECHAT: // do not react to self or if not ready to reply { - if (!sPlayerbotAIConfig->randomBotTalk) + if (!sPlayerbotAIConfig.randomBotTalk) return; if (!AllowActivity()) @@ -1156,7 +1154,7 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet) bool isFromFreeBot = false; sCharacterCache->GetCharacterNameByGuid(guid1, name); uint32 accountId = sCharacterCache->GetCharacterAccountIdByGuid(guid1); - isFromFreeBot = sPlayerbotAIConfig->IsInRandomAccountList(accountId); + isFromFreeBot = sPlayerbotAIConfig.IsInRandomAccountList(accountId); bool isMentioned = message.find(bot->GetName()) != std::string::npos; // ChatChannelSource chatChannelSource = GetChatChannelSource(bot, msgtype, chanName); @@ -1174,20 +1172,20 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet) if (lang == LANG_ADDON) return; - if (message.starts_with(sPlayerbotAIConfig->toxicLinksPrefix) && + if (message.starts_with(sPlayerbotAIConfig.toxicLinksPrefix) && (GetChatHelper()->ExtractAllItemIds(message).size() > 0 || GetChatHelper()->ExtractAllQuestIds(message).size() > 0) && - sPlayerbotAIConfig->toxicLinksRepliesChance) + sPlayerbotAIConfig.toxicLinksRepliesChance) { - if (urand(0, 50) > 0 || urand(1, 100) > sPlayerbotAIConfig->toxicLinksRepliesChance) + if (urand(0, 50) > 0 || urand(1, 100) > sPlayerbotAIConfig.toxicLinksRepliesChance) { return; } } else if ((GetChatHelper()->ExtractAllItemIds(message).count(19019) && - sPlayerbotAIConfig->thunderfuryRepliesChance)) + sPlayerbotAIConfig.thunderfuryRepliesChance)) { - if (urand(0, 60) > 0 || urand(1, 100) > sPlayerbotAIConfig->thunderfuryRepliesChance) + if (urand(0, 60) > 0 || urand(1, 100) > sPlayerbotAIConfig.thunderfuryRepliesChance) { return; } @@ -1197,8 +1195,8 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet) if (isFromFreeBot && urand(0, 20)) return; - // if (msgtype == CHAT_MSG_GUILD && (!sPlayerbotAIConfig->guildRepliesRate || urand(1, 100) >= - // sPlayerbotAIConfig->guildRepliesRate)) return; + // if (msgtype == CHAT_MSG_GUILD && (!sPlayerbotAIConfig.guildRepliesRate || urand(1, 100) >= + // sPlayerbotAIConfig.guildRepliesRate)) return; if (!isFromFreeBot) { @@ -1285,7 +1283,7 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet) // bot->GetMotionMaster()->MoveKnockbackFrom(fx, fy, horizontalSpeed, verticalSpeed); // // set delay based on actual distance - // float newdis = sqrt(sServerFacade->GetDistance2d(bot, fx, fy)); + // float newdis = sqrt(ServerFacade::instance().GetDistance2d(bot, fx, fy)); // SetNextCheckDelay((uint32)((newdis / dis) * moveTimeHalf * 4 * IN_MILLISECONDS)); // // add moveflags @@ -1347,9 +1345,9 @@ int32 PlayerbotAI::CalculateGlobalCooldown(uint32 spellid) return 0; if (bot->HasSpellCooldown(spellid)) - return sPlayerbotAIConfig->globalCoolDown; + return sPlayerbotAIConfig.globalCoolDown; - return sPlayerbotAIConfig->reactDelay; + return sPlayerbotAIConfig.reactDelay; } void PlayerbotAI::HandleMasterIncomingPacket(WorldPacket const& packet) @@ -1410,7 +1408,7 @@ void PlayerbotAI::DoNextAction(bool min) { if (!bot->IsInWorld() || bot->IsBeingTeleported() || (GetMaster() && GetMaster()->IsBeingTeleported())) { - SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown); + SetNextCheckDelay(sPlayerbotAIConfig.globalCoolDown); return; } @@ -1454,7 +1452,7 @@ void PlayerbotAI::DoNextAction(bool min) } } - bool minimal = !AllowActivity(); + bool minimal = !this->AllowActivity(); currentEngine->DoNextAction(nullptr, 0, (minimal || min)); @@ -1463,7 +1461,7 @@ void PlayerbotAI::DoNextAction(bool min) if (!bot->isAFK() && !bot->InBattleground() && !HasRealPlayerMaster()) bot->ToggleAFK(); - SetNextCheckDelay(sPlayerbotAIConfig->passiveDelay); + SetNextCheckDelay(sPlayerbotAIConfig.passiveDelay); return; } else if (bot->isAFK()) @@ -1471,7 +1469,8 @@ void PlayerbotAI::DoNextAction(bool min) if (master && master->IsInWorld()) { - float distance = sServerFacade->GetDistance2d(bot, master); + float distance = ServerFacade::instance().GetDistance2d(bot, master); + if (master->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING) && distance < 20.0f) bot->m_movementInfo.AddMovementFlag(MOVEMENTFLAG_WALKING); else @@ -1552,6 +1551,9 @@ void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster) case 532: strategyName = "karazhan"; // Karazhan break; + case 533: + strategyName = "naxx"; // Naxxramas + break; case 544: strategyName = "magtheridon"; // Magtheridon's Lair break; @@ -1704,7 +1706,7 @@ bool PlayerbotAI::PlayEmote(uint32 emote) WorldPacket data(SMSG_TEXT_EMOTE); data << (TextEmotes)emote; data << EmoteAction::GetNumberOfEmoteVariants((TextEmotes)emote, bot->getRace(), bot->getGender()); - data << ((master && (sServerFacade->GetDistance2d(bot, master) < 30.0f) && urand(0, 1)) ? master->GetGUID() + data << ((master && (ServerFacade::instance().GetDistance2d(bot, master) < 30.0f) && urand(0, 1)) ? master->GetGUID() : (bot->GetTarget() && urand(0, 1)) ? bot->GetTarget() : ObjectGuid::Empty); bot->GetSession()->HandleTextEmoteOpcode(data); @@ -1733,14 +1735,14 @@ void PlayerbotAI::ResetStrategies(bool load) AiFactory::AddDefaultCombatStrategies(bot, this, engines[BOT_STATE_COMBAT]); AiFactory::AddDefaultNonCombatStrategies(bot, this, engines[BOT_STATE_NON_COMBAT]); AiFactory::AddDefaultDeadStrategies(bot, this, engines[BOT_STATE_DEAD]); - if (sPlayerbotAIConfig->applyInstanceStrategies) + if (sPlayerbotAIConfig.applyInstanceStrategies) ApplyInstanceStrategies(bot->GetMapId()); for (uint8 i = 0; i < BOT_STATE_MAX; i++) engines[i]->Init(); // if (load) - // sPlayerbotRepository->Load(this); + // PlayerbotRepository::instance().Load(this); } bool PlayerbotAI::IsRanged(Player* player, bool bySpec) @@ -1796,35 +1798,46 @@ bool PlayerbotAI::IsCombo(Player* player) bool PlayerbotAI::IsRangedDps(Player* player, bool bySpec) { return IsRanged(player, bySpec) && IsDps(player, bySpec); } -bool PlayerbotAI::IsHealAssistantOfIndex(Player* player, int index) +bool PlayerbotAI::IsAssistHealOfIndex(Player* player, int index, bool ignoreDeadPlayers) { Group* group = player->GetGroup(); if (!group) - { return false; - } int counter = 0; + // First, assistants for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) { Player* member = ref->GetSource(); - if (!member) - { continue; - } - if (IsHeal(member)) // Check if the member is a healer - { - bool isAssistant = group->IsAssistant(member->GetGUID()); + if (ignoreDeadPlayers && !member->IsAlive()) + continue; - // Check if the index matches for both assistant and non-assistant healers - if ((isAssistant && index == counter) || (!isAssistant && index == counter)) - { + if (group->IsAssistant(member->GetGUID()) && IsHeal(member)) + { + if (index == counter) return player == member; - } + counter++; + } + } + + // If not enough assistants, get non-assistants + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + Player* member = ref->GetSource(); + if (!member) + continue; + if (ignoreDeadPlayers && !member->IsAlive()) + continue; + + if (!group->IsAssistant(member->GetGUID()) && IsHeal(member)) + { + if (index == counter) + return player == member; counter++; } } @@ -1832,35 +1845,46 @@ bool PlayerbotAI::IsHealAssistantOfIndex(Player* player, int index) return false; } -bool PlayerbotAI::IsRangedDpsAssistantOfIndex(Player* player, int index) +bool PlayerbotAI::IsAssistRangedDpsOfIndex(Player* player, int index, bool ignoreDeadPlayers) { Group* group = player->GetGroup(); if (!group) - { return false; - } int counter = 0; + // First, assistants for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) { Player* member = ref->GetSource(); - if (!member) - { continue; - } - if (IsRangedDps(member)) // Check if the member is a ranged DPS - { - bool isAssistant = group->IsAssistant(member->GetGUID()); + if (ignoreDeadPlayers && !member->IsAlive()) + continue; - // Check the index for both assistant and non-assistant ranges - if ((isAssistant && index == counter) || (!isAssistant && index == counter)) - { + if (group->IsAssistant(member->GetGUID()) && IsRangedDps(member)) + { + if (index == counter) return player == member; - } + counter++; + } + } + + // If not enough assistants, get non-assistants + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + Player* member = ref->GetSource(); + if (!member) + continue; + if (ignoreDeadPlayers && !member->IsAlive()) + continue; + + if (!group->IsAssistant(member->GetGUID()) && IsRangedDps(member)) + { + if (index == counter) + return player == member; counter++; } } @@ -2335,18 +2359,16 @@ bool PlayerbotAI::IsAssistTankOfIndex(Player* player, int index, bool ignoreDead { Group* group = player->GetGroup(); if (!group) - { return false; - } + int counter = 0; + + // First, assistants for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) { Player* member = ref->GetSource(); - if (!member) - { continue; - } if (ignoreDeadPlayers && !member->IsAlive()) continue; @@ -2354,21 +2376,17 @@ bool PlayerbotAI::IsAssistTankOfIndex(Player* player, int index, bool ignoreDead if (group->IsAssistant(member->GetGUID()) && IsAssistTank(member)) { if (index == counter) - { return player == member; - } counter++; } } - // not enough + + // If not enough assistants, get non-assistants for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) { Player* member = ref->GetSource(); - if (!member) - { continue; - } if (ignoreDeadPlayers && !member->IsAlive()) continue; @@ -2376,9 +2394,7 @@ bool PlayerbotAI::IsAssistTankOfIndex(Player* player, int index, bool ignoreDead if (!group->IsAssistant(member->GetGUID()) && IsAssistTank(member)) { if (index == counter) - { return player == member; - } counter++; } } @@ -2704,7 +2720,7 @@ bool PlayerbotAI::SayToParty(const std::string& msg) for (auto reciever : GetPlayersInGroup()) { - sServerFacade->SendPacket(reciever, &data); + ServerFacade::instance().SendPacket(reciever, &data); } return true; @@ -2721,7 +2737,7 @@ bool PlayerbotAI::SayToRaid(const std::string& msg) for (auto reciever : GetPlayersInGroup()) { - sServerFacade->SendPacket(reciever, &data); + ServerFacade::instance().SendPacket(reciever, &data); } return true; @@ -2788,7 +2804,7 @@ bool PlayerbotAI::TellMasterNoFacing(std::string const text, PlayerbotSecurityLe masterBotAI = GET_PLAYERBOT_AI(master); if ((!master || (masterBotAI && !masterBotAI->IsRealPlayer())) && - (sPlayerbotAIConfig->randomBotSayWithoutMaster || HasStrategy("debug", BOT_STATE_NON_COMBAT))) + (sPlayerbotAIConfig.randomBotSayWithoutMaster || HasStrategy("debug", BOT_STATE_NON_COMBAT))) { bot->Say(text, (bot->GetTeamId() == TEAM_ALLIANCE ? LANG_COMMON : LANG_ORCISH)); return true; @@ -2799,7 +2815,7 @@ bool PlayerbotAI::TellMasterNoFacing(std::string const text, PlayerbotSecurityLe time_t lastSaid = whispers[text]; - if (!lastSaid || (time(nullptr) - lastSaid) >= sPlayerbotAIConfig->repeatDelay / 1000) + if (!lastSaid || (time(nullptr) - lastSaid) >= sPlayerbotAIConfig.repeatDelay / 1000) { whispers[text] = time(nullptr); @@ -2837,10 +2853,10 @@ bool PlayerbotAI::IsTellAllowed(PlayerbotSecurityLevel securityLevel) if (!GetSecurity()->CheckLevelFor(securityLevel, true, master)) return false; - if (sPlayerbotAIConfig->whisperDistance && !bot->GetGroup() && sRandomPlayerbotMgr->IsRandomBot(bot) && + if (sPlayerbotAIConfig.whisperDistance && !bot->GetGroup() && sRandomPlayerbotMgr.IsRandomBot(bot) && master->GetSession()->GetSecurity() < SEC_GAMEMASTER && (bot->GetMapId() != master->GetMapId() || - sServerFacade->GetDistance2d(bot, master) > sPlayerbotAIConfig->whisperDistance)) + ServerFacade::instance().GetDistance2d(bot, master) > sPlayerbotAIConfig.whisperDistance)) return false; return true; @@ -2855,7 +2871,7 @@ bool PlayerbotAI::TellMaster(std::string const text, PlayerbotSecurityLevel secu { if (!master) { - if (sPlayerbotAIConfig->randomBotSayWithoutMaster) + if (sPlayerbotAIConfig.randomBotSayWithoutMaster) return TellMasterNoFacing(text, securityLevel); } if (!TellMasterNoFacing(text, securityLevel)) @@ -2864,7 +2880,7 @@ bool PlayerbotAI::TellMaster(std::string const text, PlayerbotSecurityLevel secu if (!bot->isMoving() && !bot->IsInCombat() && bot->GetMapId() == master->GetMapId() && !bot->HasUnitState(UNIT_STATE_IN_FLIGHT) && !bot->IsFlying()) { - if (!bot->HasInArc(EMOTE_ANGLE_IN_FRONT, master, sPlayerbotAIConfig->sightDistance)) + if (!bot->HasInArc(EMOTE_ANGLE_IN_FRONT, master, sPlayerbotAIConfig.sightDistance)) bot->SetFacingToObject(master); bot->HandleEmoteCommand(EMOTE_ONESHOT_TALK); @@ -3078,7 +3094,7 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell, { if (!spellid) { - if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) + if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) { LOG_DEBUG("playerbots", "Can cast spell failed. No spellid. - spellid: {}, bot name: {}", spellid, bot->GetName()); @@ -3088,7 +3104,7 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell, if (bot->HasUnitState(UNIT_STATE_LOST_CONTROL)) { - if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) + if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) { LOG_DEBUG("playerbots", "Can cast spell failed. Unit state lost control. - spellid: {}, bot name: {}", spellid, bot->GetName()); @@ -3108,7 +3124,7 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell, if (checkHasSpell && !bot->HasSpell(spellid)) { - if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) + if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) { LOG_DEBUG("playerbots", "Can cast spell failed. Bot not has spell. - target name: {}, spellid: {}, bot name: {}", @@ -3119,7 +3135,7 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell, if (bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL) != nullptr) { - if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) + if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) { LOG_DEBUG( "playerbots", @@ -3131,7 +3147,7 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell, if (bot->HasSpellCooldown(spellid)) { - if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) + if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) { LOG_DEBUG("playerbots", "Can cast spell failed. Spell not has cooldown. - target name: {}, spellid: {}, bot name: {}", @@ -3143,7 +3159,7 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell, SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid); if (!spellInfo) { - if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) + if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) { LOG_DEBUG("playerbots", "Can cast spell failed. No spellInfo. - target name: {}, spellid: {}, bot name: {}", target->GetName(), spellid, bot->GetName()); @@ -3153,7 +3169,7 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell, if ((bot->GetShapeshiftForm() == FORM_FLIGHT || bot->GetShapeshiftForm() == FORM_FLIGHT_EPIC) && !bot->IsInCombat()) { - if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) + if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) { LOG_DEBUG( "playerbots", @@ -3167,7 +3183,7 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell, // bool interruptOnMove = spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT; if ((CastingTime || spellInfo->IsAutoRepeatRangedSpell()) && bot->isMoving()) { - if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) + if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) { LOG_DEBUG("playerbots", "Casting time and bot is moving - target name: {}, spellid: {}, bot name: {}", target->GetName(), spellid, bot->GetName()); @@ -3182,7 +3198,7 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell, { if (spellid != 44572) // Deep Freeze { - if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) + if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) { LOG_DEBUG("playerbots", "target is immuned to spell - target name: {}, spellid: {}, bot name: {}", target->GetName(), spellid, bot->GetName()); @@ -3192,9 +3208,9 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell, // Otherwise, allow Deep Freeze even if immune } - if (bot != target && sServerFacade->GetDistance2d(bot, target) > sPlayerbotAIConfig->sightDistance) + if (bot != target && ServerFacade::instance().GetDistance2d(bot, target) > sPlayerbotAIConfig.sightDistance) { - if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) + if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) { LOG_DEBUG("playerbots", "target is out of sight distance - target name: {}, spellid: {}, bot name: {}", target->GetName(), spellid, bot->GetName()); @@ -3220,7 +3236,7 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell, SpellCastResult result = spell->CheckCast(true); delete spell; - // if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) + // if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) // { // if (result != SPELL_FAILED_NOT_READY && result != SPELL_CAST_OK) // { @@ -3244,7 +3260,7 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell, case SPELL_FAILED_OUT_OF_RANGE: return true; default: - if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) + if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) { LOG_DEBUG("playerbots", "CanCastSpell Check Failed. - target name: {}, spellid: {}, bot name: {}, result: {}", @@ -3280,7 +3296,7 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, GameObject* goTarget, bool checkH if (CastingTime > 0 && bot->isMoving()) return false; - if (sServerFacade->GetDistance2d(bot, goTarget) > sPlayerbotAIConfig->sightDistance) + if (ServerFacade::instance().GetDistance2d(bot, goTarget) > sPlayerbotAIConfig.sightDistance) return false; // ObjectGuid oldSel = bot->GetTarget(); @@ -3333,7 +3349,7 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, float x, float y, float z, bool c if (!itemTarget) { - if (bot->GetDistance(x, y, z) > sPlayerbotAIConfig->sightDistance) + if (bot->GetDistance(x, y, z) > sPlayerbotAIConfig.sightDistance) return false; } @@ -3435,7 +3451,7 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget) if (bot->IsFlying() || bot->HasUnitState(UNIT_STATE_IN_FLIGHT)) { - // if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) + // if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) // { // LOG_DEBUG("playerbots", "Spell cast is flying - target name: {}, spellid: {}, bot name: {}}", // target->GetName(), spellId, bot->GetName()); @@ -3458,13 +3474,13 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget) WorldObject* faceTo = target; if (!bot->HasInArc(CAST_ANGLE_IN_FRONT, faceTo) && (spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT)) { - sServerFacade->SetFacingTo(bot, faceTo); + ServerFacade::instance().SetFacingTo(bot, faceTo); // failWithDelay = true; } if (failWithDelay) { - SetNextCheckDelay(sPlayerbotAIConfig->reactDelay); + SetNextCheckDelay(sPlayerbotAIConfig.reactDelay); return false; } @@ -3481,7 +3497,7 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget) { bot->GetTradeData()->SetSpell(spellId); delete spell; - // if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) + // if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) // { // LOG_DEBUG("playerbots", "Spell cast no item - target name: {}, spellid: {}, bot name: {}", // target->GetName(), spellId, bot->GetName()); @@ -3543,7 +3559,7 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget) if (bot->isMoving() && spell->GetCastTime()) { // bot->StopMoving(); - SetNextCheckDelay(sPlayerbotAIConfig->reactDelay); + SetNextCheckDelay(sPlayerbotAIConfig.reactDelay); spell->cancel(); delete spell; return false; @@ -3551,7 +3567,7 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget) // spell->m_targets.SetUnitTarget(target); // SpellCastResult spellSuccess = spell->CheckCast(true); - // if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) + // if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) // { // LOG_DEBUG("playerbots", "Spell cast result - target name: {}, spellid: {}, bot name: {}, result: {}", // target->GetName(), spellId, bot->GetName(), spellSuccess); @@ -3563,7 +3579,7 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget) if (result != SPELL_CAST_OK) { - // if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) + // if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) // { // LOG_DEBUG("playerbots", "Spell cast failed. - target name: {}, spellid: {}, bot name: {}, result: {}", // target->GetName(), spellId, bot->GetName(), result); @@ -3631,7 +3647,7 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget) // { // spell->cancel(); // delete spell; - // if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) + // if (!sPlayerbotAIConfig.logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster())) // { // LOG_DEBUG("playerbots", "Spell cast loot - target name: {}, spellid: {}, bot name: {}", // target->GetName(), spellId, bot->GetName()); @@ -3711,7 +3727,7 @@ bool PlayerbotAI::CastSpell(uint32 spellId, float x, float y, float z, Item* ite if (failWithDelay) { - SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown); + SetNextCheckDelay(sPlayerbotAIConfig.globalCoolDown); return false; } @@ -3754,7 +3770,7 @@ bool PlayerbotAI::CastSpell(uint32 spellId, float x, float y, float z, Item* ite if (bot->isMoving() && spell->GetCastTime()) { // bot->StopMoving(); - SetNextCheckDelay(sPlayerbotAIConfig->reactDelay); + SetNextCheckDelay(sPlayerbotAIConfig.reactDelay); spell->cancel(); delete spell; return false; @@ -3832,12 +3848,12 @@ bool PlayerbotAI::CanCastVehicleSpell(uint32 spellId, Unit* target) if (CastingTime && vehicleBase->isMoving()) return false; - if (vehicleBase != spellTarget && sServerFacade->GetDistance2d(vehicleBase, spellTarget) > 120.0f) + if (vehicleBase != spellTarget && ServerFacade::instance().GetDistance2d(vehicleBase, spellTarget) > 120.0f) return false; if (!target && siegePos.isSet()) { - if (sServerFacade->GetDistance2d(vehicleBase, siegePos.x, siegePos.y) > 120.0f) + if (ServerFacade::instance().GetDistance2d(vehicleBase, siegePos.x, siegePos.y) > 120.0f) return false; } @@ -3907,7 +3923,7 @@ bool PlayerbotAI::CastVehicleSpell(uint32 spellId, Unit* target) PositionInfo siegePos = GetAiObjectContext()->GetValue("position")->Get()["bg siege"]; if (!target && siegePos.isSet()) { - if (sServerFacade->GetDistance2d(vehicleBase, siegePos.x, siegePos.y) > 120.0f) + if (ServerFacade::instance().GetDistance2d(vehicleBase, siegePos.x, siegePos.y) > 120.0f) return false; } @@ -3945,7 +3961,7 @@ bool PlayerbotAI::CastVehicleSpell(uint32 spellId, Unit* target) if (failWithDelay) { - SetNextCheckDelay(sPlayerbotAIConfig->reactDelay); + SetNextCheckDelay(sPlayerbotAIConfig.reactDelay); return false; } @@ -3986,7 +4002,7 @@ bool PlayerbotAI::CastVehicleSpell(uint32 spellId, Unit* target) if (seat->CanControl() && vehicleBase->isMoving() && spell->GetCastTime()) { vehicleBase->StopMoving(); - SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown); + SetNextCheckDelay(sPlayerbotAIConfig.globalCoolDown); spell->cancel(); // delete spell; return false; @@ -4063,7 +4079,7 @@ void PlayerbotAI::WaitForSpellCast(Spell* spell) castTime += duration; } - SetNextCheckDelay(castTime + sPlayerbotAIConfig->reactDelay); + SetNextCheckDelay(castTime + sPlayerbotAIConfig.reactDelay); } void PlayerbotAI::InterruptSpell() @@ -4155,8 +4171,8 @@ bool PlayerbotAI::HasAuraToDispel(Unit* target, uint32 dispelType) if (!aura || aura->IsPassive() || aura->IsRemoved()) continue; - if (sPlayerbotAIConfig->dispelAuraDuration && aura->GetDuration() && - aura->GetDuration() < (int32)sPlayerbotAIConfig->dispelAuraDuration) + if (sPlayerbotAIConfig.dispelAuraDuration && aura->GetDuration() && + aura->GetDuration() < (int32)sPlayerbotAIConfig.dispelAuraDuration) continue; SpellInfo const* spellInfo = aura->GetSpellInfo(); @@ -4276,7 +4292,7 @@ bool PlayerbotAI::HasRealPlayerMaster() bool PlayerbotAI::HasActivePlayerMaster() { return master && !GET_PLAYERBOT_AI(master); } -bool PlayerbotAI::IsAlt() { return HasRealPlayerMaster() && !sRandomPlayerbotMgr->IsRandomBot(bot); } +bool PlayerbotAI::IsAlt() { return HasRealPlayerMaster() && !sRandomPlayerbotMgr.IsRandomBot(bot); } Player* PlayerbotAI::GetGroupLeader() { @@ -4365,7 +4381,7 @@ bool PlayerbotAI::HasPlayerNearby(WorldPosition* pos, float range) { float sqRange = range * range; bool nearPlayer = false; - for (auto& player : sRandomPlayerbotMgr->GetPlayers()) + for (auto& player : sRandomPlayerbotMgr.GetPlayers()) { if (!player->IsGameMaster() || player->isGMVisible()) { @@ -4399,9 +4415,9 @@ bool PlayerbotAI::HasManyPlayersNearby(uint32 trigerrValue, float range) float sqRange = range * range; uint32 found = 0; - for (auto& player : sRandomPlayerbotMgr->GetPlayers()) + for (auto& player : sRandomPlayerbotMgr.GetPlayers()) { - if ((!player->IsGameMaster() || player->isGMVisible()) && sServerFacade->GetDistance2d(player, bot) < sqRange) + if ((!player->IsGameMaster() || player->isGMVisible()) && ServerFacade::instance().GetDistance2d(player, bot) < sqRange) { found++; @@ -4447,7 +4463,7 @@ inline bool ZoneHasRealPlayers(Player* bot) return false; } - for (Player* player : sRandomPlayerbotMgr->GetPlayers()) + for (Player* player : sRandomPlayerbotMgr.GetPlayers()) { if (player->GetMapId() != bot->GetMapId()) continue; @@ -4478,7 +4494,7 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) return false; // when botActiveAlone is 100% and smartScale disabled - if (sPlayerbotAIConfig->botActiveAlone >= 100 && !sPlayerbotAIConfig->botActiveAloneSmartScale) + if (sPlayerbotAIConfig.botActiveAlone >= 100 && !sPlayerbotAIConfig.botActiveAloneSmartScale) { return true; } @@ -4496,7 +4512,7 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) // which prevents unneeded expensive GameTime calls. if (_isBotInitializing) { - _isBotInitializing = GameTime::GetUptime().count() < sPlayerbotAIConfig->maxRandomBots * 0.11; + _isBotInitializing = GameTime::GetUptime().count() < sPlayerbotAIConfig.maxRandomBots * 0.11; // no activity allowed during bot initialization if (_isBotInitializing) @@ -4518,7 +4534,7 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) } // bot map has active players. - if (sPlayerbotAIConfig->BotActiveAloneForceWhenInMap) + if (sPlayerbotAIConfig.BotActiveAloneForceWhenInMap) { if (HasRealPlayers(bot->GetMap())) { @@ -4527,7 +4543,7 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) } // bot zone has active players. - if (sPlayerbotAIConfig->BotActiveAloneForceWhenInZone) + if (sPlayerbotAIConfig.BotActiveAloneForceWhenInZone) { if (ZoneHasRealPlayers(bot)) { @@ -4536,7 +4552,7 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) } // when in real guild - if (sPlayerbotAIConfig->BotActiveAloneForceWhenInGuild) + if (sPlayerbotAIConfig.BotActiveAloneForceWhenInGuild) { if (IsInRealGuild()) { @@ -4545,7 +4561,7 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) } // Player is near. Always active. - if (HasPlayerNearby(sPlayerbotAIConfig->BotActiveAloneForceWhenInRadius)) + if (HasPlayerNearby(sPlayerbotAIConfig.BotActiveAloneForceWhenInRadius)) { return true; } @@ -4617,13 +4633,13 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) } // HasFriend - if (sPlayerbotAIConfig->BotActiveAloneForceWhenIsFriend) + if (sPlayerbotAIConfig.BotActiveAloneForceWhenIsFriend) { // shouldnt be needed analyse in future if (!bot->GetGUID()) return false; - for (auto& player : sRandomPlayerbotMgr->GetPlayers()) + for (auto& player : sRandomPlayerbotMgr.GetPlayers()) { if (!player || !player->GetSession() || !player->IsInWorld() || player->IsDuringRemoveFromWorld() || player->GetSession()->isLogingOut()) @@ -4655,7 +4671,7 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) return false; } - if (sPlayerbotAIConfig->botActiveAlone <= 0) + if (sPlayerbotAIConfig.botActiveAlone <= 0) { return false; } @@ -4667,19 +4683,19 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) // Below is code to have a specified % of bots active at all times. // The default is 100%. With 1% of all bots going active or inactive each minute. - uint32 mod = sPlayerbotAIConfig->botActiveAlone > 100 ? 100 : sPlayerbotAIConfig->botActiveAlone; - if (sPlayerbotAIConfig->botActiveAloneSmartScale && - bot->GetLevel() >= sPlayerbotAIConfig->botActiveAloneSmartScaleWhenMinLevel && - bot->GetLevel() <= sPlayerbotAIConfig->botActiveAloneSmartScaleWhenMaxLevel) + uint32 mod = sPlayerbotAIConfig.botActiveAlone > 100 ? 100 : sPlayerbotAIConfig.botActiveAlone; + if (sPlayerbotAIConfig.botActiveAloneSmartScale && + bot->GetLevel() >= sPlayerbotAIConfig.botActiveAloneSmartScaleWhenMinLevel && + bot->GetLevel() <= sPlayerbotAIConfig.botActiveAloneSmartScaleWhenMaxLevel) { mod = AutoScaleActivity(mod); } uint32 ActivityNumber = - GetFixedBotNumer(100, sPlayerbotAIConfig->botActiveAlone * static_cast(mod) / 100 * 0.01f); + GetFixedBotNumer(100, sPlayerbotAIConfig.botActiveAlone * static_cast(mod) / 100 * 0.01f); return ActivityNumber <= - (sPlayerbotAIConfig->botActiveAlone * mod) / + (sPlayerbotAIConfig.botActiveAlone * mod) / 100; // The given percentage of bots should be active and rotate 1% of those active bots each minute. } @@ -4711,8 +4727,8 @@ uint32 PlayerbotAI::AutoScaleActivity(uint32 mod) { // Current max server update time (ms), and the configured floor/ceiling values for bot scaling uint32 maxDiff = sWorldUpdateTime.GetMaxUpdateTimeOfCurrentTable(); - uint32 diffLimitFloor = sPlayerbotAIConfig->botActiveAloneSmartScaleDiffLimitfloor; - uint32 diffLimitCeiling = sPlayerbotAIConfig->botActiveAloneSmartScaleDiffLimitCeiling; + uint32 diffLimitFloor = sPlayerbotAIConfig.botActiveAloneSmartScaleDiffLimitfloor; + uint32 diffLimitCeiling = sPlayerbotAIConfig.botActiveAloneSmartScaleDiffLimitCeiling; if (diffLimitCeiling <= diffLimitFloor) { @@ -5304,19 +5320,19 @@ float PlayerbotAI::GetRange(std::string const type) return val; if (type == "spell") - return sPlayerbotAIConfig->spellDistance; + return sPlayerbotAIConfig.spellDistance; if (type == "shoot") - return sPlayerbotAIConfig->shootDistance; + return sPlayerbotAIConfig.shootDistance; if (type == "flee") - return sPlayerbotAIConfig->fleeDistance; + return sPlayerbotAIConfig.fleeDistance; if (type == "heal") - return sPlayerbotAIConfig->healDistance; + return sPlayerbotAIConfig.healDistance; if (type == "melee") - return sPlayerbotAIConfig->meleeDistance; + return sPlayerbotAIConfig.meleeDistance; return 0; } @@ -5985,7 +6001,7 @@ bool PlayerbotAI::IsInRealGuild() if (!bot->GetGuildId()) return false; - return sPlayerbotGuildMgr->IsRealGuild(bot->GetGuildId()); + return PlayerbotGuildMgr::instance().IsRealGuild(bot->GetGuildId()); } void PlayerbotAI::QueueChatResponse(const ChatQueuedReply chatReply) { chatReplies.push_back(std::move(chatReply)); } @@ -6539,17 +6555,17 @@ std::set PlayerbotAI::GetCurrentIncompleteQuestIds() uint32 PlayerbotAI::GetReactDelay() { - uint32 base = sPlayerbotAIConfig->reactDelay; // Default 100(ms) + uint32 base = sPlayerbotAIConfig.reactDelay; // Default 100(ms) // If dynamic react delay is disabled, use a static calculation - if (!sPlayerbotAIConfig->dynamicReactDelay) + if (!sPlayerbotAIConfig.dynamicReactDelay) { if (HasRealPlayerMaster()) return base; bool inBG = bot->InBattleground() || bot->InArena(); - if (sPlayerbotAIConfig->fastReactInBG && inBG) + if (sPlayerbotAIConfig.fastReactInBG && inBG) return base; bool inCombat = bot->IsInCombat(); @@ -6574,11 +6590,11 @@ uint32 PlayerbotAI::GetReactDelay() { if (bot->IsInCombat() || currentState == BOT_STATE_COMBAT) { - return static_cast(base * (sPlayerbotAIConfig->fastReactInBG ? 2.5f : 5.0f)); + return static_cast(base * (sPlayerbotAIConfig.fastReactInBG ? 2.5f : 5.0f)); } else { - return static_cast(base * (sPlayerbotAIConfig->fastReactInBG ? 1.0f : 10.0f)); + return static_cast(base * (sPlayerbotAIConfig.fastReactInBG ? 1.0f : 10.0f)); } } @@ -6751,7 +6767,7 @@ void PlayerbotAI::EvaluateHealerDpsStrategy() if (!IsHeal(bot, true)) return; - if (sPlayerbotAIConfig->IsRestrictedHealerDPSMap(bot->GetMapId())) + if (sPlayerbotAIConfig.IsRestrictedHealerDPSMap(bot->GetMapId())) ChangeStrategy("-healer dps", BOT_STATE_COMBAT); else ChangeStrategy("+healer dps", BOT_STATE_COMBAT); diff --git a/src/Bot/PlayerbotAI.h b/src/Bot/PlayerbotAI.h index 4de4bf4a1f..c2d4aeb75b 100644 --- a/src/Bot/PlayerbotAI.h +++ b/src/Bot/PlayerbotAI.h @@ -429,8 +429,8 @@ class PlayerbotAI : public PlayerbotAIBase static uint32 GetGroupTankNum(Player* player); static bool IsAssistTank(Player* player); static bool IsAssistTankOfIndex(Player* player, int index, bool ignoreDeadPlayers = false); - static bool IsHealAssistantOfIndex(Player* player, int index); - static bool IsRangedDpsAssistantOfIndex(Player* player, int index); + static bool IsAssistHealOfIndex(Player* player, int index, bool ignoreDeadPlayers = false); + static bool IsAssistRangedDpsOfIndex(Player* player, int index, bool ignoreDeadPlayers = false); bool HasAggro(Unit* unit); static int32 GetAssistTankIndex(Player* player); int32 GetGroupSlotIndex(Player* player); @@ -491,7 +491,7 @@ class PlayerbotAI : public PlayerbotAIBase void ImbueItem(Item* item); void EnchantItemT(uint32 spellid, uint8 slot); uint32 GetBuffedCount(Player* player, std::string const spellname); - int32 GetNearGroupMemberCount(float dis = sPlayerbotAIConfig->sightDistance); + int32 GetNearGroupMemberCount(float dis = sPlayerbotAIConfig.sightDistance); virtual bool CanCastSpell(std::string const name, Unit* target, Item* itemTarget = nullptr); virtual bool CastSpell(std::string const name, Unit* target, Item* itemTarget = nullptr); @@ -545,9 +545,9 @@ class PlayerbotAI : public PlayerbotAIBase uint32 GetFixedBotNumer(uint32 maxNum = 100, float cyclePerMin = 1); GrouperType GetGrouperType(); GuilderType GetGuilderType(); - bool HasPlayerNearby(WorldPosition* pos, float range = sPlayerbotAIConfig->reactDistance); - bool HasPlayerNearby(float range = sPlayerbotAIConfig->reactDistance); - bool HasManyPlayersNearby(uint32 trigerrValue = 20, float range = sPlayerbotAIConfig->sightDistance); + bool HasPlayerNearby(WorldPosition* pos, float range = sPlayerbotAIConfig.reactDistance); + bool HasPlayerNearby(float range = sPlayerbotAIConfig.reactDistance); + bool HasManyPlayersNearby(uint32 trigerrValue = 20, float range = sPlayerbotAIConfig.sightDistance); bool AllowActive(ActivityType activityType); bool AllowActivity(ActivityType activityType = ALL_ACTIVITY, bool checkNow = false); uint32 AutoScaleActivity(uint32 mod); @@ -562,7 +562,7 @@ class PlayerbotAI : public PlayerbotAIBase bool HasCheat(BotCheatMask mask) { return ((uint32)mask & (uint32)cheatMask) != 0 || - ((uint32)mask & (uint32)sPlayerbotAIConfig->botCheatMask) != 0; + ((uint32)mask & (uint32)sPlayerbotAIConfig.botCheatMask) != 0; } BotCheatMask GetCheat() { return cheatMask; } void SetCheat(BotCheatMask mask) { cheatMask = mask; } diff --git a/src/Bot/PlayerbotMgr.cpp b/src/Bot/PlayerbotMgr.cpp index e01afb0f7c..79850ab24e 100644 --- a/src/Bot/PlayerbotMgr.cpp +++ b/src/Bot/PlayerbotMgr.cpp @@ -102,11 +102,11 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId Player* masterPlayer = masterSession ? masterSession->GetPlayer() : nullptr; bool isRndbot = !masterAccountId; - bool sameAccount = sPlayerbotAIConfig->allowAccountBots && accountId == masterAccountId; + bool sameAccount = sPlayerbotAIConfig.allowAccountBots && accountId == masterAccountId; Guild* guild = masterPlayer ? sGuildMgr->GetGuildById(masterPlayer->GetGuildId()) : nullptr; - bool sameGuild = sPlayerbotAIConfig->allowGuildBots && guild && guild->GetMember(playerGuid); - bool addClassBot = sRandomPlayerbotMgr->IsAddclassBot(playerGuid.GetCounter()); - bool linkedAccount = sPlayerbotAIConfig->allowTrustedAccountBots && IsAccountLinked(accountId, masterAccountId); + bool sameGuild = sPlayerbotAIConfig.allowGuildBots && guild && guild->GetMember(playerGuid); + bool addClassBot = sRandomPlayerbotMgr.IsAddclassBot(playerGuid.GetCounter()); + bool linkedAccount = sPlayerbotAIConfig.allowTrustedAccountBots && IsAccountLinked(accountId, masterAccountId); bool allowed = true; std::ostringstream out; @@ -126,10 +126,10 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId return; } uint32 count = mgr->GetPlayerbotsCount() + botLoading.size(); - if (count >= sPlayerbotAIConfig->maxAddedBots) + if (count >= sPlayerbotAIConfig.maxAddedBots) { allowed = false; - out << "Failure: You have added too many bots (more than " << sPlayerbotAIConfig->maxAddedBots << ")"; + out << "Failure: You have added too many bots (more than " << sPlayerbotAIConfig.maxAddedBots << ")"; } } if (!allowed) @@ -156,7 +156,6 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId [](SQLQueryHolderBase const& queryHolder) { PlayerbotLoginQueryHolder const& holder = static_cast(queryHolder); - PlayerbotHolder* mgr = sRandomPlayerbotMgr; // could be null uint32 masterAccountId = holder.GetMasterAccountId(); if (masterAccountId) @@ -164,14 +163,25 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId // verify and find current world session of master WorldSession* masterSession = sWorldSessionMgr->FindSession(masterAccountId); Player* masterPlayer = masterSession ? masterSession->GetPlayer() : nullptr; + if (masterPlayer) - mgr = GET_PLAYERBOT_MGR(masterPlayer); + { + PlayerbotHolder* mgr = PlayerbotsMgr::instance().GetPlayerbotMgr(masterPlayer); + + if (mgr != nullptr) + { + mgr->HandlePlayerBotLoginCallback(holder); + + return; + } + + PlayerbotHolder::botLoading.erase(holder.GetGuid()); + + return; + } } - if (mgr) - mgr->HandlePlayerBotLoginCallback(holder); - else - PlayerbotHolder::botLoading.erase(holder.GetGuid()); + RandomPlayerbotMgr ::instance().HandlePlayerBotLoginCallback(holder); }); } @@ -216,9 +226,9 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con masterAccountId); } - sRandomPlayerbotMgr->OnPlayerLogin(bot); + sRandomPlayerbotMgr.OnPlayerLogin(bot); auto op = std::make_unique(bot->GetGUID(), masterAccountId); - sPlayerbotWorldProcessor->QueueOperation(std::move(op)); + PlayerbotWorldThreadProcessor::instance().QueueOperation(std::move(op)); PlayerbotHolder::botLoading.erase(holder.GetGuid()); } @@ -312,8 +322,8 @@ void PlayerbotMgr::CancelLogout() } } - for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr->GetPlayerBotsBegin(); - it != sRandomPlayerbotMgr->GetPlayerBotsEnd(); ++it) + for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr.GetPlayerBotsBegin(); + it != sRandomPlayerbotMgr.GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot); @@ -341,7 +351,7 @@ void PlayerbotHolder::LogoutPlayerBot(ObjectGuid guid) // Queue group cleanup operation for world thread auto cleanupOp = std::make_unique(guid); - sPlayerbotWorldProcessor->QueueOperation(std::move(cleanupOp)); + PlayerbotWorldThreadProcessor::instance().QueueOperation(std::move(cleanupOp)); LOG_DEBUG("playerbots", "Bot {} logging out", bot->GetName().c_str()); bot->SaveToDB(false, false); @@ -442,7 +452,7 @@ void PlayerbotHolder::DisablePlayerBot(ObjectGuid guid) Group* group = bot->GetGroup(); if (group && !bot->InBattleground() && !bot->InBattlegroundQueue() && botAI->HasActivePlayerMaster()) { - sPlayerbotRepository->Save(botAI); + PlayerbotRepository::instance().Save(botAI); } LOG_DEBUG("playerbots", "Bot {} logged out", bot->GetName().c_str()); @@ -488,7 +498,7 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) return; } - sPlayerbotsMgr->AddPlayerbotData(bot, true); + PlayerbotsMgr::instance().AddPlayerbotData(bot, true); playerBots[bot->GetGUID()] = bot; OnBotLoginInternal(bot); @@ -528,10 +538,10 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) // Don't disband alt groups when master goes away // Controlled by config - if (sPlayerbotAIConfig->KeepAltsInGroup()) + if (sPlayerbotAIConfig.KeepAltsInGroup()) { uint32 account = sCharacterCache->GetCharacterAccountIdByGuid(member); - if (!sPlayerbotAIConfig->IsInRandomAccountList(account)) + if (!sPlayerbotAIConfig.IsInRandomAccountList(account)) { groupValid = true; break; @@ -552,9 +562,9 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) } else { - botAI->ResetStrategies(!sRandomPlayerbotMgr->IsRandomBot(bot)); + botAI->ResetStrategies(!sRandomPlayerbotMgr.IsRandomBot(bot)); } - sPlayerbotRepository->Load(botAI); + PlayerbotRepository::instance().Load(botAI); if (master && !master->HasUnitState(UNIT_STATE_IN_FLIGHT)) { @@ -580,52 +590,52 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) { // Queue ConvertToRaid operation auto convertOp = std::make_unique(master->GetGUID()); - sPlayerbotWorldProcessor->QueueOperation(std::move(convertOp)); + PlayerbotWorldThreadProcessor::instance().QueueOperation(std::move(convertOp)); } if (mgroup->isRaidGroup()) { // Queue AddMember operation auto addOp = std::make_unique(master->GetGUID(), bot->GetGUID()); - sPlayerbotWorldProcessor->QueueOperation(std::move(addOp)); + PlayerbotWorldThreadProcessor::instance().QueueOperation(std::move(addOp)); } } else { // Queue AddMember operation auto addOp = std::make_unique(master->GetGUID(), bot->GetGUID()); - sPlayerbotWorldProcessor->QueueOperation(std::move(addOp)); + PlayerbotWorldThreadProcessor::instance().QueueOperation(std::move(addOp)); } } else if (master && !group) { // Queue group creation and AddMember operation auto inviteOp = std::make_unique(master->GetGUID(), bot->GetGUID()); - sPlayerbotWorldProcessor->QueueOperation(std::move(inviteOp)); + PlayerbotWorldThreadProcessor::instance().QueueOperation(std::move(inviteOp)); } // if (master) // { // // bot->TeleportTo(master); // } uint32 accountId = bot->GetSession()->GetAccountId(); - bool isRandomAccount = sPlayerbotAIConfig->IsInRandomAccountList(accountId); + bool isRandomAccount = sPlayerbotAIConfig.IsInRandomAccountList(accountId); - if (isRandomAccount && sPlayerbotAIConfig->randomBotFixedLevel) + if (isRandomAccount && sPlayerbotAIConfig.randomBotFixedLevel) { bot->SetPlayerFlag(PLAYER_FLAGS_NO_XP_GAIN); } - else if (isRandomAccount && !sPlayerbotAIConfig->randomBotFixedLevel) + else if (isRandomAccount && !sPlayerbotAIConfig.randomBotFixedLevel) { bot->RemovePlayerFlag(PLAYER_FLAGS_NO_XP_GAIN); } bot->SaveToDB(false, false); - bool addClassBot = sRandomPlayerbotMgr->IsAccountType(accountId, 2); + bool addClassBot = sRandomPlayerbotMgr.IsAccountType(accountId, 2); if (addClassBot && master && abs((int)master->GetLevel() - (int)bot->GetLevel()) > 3) { // PlayerbotFactory factory(bot, master->GetLevel()); // factory.Randomize(false); uint32 mixedGearScore = - PlayerbotAI::GetMixedGearScore(master, true, false, 12) * sPlayerbotAIConfig->autoInitEquipLevelLimitRatio; + PlayerbotAI::GetMixedGearScore(master, true, false, 12) * sPlayerbotAIConfig.autoInitEquipLevelLimitRatio; // work around: distinguish from 0 if no gear if (mixedGearScore == 0) mixedGearScore = 1; @@ -634,7 +644,7 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) } // bots join World chat if not solo oriented - if (bot->GetLevel() >= 10 && sRandomPlayerbotMgr->IsRandomBot(bot) && GET_PLAYERBOT_AI(bot) && + if (bot->GetLevel() >= 10 && sRandomPlayerbotMgr.IsRandomBot(bot) && GET_PLAYERBOT_AI(bot) && GET_PLAYERBOT_AI(bot)->GetGrouperType() != GrouperType::SOLO) { // TODO make action/config @@ -702,12 +712,12 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, ObjectGuid guid, ObjectGuid masterguid, bool admin, uint32 masterAccountId, uint32 masterGuildId) { - if (!sPlayerbotAIConfig->enabled || guid.IsEmpty()) + if (!sPlayerbotAIConfig.enabled || guid.IsEmpty()) return "bot system is disabled"; uint32 botAccount = sCharacterCache->GetCharacterAccountIdByGuid(guid); - //bool isRandomBot = sRandomPlayerbotMgr->IsRandomBot(guid.GetCounter()); //not used, line marked for removal. - //bool isRandomAccount = sPlayerbotAIConfig->IsInRandomAccountList(botAccount); //not used, shadowed, line marked for removal. + //bool isRandomBot = sRandomPlayerbotMgr.IsRandomBot(guid.GetCounter()); //not used, line marked for removal. + //bool isRandomAccount = sPlayerbotAIConfig.IsInRandomAccountList(botAccount); //not used, shadowed, line marked for removal. //bool isMasterAccount = (masterAccountId == botAccount); //not used, line marked for removal. if (cmd == "add" || cmd == "addaccount" || cmd == "login") @@ -722,8 +732,8 @@ std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, Obje if (!accountId) return "character not found"; - if (!sPlayerbotAIConfig->allowAccountBots && accountId != masterAccountId && - !(sPlayerbotAIConfig->allowTrustedAccountBots && IsAccountLinked(accountId, masterAccountId))) + if (!sPlayerbotAIConfig.allowAccountBots && accountId != masterAccountId && + !(sPlayerbotAIConfig.allowTrustedAccountBots && IsAccountLinked(accountId, masterAccountId))) { return "you can only add bots from your own account or linked accounts"; } @@ -748,12 +758,12 @@ std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, Obje // { Player* bot = GetPlayerBot(guid); if (!bot) - bot = sRandomPlayerbotMgr->GetPlayerBot(guid); + bot = sRandomPlayerbotMgr.GetPlayerBot(guid); if (!bot) return "bot not found"; - bool addClassBot = sRandomPlayerbotMgr->IsAddclassBot(guid.GetCounter()); + bool addClassBot = sRandomPlayerbotMgr.IsAddclassBot(guid.GetCounter()); if (!addClassBot) return "ERROR: You can not use this command on non-addclass bot."; @@ -771,7 +781,7 @@ std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, Obje { if (Player* master = GET_PLAYERBOT_AI(bot)->GetMaster()) { - if (master->GetSession()->GetSecurity() <= SEC_PLAYER && sPlayerbotAIConfig->autoInitOnly && + if (master->GetSession()->GetSecurity() <= SEC_PLAYER && sPlayerbotAIConfig.autoInitOnly && cmd != "init=auto") { return "The command is not allowed, use init=auto instead."; @@ -818,7 +828,7 @@ std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, Obje else if (cmd == "init=auto") { uint32 mixedGearScore = PlayerbotAI::GetMixedGearScore(master, true, false, 12) * - sPlayerbotAIConfig->autoInitEquipLevelLimitRatio; + sPlayerbotAIConfig.autoInitEquipLevelLimitRatio; // work around: distinguish from 0 if no gear if (mixedGearScore == 0) mixedGearScore = 1; @@ -858,7 +868,7 @@ std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, Obje } else if (cmd == "random") { - sRandomPlayerbotMgr->Randomize(bot); + sRandomPlayerbotMgr.Randomize(bot); return "ok"; } else if (cmd == "quests") @@ -886,7 +896,7 @@ static uint8 GetOfflinePlayerGender(ObjectGuid guid) bool PlayerbotMgr::HandlePlayerbotMgrCommand(ChatHandler* handler, char const* args) { - if (!sPlayerbotAIConfig->enabled) + if (!sPlayerbotAIConfig.enabled) { handler->PSendSysMessage("|cffff0000Playerbot system is currently disabled!"); return false; @@ -1052,7 +1062,7 @@ std::vector PlayerbotHolder::HandlePlayerbotCommand(char const* arg { if (master->GetSession()->GetSecurity() >= SEC_GAMEMASTER) { - sPlayerbotAIConfig->Initialize(); + sPlayerbotAIConfig.Initialize(); messages.push_back("Config reloaded."); return messages; } @@ -1065,11 +1075,11 @@ std::vector PlayerbotHolder::HandlePlayerbotCommand(char const* arg if (!strcmp(cmd, "tweak")) { - sPlayerbotAIConfig->tweakValue = sPlayerbotAIConfig->tweakValue++; - if (sPlayerbotAIConfig->tweakValue > 2) - sPlayerbotAIConfig->tweakValue = 0; + sPlayerbotAIConfig.tweakValue = sPlayerbotAIConfig.tweakValue++; + if (sPlayerbotAIConfig.tweakValue > 2) + sPlayerbotAIConfig.tweakValue = 0; - messages.push_back("Set tweakvalue to " + std::to_string(sPlayerbotAIConfig->tweakValue)); + messages.push_back("Set tweakvalue to " + std::to_string(sPlayerbotAIConfig.tweakValue)); return messages; } @@ -1080,14 +1090,14 @@ std::vector PlayerbotHolder::HandlePlayerbotCommand(char const* arg messages.push_back("Disable player botAI"); delete GET_PLAYERBOT_AI(master); } - else if (sPlayerbotAIConfig->selfBotLevel == 0) + else if (sPlayerbotAIConfig.selfBotLevel == 0) messages.push_back("Self-bot is disabled"); - else if (sPlayerbotAIConfig->selfBotLevel == 1 && master->GetSession()->GetSecurity() < SEC_GAMEMASTER) + else if (sPlayerbotAIConfig.selfBotLevel == 1 && master->GetSession()->GetSecurity() < SEC_GAMEMASTER) messages.push_back("You do not have permission to enable player botAI"); else { messages.push_back("Enable player botAI"); - sPlayerbotsMgr->AddPlayerbotData(master, true); + PlayerbotsMgr::instance().AddPlayerbotData(master, true); GET_PLAYERBOT_AI(master)->SetMaster(master); } @@ -1102,7 +1112,7 @@ std::vector PlayerbotHolder::HandlePlayerbotCommand(char const* arg if (!strcmp(cmd, "addclass")) { - if (sPlayerbotAIConfig->addClassCommand == 0 && master->GetSession()->GetSecurity() < SEC_GAMEMASTER) + if (sPlayerbotAIConfig.addClassCommand == 0 && master->GetSession()->GetSecurity() < SEC_GAMEMASTER) { messages.push_back("You do not have permission to create bot by addclass command"); return messages; @@ -1183,7 +1193,7 @@ std::vector PlayerbotHolder::HandlePlayerbotCommand(char const* arg return messages; } uint8 teamId = master->GetTeamId(true); - const std::unordered_set &guidCache = sRandomPlayerbotMgr->addclassCache[RandomPlayerbotMgr::GetTeamClassIdx(teamId == TEAM_ALLIANCE, claz)]; + const std::unordered_set &guidCache = sRandomPlayerbotMgr.addclassCache[RandomPlayerbotMgr::GetTeamClassIdx(teamId == TEAM_ALLIANCE, claz)]; for (const ObjectGuid &guid: guidCache) { // If the user requested a specific gender, skip any character that doesn't match. @@ -1194,7 +1204,7 @@ std::vector PlayerbotHolder::HandlePlayerbotCommand(char const* arg if (ObjectAccessor::FindConnectedPlayer(guid)) continue; uint32 guildId = sCharacterCache->GetCharacterGuildIdByGuid(guid); - if (guildId && sPlayerbotGuildMgr->IsRealGuild(guildId)) + if (guildId && PlayerbotGuildMgr::instance().IsRealGuild(guildId)) continue; AddPlayerBot(guid, master->GetSession()->GetAccountId()); messages.push_back("Add class " + std::string(charname)); @@ -1424,7 +1434,7 @@ std::string const PlayerbotHolder::ListBots(Player* master) for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) { Player* member = ObjectAccessor::FindPlayer(itr->guid); - if (member && sRandomPlayerbotMgr->IsRandomBot(member)) + if (member && sRandomPlayerbotMgr.IsRandomBot(member)) { std::string const name = member->GetName(); @@ -1494,12 +1504,12 @@ PlayerbotMgr::PlayerbotMgr(Player* const master) : PlayerbotHolder(), master(mas PlayerbotMgr::~PlayerbotMgr() { if (master) - sPlayerbotsMgr->RemovePlayerBotData(master->GetGUID(), false); + PlayerbotsMgr::instance().RemovePlayerBotData(master->GetGUID(), false); } void PlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) { - SetNextCheckDelay(sPlayerbotAIConfig->reactDelay); + SetNextCheckDelay(sPlayerbotAIConfig.reactDelay); CheckTellErrors(elapsed); } @@ -1509,10 +1519,10 @@ void PlayerbotMgr::HandleCommand(uint32 type, std::string const text) if (!master) return; - if (text.find(sPlayerbotAIConfig->commandSeparator) != std::string::npos) + if (text.find(sPlayerbotAIConfig.commandSeparator) != std::string::npos) { std::vector commands; - split(commands, text, sPlayerbotAIConfig->commandSeparator.c_str()); + split(commands, text, sPlayerbotAIConfig.commandSeparator.c_str()); for (std::vector::iterator i = commands.begin(); i != commands.end(); ++i) { HandleCommand(type, *i); @@ -1529,8 +1539,8 @@ void PlayerbotMgr::HandleCommand(uint32 type, std::string const text) botAI->HandleCommand(type, text, master); } - for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr->GetPlayerBotsBegin(); - it != sRandomPlayerbotMgr->GetPlayerBotsEnd(); ++it) + for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr.GetPlayerBotsBegin(); + it != sRandomPlayerbotMgr.GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot); @@ -1551,8 +1561,8 @@ void PlayerbotMgr::HandleMasterIncomingPacket(WorldPacket const& packet) botAI->HandleMasterIncomingPacket(packet); } - for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr->GetPlayerBotsBegin(); - it != sRandomPlayerbotMgr->GetPlayerBotsEnd(); ++it) + for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr.GetPlayerBotsBegin(); + it != sRandomPlayerbotMgr.GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot); @@ -1587,8 +1597,8 @@ void PlayerbotMgr::HandleMasterOutgoingPacket(WorldPacket const& packet) botAI->HandleMasterOutgoingPacket(packet); } - for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr->GetPlayerBotsBegin(); - it != sRandomPlayerbotMgr->GetPlayerBotsEnd(); ++it) + for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr.GetPlayerBotsBegin(); + it != sRandomPlayerbotMgr.GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot); @@ -1605,8 +1615,8 @@ void PlayerbotMgr::SaveToDB() bot->SaveToDB(false, false); } - for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr->GetPlayerBotsBegin(); - it != sRandomPlayerbotMgr->GetPlayerBotsEnd(); ++it) + for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr.GetPlayerBotsBegin(); + it != sRandomPlayerbotMgr.GetPlayerBotsEnd(); ++it) { Player* const bot = it->second; if (GET_PLAYERBOT_AI(bot) && GET_PLAYERBOT_AI(bot)->GetMaster() == GetMaster()) @@ -1648,12 +1658,12 @@ void PlayerbotMgr::OnPlayerLogin(Player* player) usedLocale = LOCALE_enUS; // fallback // set locale priority for bot texts - sPlayerbotTextMgr->AddLocalePriority(usedLocale); + PlayerbotTextMgr::instance().AddLocalePriority(usedLocale); - if (sPlayerbotAIConfig->selfBotLevel > 2) + if (sPlayerbotAIConfig.selfBotLevel > 2) HandlePlayerbotCommand("self", player); - if (!sPlayerbotAIConfig->botAutologin) + if (!sPlayerbotAIConfig.botAutologin) return; uint32 accountId = session->GetAccountId(); @@ -1693,7 +1703,7 @@ void PlayerbotMgr::TellError(std::string const botName, std::string const text) void PlayerbotMgr::CheckTellErrors(uint32 elapsed) { time_t now = time(nullptr); - if ((now - lastErrorTell) < sPlayerbotAIConfig->errorDelay / 1000) + if ((now - lastErrorTell) < sPlayerbotAIConfig.errorDelay / 1000) return; lastErrorTell = now; @@ -1777,7 +1787,7 @@ void PlayerbotsMgr::RemovePlayerBotData(ObjectGuid const& guid, bool is_AI) PlayerbotAI* PlayerbotsMgr::GetPlayerbotAI(Player* player) { - if (!(sPlayerbotAIConfig->enabled) || !player) + if (!(sPlayerbotAIConfig.enabled) || !player) { return nullptr; } @@ -1797,7 +1807,7 @@ PlayerbotAI* PlayerbotsMgr::GetPlayerbotAI(Player* player) PlayerbotMgr* PlayerbotsMgr::GetPlayerbotMgr(Player* player) { - if (!(sPlayerbotAIConfig->enabled) || !player) + if (!(sPlayerbotAIConfig.enabled) || !player) { return nullptr; } diff --git a/src/Bot/PlayerbotMgr.h b/src/Bot/PlayerbotMgr.h index 7ee576006b..b80f6f2363 100644 --- a/src/Bot/PlayerbotMgr.h +++ b/src/Bot/PlayerbotMgr.h @@ -6,12 +6,9 @@ #ifndef _PLAYERBOT_PLAYERBOTMGR_H #define _PLAYERBOT_PLAYERBOTMGR_H -#include "Common.h" #include "ObjectGuid.h" #include "Player.h" #include "PlayerbotAIBase.h" -#include "QueryHolder.h" -#include "QueryResult.h" class ChatHandler; class PlayerbotAI; @@ -101,13 +98,10 @@ class PlayerbotMgr : public PlayerbotHolder class PlayerbotsMgr { public: - PlayerbotsMgr() {} - ~PlayerbotsMgr() {} - - static PlayerbotsMgr* instance() + static PlayerbotsMgr& instance() { static PlayerbotsMgr instance; - return &instance; + return instance; } void AddPlayerbotData(Player* player, bool isBotAI); @@ -117,6 +111,15 @@ class PlayerbotsMgr PlayerbotMgr* GetPlayerbotMgr(Player* player); private: + PlayerbotsMgr() = default; + ~PlayerbotsMgr() = default; + + PlayerbotsMgr(const PlayerbotsMgr&) = delete; + PlayerbotsMgr& operator=(const PlayerbotsMgr&) = delete; + + PlayerbotsMgr(PlayerbotsMgr&&) = delete; + PlayerbotsMgr& operator=(PlayerbotsMgr&&) = delete; + std::unordered_map _playerbotsAIMap; std::unordered_map _playerbotsMgrMap; }; diff --git a/src/Bot/RandomPlayerbotMgr.cpp b/src/Bot/RandomPlayerbotMgr.cpp index 4d589ef1b4..4707d854ff 100644 --- a/src/Bot/RandomPlayerbotMgr.cpp +++ b/src/Bot/RandomPlayerbotMgr.cpp @@ -14,12 +14,9 @@ #include #include -#include "AccountMgr.h" #include "AiFactory.h" -#include "ArenaTeamMgr.h" #include "Battleground.h" #include "BattlegroundMgr.h" -#include "CellImpl.h" #include "ChannelMgr.h" #include "DBCStores.h" #include "DBCStructure.h" @@ -28,8 +25,6 @@ #include "FleeManager.h" #include "FlightMasterCache.h" #include "GridNotifiers.h" -#include "GridNotifiersImpl.h" -#include "GuildMgr.h" #include "GuildTaskMgr.h" #include "LFGMgr.h" #include "MapMgr.h" @@ -40,7 +35,6 @@ #include "Player.h" #include "PlayerbotAI.h" #include "PlayerbotAIConfig.h" -#include "PlayerbotCommandServer.h" #include "PlayerbotFactory.h" #include "Playerbots.h" #include "Position.h" @@ -50,8 +44,13 @@ #include "SharedDefines.h" #include "TravelMgr.h" #include "Unit.h" -#include "UpdateTime.h" #include "World.h" +#include "Cell.h" +#include "GridNotifiers.h" +// Required for Cell because of poor AC implementation +#include "CellImpl.h" +// Required for GridNotifiers because of poor AC implementation +#include "GridNotifiersImpl.h" struct GuidClassRaceInfo { @@ -102,7 +101,7 @@ static const std::unordered_map> cityToBankers = { // Quick lookup map: banker entry → location static std::unordered_map bankerEntryToLocation; -void PrintStatsThread() { sRandomPlayerbotMgr->PrintStats(); } +void PrintStatsThread() { sRandomPlayerbotMgr.PrintStats(); } void activatePrintStatsThread() { @@ -110,7 +109,7 @@ void activatePrintStatsThread() t.detach(); } -void CheckBgQueueThread() { sRandomPlayerbotMgr->CheckBgQueue(); } +void CheckBgQueueThread() { sRandomPlayerbotMgr.CheckBgQueue(); } void activateCheckBgQueueThread() { @@ -118,7 +117,7 @@ void activateCheckBgQueueThread() t.detach(); } -void CheckLfgQueueThread() { sRandomPlayerbotMgr->CheckLfgQueue(); } +void CheckLfgQueueThread() { sRandomPlayerbotMgr.CheckLfgQueue(); } void activateCheckLfgQueueThread() { @@ -126,7 +125,7 @@ void activateCheckLfgQueueThread() t.detach(); } -void CheckPlayersThread() { sRandomPlayerbotMgr->CheckPlayers(); } +void CheckPlayersThread() { sRandomPlayerbotMgr.CheckPlayers(); } void activateCheckPlayersThread() { @@ -215,36 +214,6 @@ double botPIDImpl::calculate(double setpoint, double pv) botPIDImpl::~botPIDImpl() {} -RandomPlayerbotMgr::RandomPlayerbotMgr() : PlayerbotHolder(), processTicks(0) -{ - playersLevel = sPlayerbotAIConfig->randombotStartingLevel; - - if (sPlayerbotAIConfig->enabled || sPlayerbotAIConfig->randomBotAutologin) - { - sPlayerbotCommandServer->Start(); - } - - BattlegroundData.clear(); // Clear here and here only. - - // Cleanup on server start: orphaned pet data that's often left behind by bot pets that no longer exist in the DB - CharacterDatabase.Execute("DELETE FROM pet_aura WHERE guid NOT IN (SELECT id FROM character_pet)"); - CharacterDatabase.Execute("DELETE FROM pet_spell WHERE guid NOT IN (SELECT id FROM character_pet)"); - CharacterDatabase.Execute("DELETE FROM pet_spell_cooldown WHERE guid NOT IN (SELECT id FROM character_pet)"); - - for (int bracket = BG_BRACKET_ID_FIRST; bracket < MAX_BATTLEGROUND_BRACKETS; ++bracket) - { - for (int queueType = BATTLEGROUND_QUEUE_AV; queueType < MAX_BATTLEGROUND_QUEUE_TYPES; ++queueType) - { - BattlegroundData[queueType][bracket] = BattlegroundInfo(); - } - } - BgCheckTimer = 0; - LfgCheckTimer = 0; - PlayersCheckTimer = 0; -} - -RandomPlayerbotMgr::~RandomPlayerbotMgr() {} - uint32 RandomPlayerbotMgr::GetMaxAllowedBotCount() { return GetEventValue(0, "bot_count"); } void RandomPlayerbotMgr::LogPlayerLocation() @@ -253,9 +222,9 @@ void RandomPlayerbotMgr::LogPlayerLocation() try { - sPlayerbotAIConfig->openLog("player_location.csv", "w"); + sPlayerbotAIConfig.openLog("player_location.csv", "w"); - if (sPlayerbotAIConfig->randomBotAutologin) + if (sPlayerbotAIConfig.randomBotAutologin) { for (auto i : GetAllBots()) { @@ -264,7 +233,7 @@ void RandomPlayerbotMgr::LogPlayerLocation() continue; std::ostringstream out; - out << sPlayerbotAIConfig->GetTimestampStr() << "+00,"; + out << sPlayerbotAIConfig.GetTimestampStr() << "+00,"; out << "RND" << ","; out << bot->GetName() << ","; @@ -298,7 +267,7 @@ void RandomPlayerbotMgr::LogPlayerLocation() out << (bot->IsInCombat() ? "combat" : "safe") << ","; out << (bot->isDead() ? (bot->GetCorpse() ? "ghost" : "dead") : "alive"); - sPlayerbotAIConfig->log("player_location.csv", out.str().c_str()); + sPlayerbotAIConfig.log("player_location.csv", out.str().c_str()); } for (auto i : GetPlayers()) @@ -308,7 +277,7 @@ void RandomPlayerbotMgr::LogPlayerLocation() continue; std::ostringstream out; - out << sPlayerbotAIConfig->GetTimestampStr() << "+00,"; + out << sPlayerbotAIConfig.GetTimestampStr() << "+00,"; out << "PLR" << ","; out << bot->GetName() << ","; @@ -342,7 +311,7 @@ void RandomPlayerbotMgr::LogPlayerLocation() out << (bot->IsInCombat() ? "combat" : "safe") << ","; out << (bot->isDead() ? (bot->GetCorpse() ? "ghost" : "dead") : "alive"); - sPlayerbotAIConfig->log("player_location.csv", out.str().c_str()); + sPlayerbotAIConfig.log("player_location.csv", out.str().c_str()); } } } @@ -359,12 +328,12 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) if (totalPmo) totalPmo->finish(); - totalPmo = sPerfMonitor->start(PERF_MON_TOTAL, "RandomPlayerbotMgr::FullTick"); + totalPmo = sPerfMonitor.start(PERF_MON_TOTAL, "RandomPlayerbotMgr::FullTick"); - if (!sPlayerbotAIConfig->randomBotAutologin || !sPlayerbotAIConfig->enabled) + if (!sPlayerbotAIConfig.randomBotAutologin || !sPlayerbotAIConfig.enabled) return; - /*if (sPlayerbotAIConfig->enablePrototypePerformanceDiff) + /*if (sPlayerbotAIConfig.enablePrototypePerformanceDiff) { LOG_INFO("playerbots", "---------------------------------------"); LOG_INFO("playerbots", @@ -374,13 +343,13 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) }*/ uint32 maxAllowedBotCount = GetEventValue(0, "bot_count"); - if (!maxAllowedBotCount || (maxAllowedBotCount < sPlayerbotAIConfig->minRandomBots || - maxAllowedBotCount > sPlayerbotAIConfig->maxRandomBots)) + if (!maxAllowedBotCount || (maxAllowedBotCount < sPlayerbotAIConfig.minRandomBots || + maxAllowedBotCount > sPlayerbotAIConfig.maxRandomBots)) { - maxAllowedBotCount = urand(sPlayerbotAIConfig->minRandomBots, sPlayerbotAIConfig->maxRandomBots); + maxAllowedBotCount = urand(sPlayerbotAIConfig.minRandomBots, sPlayerbotAIConfig.maxRandomBots); SetEventValue(0, "bot_count", maxAllowedBotCount, - urand(sPlayerbotAIConfig->randomBotCountChangeMinInterval, - sPlayerbotAIConfig->randomBotCountChangeMaxInterval)); + urand(sPlayerbotAIConfig.randomBotCountChangeMinInterval, + sPlayerbotAIConfig.randomBotCountChangeMaxInterval)); } GetBots(); @@ -389,25 +358,25 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) uint32 onlineBotCount = playerBots.size(); uint32 onlineBotFocus = 75; - if (onlineBotCount < (uint32)(sPlayerbotAIConfig->minRandomBots * 90 / 100)) + if (onlineBotCount < (uint32)(sPlayerbotAIConfig.minRandomBots * 90 / 100)) onlineBotFocus = 25; // only keep updating till initializing time has completed, // which prevents unneeded expensive GameTime calls. if (_isBotInitializing) { - _isBotInitializing = GameTime::GetUptime().count() < sPlayerbotAIConfig->maxRandomBots * (0.11 + 0.4); + _isBotInitializing = GameTime::GetUptime().count() < sPlayerbotAIConfig.maxRandomBots * (0.11 + 0.4); } - uint32 updateIntervalTurboBoost = _isBotInitializing ? 1 : sPlayerbotAIConfig->randomBotUpdateInterval; + uint32 updateIntervalTurboBoost = _isBotInitializing ? 1 : sPlayerbotAIConfig.randomBotUpdateInterval; SetNextCheckDelay(updateIntervalTurboBoost * (onlineBotFocus + 25) * 10); - PerfMonitorOperation* pmo = sPerfMonitor->start( + PerfMonitorOperation* pmo = sPerfMonitor.start( PERF_MON_TOTAL, onlineBotCount < maxAllowedBotCount ? "RandomPlayerbotMgr::Login" : "RandomPlayerbotMgr::UpdateAIInternal"); bool realPlayerIsLogged = false; - if (sPlayerbotAIConfig->disabledWithoutRealPlayer) + if (sPlayerbotAIConfig.disabledWithoutRealPlayer) { if (sWorldSessionMgr->GetActiveAndQueuedSessionCount() > 0) { @@ -416,7 +385,7 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) if (DelayLoginBotsTimer == 0) { - DelayLoginBotsTimer = time(nullptr) + sPlayerbotAIConfig->disabledWithoutRealPlayerLoginDelay; + DelayLoginBotsTimer = time(nullptr) + sPlayerbotAIConfig.disabledWithoutRealPlayerLoginDelay; } } else @@ -427,7 +396,7 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) } if (RealPlayerLastTimeSeen != 0 && onlineBotCount > 0 && - time(nullptr) > RealPlayerLastTimeSeen + sPlayerbotAIConfig->disabledWithoutRealPlayerLogoutDelay) + time(nullptr) > RealPlayerLastTimeSeen + sPlayerbotAIConfig.disabledWithoutRealPlayerLogoutDelay) { LogoutAllBots(); LOG_INFO("playerbots", "Logout all bots due no real player session."); @@ -435,7 +404,7 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) } if (availableBotCount < maxAllowedBotCount && - (sPlayerbotAIConfig->disabledWithoutRealPlayer == false || + (sPlayerbotAIConfig.disabledWithoutRealPlayer == false || (realPlayerIsLogged && DelayLoginBotsTimer != 0 && time(nullptr) >= DelayLoginBotsTimer))) { AddRandomBots(); @@ -446,25 +415,25 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) AddRandomBots(); } - if (sPlayerbotAIConfig->syncLevelWithPlayers && !players.empty()) + if (sPlayerbotAIConfig.syncLevelWithPlayers && !players.empty()) { if (time(nullptr) > (PlayersCheckTimer + 60)) - sRandomPlayerbotMgr->CheckPlayers(); + sRandomPlayerbotMgr.CheckPlayers(); } - if (sPlayerbotAIConfig->randomBotJoinBG /* && !players.empty()*/) + if (sPlayerbotAIConfig.randomBotJoinBG /* && !players.empty()*/) { if (time(nullptr) > (BgCheckTimer + 35)) - sRandomPlayerbotMgr->CheckBgQueue(); + sRandomPlayerbotMgr.CheckBgQueue(); } - if (sPlayerbotAIConfig->randomBotJoinLfg /* && !players.empty()*/) + if (sPlayerbotAIConfig.randomBotJoinLfg /* && !players.empty()*/) { if (time(nullptr) > (LfgCheckTimer + 30)) - sRandomPlayerbotMgr->CheckLfgQueue(); + sRandomPlayerbotMgr.CheckLfgQueue(); } - if (sPlayerbotAIConfig->randomBotAutologin && time(nullptr) > (printStatsTimer + 300)) + if (sPlayerbotAIConfig.randomBotAutologin && time(nullptr) > (printStatsTimer + 300)) { if (!printStatsTimer) { @@ -472,18 +441,18 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) } else { - sRandomPlayerbotMgr->PrintStats(); + sRandomPlayerbotMgr.PrintStats(); // activatePrintStatsThread(); } } - uint32 updateBots = sPlayerbotAIConfig->randomBotsPerInterval * onlineBotFocus / 100; + uint32 updateBots = sPlayerbotAIConfig.randomBotsPerInterval * onlineBotFocus / 100; uint32 maxNewBots = onlineBotCount < maxAllowedBotCount && - (sPlayerbotAIConfig->disabledWithoutRealPlayer == false || + (sPlayerbotAIConfig.disabledWithoutRealPlayer == false || (realPlayerIsLogged && DelayLoginBotsTimer != 0 && time(nullptr) >= DelayLoginBotsTimer)) ? maxAllowedBotCount - onlineBotCount : 0; - uint32 loginBots = std::min(sPlayerbotAIConfig->randomBotsPerInterval - updateBots, maxNewBots); + uint32 loginBots = std::min(sPlayerbotAIConfig.randomBotsPerInterval - updateBots, maxNewBots); if (!availableBots.empty()) { @@ -531,7 +500,7 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) if (pmo) pmo->finish(); - if (sPlayerbotAIConfig->hasLog("player_location.csv")) + if (sPlayerbotAIConfig.hasLog("player_location.csv")) { LogPlayerLocation(); } @@ -546,8 +515,8 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/) // // // % increase/decrease wanted diff , avg diff // float activityPercentageMod = pid.calculate( -// sRandomPlayerbotMgr->GetPlayers().empty() ? sPlayerbotAIConfig->diffEmpty : -// sPlayerbotAIConfig->diffWithPlayer, sWorldUpdateTime.GetAverageUpdateTime()); +// sRandomPlayerbotMgr.GetPlayers().empty() ? sPlayerbotAIConfig.diffEmpty : +// sPlayerbotAIConfig.diffWithPlayer, sWorldUpdateTime.GetAverageUpdateTime()); // // activityPercentage = activityPercentageMod + 50; // @@ -573,7 +542,7 @@ void RandomPlayerbotMgr::AssignAccountTypes() std::vector allRandomBotAccounts; QueryResult allAccounts = LoginDatabase.Query( "SELECT id FROM account WHERE username LIKE '{}%%' ORDER BY id", - sPlayerbotAIConfig->randomBotAccountPrefix.c_str()); + sPlayerbotAIConfig.randomBotAccountPrefix.c_str()); if (allAccounts) { @@ -614,15 +583,15 @@ void RandomPlayerbotMgr::AssignAccountTypes() // Calculate needed RNDbot accounts uint32 neededRndBotAccounts = 0; - if (sPlayerbotAIConfig->maxRandomBots > 0) + if (sPlayerbotAIConfig.maxRandomBots > 0) { int divisor = RandomPlayerbotFactory::CalculateAvailableCharsPerAccount(); - int maxBots = sPlayerbotAIConfig->maxRandomBots; + int maxBots = sPlayerbotAIConfig.maxRandomBots; // Take periodic online-offline into account - if (sPlayerbotAIConfig->enablePeriodicOnlineOffline) + if (sPlayerbotAIConfig.enablePeriodicOnlineOffline) { - maxBots *= sPlayerbotAIConfig->periodicOnlineOfflineRatio; + maxBots *= sPlayerbotAIConfig.periodicOnlineOfflineRatio; } // Calculate base accounts needed for RNDbots, ensuring round up for maxBots not cleanly divisible by the divisor @@ -663,7 +632,7 @@ void RandomPlayerbotMgr::AssignAccountTypes() } // Assign AddClass accounts from highest position if needed - uint32 neededAddClassAccounts = sPlayerbotAIConfig->addClassAccountPoolSize; + uint32 neededAddClassAccounts = sPlayerbotAIConfig.addClassAccountPoolSize; if (existingAddClassAccounts < neededAddClassAccounts) { @@ -719,16 +688,16 @@ uint32 RandomPlayerbotMgr::AddRandomBots() { // Calculate how many bots to add maxAllowedBotCount -= currentBots.size(); - maxAllowedBotCount = std::min(sPlayerbotAIConfig->randomBotsPerInterval, maxAllowedBotCount); + maxAllowedBotCount = std::min(sPlayerbotAIConfig.randomBotsPerInterval, maxAllowedBotCount); // Single RNG instance for all shuffling std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count()); // Only need to track the Alliance count, as it's in Phase 1 - uint32 totalRatio = sPlayerbotAIConfig->randomBotAllianceRatio + sPlayerbotAIConfig->randomBotHordeRatio; - uint32 allowedAllianceCount = maxAllowedBotCount * (sPlayerbotAIConfig->randomBotAllianceRatio) / totalRatio; + uint32 totalRatio = sPlayerbotAIConfig.randomBotAllianceRatio + sPlayerbotAIConfig.randomBotHordeRatio; + uint32 allowedAllianceCount = maxAllowedBotCount * (sPlayerbotAIConfig.randomBotAllianceRatio) / totalRatio; - uint32 remainder = maxAllowedBotCount * (sPlayerbotAIConfig->randomBotAllianceRatio) % totalRatio; + uint32 remainder = maxAllowedBotCount * (sPlayerbotAIConfig.randomBotAllianceRatio) % totalRatio; // Fix #1082: Randomly add one based on reminder if (remainder && urand(1, totalRatio) <= remainder) @@ -738,13 +707,13 @@ uint32 RandomPlayerbotMgr::AddRandomBots() // Determine which accounts to use based on EnablePeriodicOnlineOffline std::vector accountsToUse; - if (sPlayerbotAIConfig->enablePeriodicOnlineOffline) + if (sPlayerbotAIConfig.enablePeriodicOnlineOffline) { // Calculate how many accounts can be used // With enablePeriodicOnlineOffline, don't use all of rndBotTypeAccounts right away. Fraction results are rounded up - uint32 accountsToUseCount = (rndBotTypeAccounts.size() + sPlayerbotAIConfig->periodicOnlineOfflineRatio - 1) - / sPlayerbotAIConfig->periodicOnlineOfflineRatio; + uint32 accountsToUseCount = (rndBotTypeAccounts.size() + sPlayerbotAIConfig.periodicOnlineOfflineRatio - 1) + / sPlayerbotAIConfig.periodicOnlineOfflineRatio; // Randomly select accounts std::vector shuffledAccounts = rndBotTypeAccounts; @@ -814,15 +783,15 @@ uint32 RandomPlayerbotMgr::AddRandomBots() GetEventValue(charInfo.guid, "logout") || GetPlayerBot(charInfo.guid) || std::find(currentBots.begin(), currentBots.end(), charInfo.guid) != currentBots.end() || - (sPlayerbotAIConfig->disableDeathKnightLogin && charInfo.rClass == CLASS_DEATH_KNIGHT)) + (sPlayerbotAIConfig.disableDeathKnightLogin && charInfo.rClass == CLASS_DEATH_KNIGHT)) { return false; } - uint32 add_time = sPlayerbotAIConfig->enablePeriodicOnlineOffline - ? urand(sPlayerbotAIConfig->minRandomBotInWorldTime, - sPlayerbotAIConfig->maxRandomBotInWorldTime) - : sPlayerbotAIConfig->permanentlyInWorldTime; + uint32 add_time = sPlayerbotAIConfig.enablePeriodicOnlineOffline + ? urand(sPlayerbotAIConfig.minRandomBotInWorldTime, + sPlayerbotAIConfig.maxRandomBotInWorldTime) + : sPlayerbotAIConfig.permanentlyInWorldTime; SetEventValue(charInfo.guid, "add", 1, add_time); SetEventValue(charInfo.guid, "logout", 0, 0); @@ -1187,24 +1156,24 @@ void RandomPlayerbotMgr::CheckBgQueue() } // If enabled, wait for all bots to have logged in before queueing for Arena's / BG's - if (sPlayerbotAIConfig->randomBotAutoJoinBG && playerBots.size() >= GetMaxAllowedBotCount()) + if (sPlayerbotAIConfig.randomBotAutoJoinBG && playerBots.size() >= GetMaxAllowedBotCount()) { - uint32 randomBotAutoJoinArenaBracket = sPlayerbotAIConfig->randomBotAutoJoinArenaBracket; - uint32 randomBotAutoJoinBGRatedArena2v2Count = sPlayerbotAIConfig->randomBotAutoJoinBGRatedArena2v2Count; - uint32 randomBotAutoJoinBGRatedArena3v3Count = sPlayerbotAIConfig->randomBotAutoJoinBGRatedArena3v3Count; - uint32 randomBotAutoJoinBGRatedArena5v5Count = sPlayerbotAIConfig->randomBotAutoJoinBGRatedArena5v5Count; + uint32 randomBotAutoJoinArenaBracket = sPlayerbotAIConfig.randomBotAutoJoinArenaBracket; + uint32 randomBotAutoJoinBGRatedArena2v2Count = sPlayerbotAIConfig.randomBotAutoJoinBGRatedArena2v2Count; + uint32 randomBotAutoJoinBGRatedArena3v3Count = sPlayerbotAIConfig.randomBotAutoJoinBGRatedArena3v3Count; + uint32 randomBotAutoJoinBGRatedArena5v5Count = sPlayerbotAIConfig.randomBotAutoJoinBGRatedArena5v5Count; - uint32 randomBotAutoJoinBGICCount = sPlayerbotAIConfig->randomBotAutoJoinBGICCount; - uint32 randomBotAutoJoinBGEYCount = sPlayerbotAIConfig->randomBotAutoJoinBGEYCount; - uint32 randomBotAutoJoinBGAVCount = sPlayerbotAIConfig->randomBotAutoJoinBGAVCount; - uint32 randomBotAutoJoinBGABCount = sPlayerbotAIConfig->randomBotAutoJoinBGABCount; - uint32 randomBotAutoJoinBGWSCount = sPlayerbotAIConfig->randomBotAutoJoinBGWSCount; + uint32 randomBotAutoJoinBGICCount = sPlayerbotAIConfig.randomBotAutoJoinBGICCount; + uint32 randomBotAutoJoinBGEYCount = sPlayerbotAIConfig.randomBotAutoJoinBGEYCount; + uint32 randomBotAutoJoinBGAVCount = sPlayerbotAIConfig.randomBotAutoJoinBGAVCount; + uint32 randomBotAutoJoinBGABCount = sPlayerbotAIConfig.randomBotAutoJoinBGABCount; + uint32 randomBotAutoJoinBGWSCount = sPlayerbotAIConfig.randomBotAutoJoinBGWSCount; - std::vector icBrackets = parseBrackets(sPlayerbotAIConfig->randomBotAutoJoinICBrackets); - std::vector eyBrackets = parseBrackets(sPlayerbotAIConfig->randomBotAutoJoinEYBrackets); - std::vector avBrackets = parseBrackets(sPlayerbotAIConfig->randomBotAutoJoinAVBrackets); - std::vector abBrackets = parseBrackets(sPlayerbotAIConfig->randomBotAutoJoinABBrackets); - std::vector wsBrackets = parseBrackets(sPlayerbotAIConfig->randomBotAutoJoinWSBrackets); + std::vector icBrackets = parseBrackets(sPlayerbotAIConfig.randomBotAutoJoinICBrackets); + std::vector eyBrackets = parseBrackets(sPlayerbotAIConfig.randomBotAutoJoinEYBrackets); + std::vector avBrackets = parseBrackets(sPlayerbotAIConfig.randomBotAutoJoinAVBrackets); + std::vector abBrackets = parseBrackets(sPlayerbotAIConfig.randomBotAutoJoinABBrackets); + std::vector wsBrackets = parseBrackets(sPlayerbotAIConfig.randomBotAutoJoinWSBrackets); // Check both bgInstanceCount / bgInstances.size // to help counter against potentional inconsistencies @@ -1369,7 +1338,7 @@ void RandomPlayerbotMgr::CheckPlayers() LOG_INFO("playerbots", "Checking Players..."); if (!playersLevel) - playersLevel = sPlayerbotAIConfig->randombotStartingLevel; + playersLevel = sPlayerbotAIConfig.randombotStartingLevel; for (std::vector::iterator i = players.begin(); i != players.end(); ++i) { @@ -1393,7 +1362,7 @@ void RandomPlayerbotMgr::ScheduleRandomize(uint32 bot, uint32 time) { SetEventVa void RandomPlayerbotMgr::ScheduleTeleport(uint32 bot, uint32 time) { if (!time) - time = 60 + urand(sPlayerbotAIConfig->randomBotUpdateInterval, sPlayerbotAIConfig->randomBotUpdateInterval * 3); + time = 60 + urand(sPlayerbotAIConfig.randomBotUpdateInterval, sPlayerbotAIConfig.randomBotUpdateInterval * 3); SetEventValue(bot, "teleport", 1, time); } @@ -1401,8 +1370,8 @@ void RandomPlayerbotMgr::ScheduleTeleport(uint32 bot, uint32 time) void RandomPlayerbotMgr::ScheduleChangeStrategy(uint32 bot, uint32 time) { if (!time) - time = urand(sPlayerbotAIConfig->minRandomBotChangeStrategyTime, - sPlayerbotAIConfig->maxRandomBotChangeStrategyTime); + time = urand(sPlayerbotAIConfig.minRandomBotChangeStrategyTime, + sPlayerbotAIConfig.maxRandomBotChangeStrategyTime); SetEventValue(bot, "change_strategy", 1, time); } @@ -1440,7 +1409,7 @@ bool RandomPlayerbotMgr::ProcessBot(uint32 bot) AddPlayerBot(botGUID, 0); randomTime = urand(1, 2); - uint32 randomBotUpdateInterval = _isBotInitializing ? 1 : sPlayerbotAIConfig->randomBotUpdateInterval; + uint32 randomBotUpdateInterval = _isBotInitializing ? 1 : sPlayerbotAIConfig.randomBotUpdateInterval; randomTime = urand(std::max(5, static_cast(randomBotUpdateInterval * 0.5)), std::max(12, static_cast(randomBotUpdateInterval * 2))); SetEventValue(bot, "update", 1, randomTime); @@ -1477,7 +1446,7 @@ bool RandomPlayerbotMgr::ProcessBot(uint32 bot) if (botAI) { // botAI->GetAiObjectContext()->GetValue("random bot update")->Set(true); - if (!sRandomPlayerbotMgr->IsRandomBot(player)) + if (!sRandomPlayerbotMgr.IsRandomBot(player)) update = false; if (player->GetGroup() && botAI->GetGroupLeader()) @@ -1489,14 +1458,14 @@ bool RandomPlayerbotMgr::ProcessBot(uint32 bot) } } - // if (botAI->HasPlayerNearby(sPlayerbotAIConfig->grindDistance)) + // if (botAI->HasPlayerNearby(sPlayerbotAIConfig.grindDistance)) // update = false; } if (update) ProcessBot(player); - randomTime = urand(sPlayerbotAIConfig->minRandomBotReviveTime, sPlayerbotAIConfig->maxRandomBotReviveTime); + randomTime = urand(sPlayerbotAIConfig.minRandomBotReviveTime, sPlayerbotAIConfig.maxRandomBotReviveTime); SetEventValue(bot, "update", 1, randomTime); return true; @@ -1510,7 +1479,7 @@ bool RandomPlayerbotMgr::ProcessBot(uint32 bot) LogoutPlayerBot(botGUID); currentBots.remove(bot); SetEventValue(bot, "logout", 1, - urand(sPlayerbotAIConfig->minRandomBotInWorldTime, sPlayerbotAIConfig->maxRandomBotInWorldTime)); + urand(sPlayerbotAIConfig.minRandomBotInWorldTime, sPlayerbotAIConfig.maxRandomBotInWorldTime)); return true; } @@ -1538,10 +1507,10 @@ bool RandomPlayerbotMgr::ProcessBot(Player* bot) if (!GetEventValue(botId, "dead")) { uint32 randomTime = - urand(sPlayerbotAIConfig->minRandomBotReviveTime, sPlayerbotAIConfig->maxRandomBotReviveTime); + urand(sPlayerbotAIConfig.minRandomBotReviveTime, sPlayerbotAIConfig.maxRandomBotReviveTime); LOG_DEBUG("playerbots", "Mark bot {} as dead, will be revived in {}s.", bot->GetName().c_str(), randomTime); - SetEventValue(botId, "dead", 1, sPlayerbotAIConfig->maxRandomBotInWorldTime); + SetEventValue(botId, "dead", 1, sPlayerbotAIConfig.maxRandomBotInWorldTime); SetEventValue(botId, "revive", 1, randomTime); return false; } @@ -1591,11 +1560,11 @@ bool RandomPlayerbotMgr::ProcessBot(Player* bot) // if (guild->GetLeaderGUID() == player->GetGUID()) // { // for (std::vector::iterator i = players.begin(); i != players.end(); ++i) - // sGuildTaskMgr->Update(*i, player); + // GuildTaskMgr::instance().Update(*i, player); // } // uint32 accountId = sCharacterCache->GetCharacterAccountIdByGuid(guild->GetLeaderGUID()); - // if (!sPlayerbotAIConfig->IsInRandomAccountList(accountId)) + // if (!sPlayerbotAIConfig.IsInRandomAccountList(accountId)) // { // uint8 rank = player->GetRank(); // randomiser = rank < 4 ? false : true; @@ -1608,7 +1577,7 @@ bool RandomPlayerbotMgr::ProcessBot(Player* bot) LOG_DEBUG("playerbots", "Bot #{} {}:{} <{}>: randomized", botId, bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(), bot->GetName()); uint32 randomTime = - urand(sPlayerbotAIConfig->minRandomBotRandomizeTime, sPlayerbotAIConfig->maxRandomBotRandomizeTime); + urand(sPlayerbotAIConfig.minRandomBotRandomizeTime, sPlayerbotAIConfig.maxRandomBotRandomizeTime); ScheduleRandomize(botId, randomTime); return true; } @@ -1627,8 +1596,8 @@ bool RandomPlayerbotMgr::ProcessBot(Player* bot) LOG_DEBUG("playerbots", "Bot #{} <{}>: teleport for level and refresh", botId, bot->GetName()); Refresh(bot); RandomTeleportForLevel(bot); - uint32 time = urand(sPlayerbotAIConfig->minRandomBotTeleportInterval, - sPlayerbotAIConfig->maxRandomBotTeleportInterval); + uint32 time = urand(sPlayerbotAIConfig.minRandomBotTeleportInterval, + sPlayerbotAIConfig.maxRandomBotTeleportInterval); ScheduleTeleport(botId, time); return true; } @@ -1680,7 +1649,7 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector& return; } - // if (sPlayerbotAIConfig->randomBotRpgChance < 0) + // if (sPlayerbotAIConfig.randomBotRpgChance < 0) // return; if (locs.empty()) @@ -1697,9 +1666,9 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector& [bot](WorldPosition l) { std::vector::iterator i = - find(sPlayerbotAIConfig->randomBotMaps.begin(), - sPlayerbotAIConfig->randomBotMaps.end(), l.getMapId()); - return i == sPlayerbotAIConfig->randomBotMaps.end(); + find(sPlayerbotAIConfig.randomBotMaps.begin(), + sPlayerbotAIConfig.randomBotMaps.end(), l.getMapId()); + return i == sPlayerbotAIConfig.randomBotMaps.end(); }), tlocs.end()); if (tlocs.empty()) @@ -1708,17 +1677,17 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector& return; } - PerfMonitorOperation* pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "RandomTeleportByLocations"); + PerfMonitorOperation* pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "RandomTeleportByLocations"); std::shuffle(std::begin(tlocs), std::end(tlocs), RandomEngine::Instance()); for (uint32 i = 0; i < tlocs.size(); i++) { WorldLocation loc = tlocs[i]; - float x = loc.GetPositionX(); // + (attemtps > 0 ? urand(0, sPlayerbotAIConfig->grindDistance) - - // sPlayerbotAIConfig->grindDistance / 2 : 0); - float y = loc.GetPositionY(); // + (attemtps > 0 ? urand(0, sPlayerbotAIConfig->grindDistance) - - // sPlayerbotAIConfig->grindDistance / 2 : 0); + float x = loc.GetPositionX(); // + (attemtps > 0 ? urand(0, sPlayerbotAIConfig.grindDistance) - + // sPlayerbotAIConfig.grindDistance / 2 : 0); + float y = loc.GetPositionY(); // + (attemtps > 0 ? urand(0, sPlayerbotAIConfig.grindDistance) - + // sPlayerbotAIConfig.grindDistance / 2 : 0); float z = loc.GetPositionZ(); Map* map = sMapMgr->FindMap(loc.GetMapId(), 0); @@ -1869,7 +1838,7 @@ void RandomPlayerbotMgr::PrepareZone2LevelBracket() zone2LevelBracket[4197] = {79, 80}; // Wintergrasp // Override with values from config - for (auto const& [zoneId, bracketPair] : sPlayerbotAIConfig->zoneBrackets) + for (auto const& [zoneId, bracketPair] : sPlayerbotAIConfig.zoneBrackets) { zone2LevelBracket[zoneId] = {bracketPair.first, bracketPair.second}; } @@ -1920,7 +1889,7 @@ void RandomPlayerbotMgr::PrepareTeleportCache() "INNER JOIN creature_template t on c.id1 = t.entry " "ORDER BY " "t.minlevel;", - sPlayerbotAIConfig->randomBotMapsAsString.c_str()); + sPlayerbotAIConfig.randomBotMapsAsString.c_str()); uint32 collected_locs = 0; if (results) { @@ -1936,8 +1905,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.randomBotTeleLowerLevel; + l <= (int32)level + (int32)sPlayerbotAIConfig.randomBotTeleHigherLevel; l++) { if (l < 1 || l > maxLevel) { @@ -1949,7 +1918,7 @@ void RandomPlayerbotMgr::PrepareTeleportCache() } LOG_INFO("playerbots", ">> {} locations for level collected.", collected_locs); - if (sPlayerbotAIConfig->enableNewRpgStrategy) + if (sPlayerbotAIConfig.enableNewRpgStrategy) { PrepareZone2LevelBracket(); LOG_INFO("playerbots", "Preparing innkeepers / flightmasters locations for level..."); @@ -1972,7 +1941,7 @@ void RandomPlayerbotMgr::PrepareTeleportCache() "AND map IN ({}) " "ORDER BY " "t.minlevel;", - sPlayerbotAIConfig->randomBotMapsAsString.c_str()); + sPlayerbotAIConfig.randomBotMapsAsString.c_str()); collected_locs = 0; if (results) { @@ -2005,10 +1974,10 @@ void RandomPlayerbotMgr::PrepareTeleportCache() { WorldPosition pos(mapId, x, y, z, orient); if (forHorde) - sFlightMasterCache->AddHordeFlightMaster(guid, pos); + FlightMasterCache::Instance().AddHordeFlightMaster(guid, pos); if (forAlliance) - sFlightMasterCache->AddAllianceFlightMaster(guid, pos); + FlightMasterCache::Instance().AddAllianceFlightMaster(guid, pos); } const AreaTableEntry* area = sAreaTableStore.LookupEntry(map->GetAreaId(PHASEMASK_NORMAL, x, y, z)); uint32 zoneId = area->zone ? area->zone : area->ID; @@ -2077,7 +2046,7 @@ void RandomPlayerbotMgr::PrepareTeleportCache() "AND map IN ({}) " "ORDER BY " "t.minlevel;", - sPlayerbotAIConfig->randomBotMapsAsString.c_str()); + sPlayerbotAIConfig.randomBotMapsAsString.c_str()); collected_locs = 0; if (results) { @@ -2157,16 +2126,16 @@ void RandomPlayerbotMgr::PrepareAddclassCache() void RandomPlayerbotMgr::Init() { - if (sPlayerbotAIConfig->addClassCommand) - sRandomPlayerbotMgr->PrepareAddclassCache(); + if (sPlayerbotAIConfig.addClassCommand) + sRandomPlayerbotMgr.PrepareAddclassCache(); - if (sPlayerbotAIConfig->enabled) + if (sPlayerbotAIConfig.enabled) { - sRandomPlayerbotMgr->PrepareTeleportCache(); + sRandomPlayerbotMgr.PrepareTeleportCache(); } - if (sPlayerbotAIConfig->randomBotJoinBG) - sRandomPlayerbotMgr->LoadBattleMastersCache(); + if (sPlayerbotAIConfig.randomBotJoinBG) + sRandomPlayerbotMgr.LoadBattleMastersCache(); PlayerbotsDatabase.Execute("DELETE FROM playerbots_random_bots WHERE event = 'add'"); } @@ -2179,17 +2148,17 @@ void RandomPlayerbotMgr::RandomTeleportForLevel(Player* bot) uint32 level = bot->GetLevel(); uint8 race = bot->getRace(); std::vector* locs = nullptr; - if (sPlayerbotAIConfig->enableNewRpgStrategy) + if (sPlayerbotAIConfig.enableNewRpgStrategy) locs = IsAlliance(race) ? &allianceStarterPerLevelCache[level] : &hordeStarterPerLevelCache[level]; else locs = &locsPerLevelCache[level]; - if (level >= 10 && urand(0, 100) < sPlayerbotAIConfig->probTeleToBankers * 100) + if (level >= 10 && urand(0, 100) < sPlayerbotAIConfig.probTeleToBankers * 100) { std::vector fallbackLocs; for (auto& bLoc : bankerLocsPerLevelCache[level]) fallbackLocs.push_back(bLoc.loc); - if (!sPlayerbotAIConfig->enableWeightTeleToCityBankers) + if (!sPlayerbotAIConfig.enableWeightTeleToCityBankers) { RandomTeleport(bot, fallbackLocs, true); return; @@ -2227,16 +2196,16 @@ void RandomPlayerbotMgr::RandomTeleportForLevel(Player* bot) int weight = 0; switch (city) { - case CityId::STORMWIND: weight = sPlayerbotAIConfig->weightTeleToStormwind; break; - case CityId::IRONFORGE: weight = sPlayerbotAIConfig->weightTeleToIronforge; break; - case CityId::DARNASSUS: weight = sPlayerbotAIConfig->weightTeleToDarnassus; break; - case CityId::EXODAR: weight = sPlayerbotAIConfig->weightTeleToExodar; break; - case CityId::ORGRIMMAR: weight = sPlayerbotAIConfig->weightTeleToOrgrimmar; break; - case CityId::UNDERCITY: weight = sPlayerbotAIConfig->weightTeleToUndercity; break; - case CityId::THUNDER_BLUFF: weight = sPlayerbotAIConfig->weightTeleToThunderBluff; break; - case CityId::SILVERMOON_CITY: weight = sPlayerbotAIConfig->weightTeleToSilvermoonCity; break; - case CityId::SHATTRATH_CITY: weight = sPlayerbotAIConfig->weightTeleToShattrathCity; break; - case CityId::DALARAN: weight = sPlayerbotAIConfig->weightTeleToDalaran; break; + case CityId::STORMWIND: weight = sPlayerbotAIConfig.weightTeleToStormwind; break; + case CityId::IRONFORGE: weight = sPlayerbotAIConfig.weightTeleToIronforge; break; + case CityId::DARNASSUS: weight = sPlayerbotAIConfig.weightTeleToDarnassus; break; + case CityId::EXODAR: weight = sPlayerbotAIConfig.weightTeleToExodar; break; + case CityId::ORGRIMMAR: weight = sPlayerbotAIConfig.weightTeleToOrgrimmar; break; + case CityId::UNDERCITY: weight = sPlayerbotAIConfig.weightTeleToUndercity; break; + case CityId::THUNDER_BLUFF: weight = sPlayerbotAIConfig.weightTeleToThunderBluff; break; + case CityId::SILVERMOON_CITY: weight = sPlayerbotAIConfig.weightTeleToSilvermoonCity; break; + case CityId::SHATTRATH_CITY: weight = sPlayerbotAIConfig.weightTeleToShattrathCity; break; + case CityId::DALARAN: weight = sPlayerbotAIConfig.weightTeleToDalaran; break; default: weight = 0; break; } if (weight <= 0) continue; @@ -2284,7 +2253,7 @@ void RandomPlayerbotMgr::RandomTeleportGrindForLevel(Player* bot) uint32 level = bot->GetLevel(); uint8 race = bot->getRace(); std::vector* locs = nullptr; - if (sPlayerbotAIConfig->enableNewRpgStrategy) + if (sPlayerbotAIConfig.enableNewRpgStrategy) locs = IsAlliance(race) ? &allianceStarterPerLevelCache[level] : &hordeStarterPerLevelCache[level]; else locs = &locsPerLevelCache[level]; @@ -2299,11 +2268,11 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot) if (bot->InBattleground()) return; - PerfMonitorOperation* pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "RandomTeleport"); + PerfMonitorOperation* pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "RandomTeleport"); std::vector locs; std::list targets; - float range = sPlayerbotAIConfig->randomBotTeleportDistance; + float range = sPlayerbotAIConfig.randomBotTeleportDistance; Acore::AnyUnitInObjectRangeCheck u_check(bot, range); Acore::UnitListSearcher searcher(bot, targets, u_check); Cell::VisitObjects(bot, searcher, range); @@ -2313,7 +2282,7 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot) for (Unit* unit : targets) { bot->UpdatePosition(*unit); - FleeManager manager(bot, sPlayerbotAIConfig->sightDistance, 0, true); + FleeManager manager(bot, sPlayerbotAIConfig.sightDistance, 0, true); float rx, ry, rz; if (manager.CalculateDestination(&rx, &ry, &rz)) { @@ -2342,7 +2311,7 @@ void RandomPlayerbotMgr::Randomize(Player* bot) { RandomizeFirst(bot); } - else if (bot->GetLevel() < sPlayerbotAIConfig->randomBotMaxLevel || !sPlayerbotAIConfig->downgradeMaxLevelBot) + else if (bot->GetLevel() < sPlayerbotAIConfig.randomBotMaxLevel || !sPlayerbotAIConfig.downgradeMaxLevelBot) { uint8 level = bot->GetLevel(); PlayerbotFactory factory(bot, level); @@ -2357,11 +2326,11 @@ void RandomPlayerbotMgr::Randomize(Player* bot) void RandomPlayerbotMgr::IncreaseLevel(Player* bot) { - uint32 maxLevel = sPlayerbotAIConfig->randomBotMaxLevel; + uint32 maxLevel = sPlayerbotAIConfig.randomBotMaxLevel; if (maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); - PerfMonitorOperation* pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "IncreaseLevel"); + PerfMonitorOperation* pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "IncreaseLevel"); uint32 lastLevel = GetValue(bot, "level"); uint8 level = bot->GetLevel() + 1; if (level > maxLevel) @@ -2384,27 +2353,27 @@ void RandomPlayerbotMgr::RandomizeFirst(Player* bot) if (!botAI) return; - uint32 maxLevel = sPlayerbotAIConfig->randomBotMaxLevel; + uint32 maxLevel = sPlayerbotAIConfig.randomBotMaxLevel; if (maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); // if lvl sync is enabled, max level is limited by online players lvl - if (sPlayerbotAIConfig->syncLevelWithPlayers) - maxLevel = std::max(sPlayerbotAIConfig->randomBotMinLevel, + if (sPlayerbotAIConfig.syncLevelWithPlayers) + maxLevel = std::max(sPlayerbotAIConfig.randomBotMinLevel, std::min(playersLevel, sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))); - uint32 minLevel = sPlayerbotAIConfig->randomBotMinLevel; + uint32 minLevel = sPlayerbotAIConfig.randomBotMinLevel; if (bot->getClass() == CLASS_DEATH_KNIGHT) { maxLevel = std::max(maxLevel, sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL)); minLevel = std::max(minLevel, sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL)); } - PerfMonitorOperation* pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "RandomizeFirst"); + PerfMonitorOperation* pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "RandomizeFirst"); uint32 level; - if (sPlayerbotAIConfig->downgradeMaxLevelBot && bot->GetLevel() >= sPlayerbotAIConfig->randomBotMaxLevel) + if (sPlayerbotAIConfig.downgradeMaxLevelBot && bot->GetLevel() >= sPlayerbotAIConfig.randomBotMaxLevel) { if (bot->getClass() == CLASS_DEATH_KNIGHT) { @@ -2412,18 +2381,18 @@ void RandomPlayerbotMgr::RandomizeFirst(Player* bot) } else { - level = sPlayerbotAIConfig->randomBotMinLevel; + level = sPlayerbotAIConfig.randomBotMinLevel; } } else { uint32 roll = urand(1, 100); - if (roll <= 100 * sPlayerbotAIConfig->randomBotMaxLevelChance) + if (roll <= 100 * sPlayerbotAIConfig.randomBotMaxLevelChance) { level = maxLevel; } else if (roll <= - (100 * (sPlayerbotAIConfig->randomBotMaxLevelChance + sPlayerbotAIConfig->randomBotMinLevelChance))) + (100 * (sPlayerbotAIConfig.randomBotMaxLevelChance + sPlayerbotAIConfig.randomBotMinLevelChance))) { level = minLevel; } @@ -2433,11 +2402,11 @@ void RandomPlayerbotMgr::RandomizeFirst(Player* bot) } } - if (sPlayerbotAIConfig->disableRandomLevels) + if (sPlayerbotAIConfig.disableRandomLevels) { - level = bot->getClass() == CLASS_DEATH_KNIGHT ? std::max(sPlayerbotAIConfig->randombotStartingLevel, + level = bot->getClass() == CLASS_DEATH_KNIGHT ? std::max(sPlayerbotAIConfig.randombotStartingLevel, sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL)) - : sPlayerbotAIConfig->randombotStartingLevel; + : sPlayerbotAIConfig.randombotStartingLevel; } SetValue(bot, "level", level); @@ -2445,9 +2414,9 @@ void RandomPlayerbotMgr::RandomizeFirst(Player* bot) factory.Randomize(false); uint32 randomTime = - urand(sPlayerbotAIConfig->minRandomBotRandomizeTime, sPlayerbotAIConfig->maxRandomBotRandomizeTime); + urand(sPlayerbotAIConfig.minRandomBotRandomizeTime, sPlayerbotAIConfig.maxRandomBotRandomizeTime); uint32 inworldTime = - urand(sPlayerbotAIConfig->minRandomBotInWorldTime, sPlayerbotAIConfig->maxRandomBotInWorldTime); + urand(sPlayerbotAIConfig.minRandomBotInWorldTime, sPlayerbotAIConfig.maxRandomBotInWorldTime); PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_UPD_RANDOM_BOTS); stmt->SetData(0, randomTime); @@ -2479,16 +2448,16 @@ void RandomPlayerbotMgr::RandomizeMin(Player* bot) if (!botAI) return; - PerfMonitorOperation* pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "RandomizeMin"); - uint32 level = sPlayerbotAIConfig->randomBotMinLevel; + PerfMonitorOperation* pmo = sPerfMonitor.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); + urand(sPlayerbotAIConfig.minRandomBotRandomizeTime, sPlayerbotAIConfig.maxRandomBotRandomizeTime); uint32 inworldTime = - urand(sPlayerbotAIConfig->minRandomBotInWorldTime, sPlayerbotAIConfig->maxRandomBotInWorldTime); + urand(sPlayerbotAIConfig.minRandomBotInWorldTime, sPlayerbotAIConfig.maxRandomBotInWorldTime); PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_UPD_RANDOM_BOTS); stmt->SetData(0, randomTime); @@ -2527,8 +2496,8 @@ uint32 RandomPlayerbotMgr::GetZoneLevel(uint16 mapId, float teleX, float teleY, "SELECT AVG(t.minlevel) minlevel, AVG(t.maxlevel) maxlevel FROM creature c " "INNER JOIN creature_template t ON c.id1 = t.entry WHERE map = {} AND minlevel > 1 AND ABS(position_x - {}) < " "{} AND ABS(position_y - {}) < {}", - mapId, teleX, sPlayerbotAIConfig->randomBotTeleportDistance / 2, teleY, - sPlayerbotAIConfig->randomBotTeleportDistance / 2); + mapId, teleX, sPlayerbotAIConfig.randomBotTeleportDistance / 2, teleY, + sPlayerbotAIConfig.randomBotTeleportDistance / 2); if (results) { @@ -2560,7 +2529,7 @@ void RandomPlayerbotMgr::Refresh(Player* bot) botAI->ResetStrategies(false); } - // if (sPlayerbotAIConfig->disableRandomLevels) + // if (sPlayerbotAIConfig.disableRandomLevels) // return; if (bot->InBattleground()) @@ -2568,7 +2537,7 @@ void RandomPlayerbotMgr::Refresh(Player* bot) LOG_DEBUG("playerbots", "Refreshing bot {} <{}>", bot->GetGUID().ToString().c_str(), bot->GetName().c_str()); - PerfMonitorOperation* pmo = sPerfMonitor->start(PERF_MON_RNDBOT, "Refresh"); + PerfMonitorOperation* pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "Refresh"); botAI->Reset(); @@ -2612,7 +2581,7 @@ bool RandomPlayerbotMgr::IsRandomBot(Player* bot) bool RandomPlayerbotMgr::IsRandomBot(ObjectGuid::LowType bot) { ObjectGuid guid = ObjectGuid::Create(bot); - if (!sPlayerbotAIConfig->IsInRandomAccountList(sCharacterCache->GetCharacterAccountIdByGuid(guid))) + if (!sPlayerbotAIConfig.IsInRandomAccountList(sCharacterCache->GetCharacterAccountIdByGuid(guid))) return false; if (std::find(currentBots.begin(), currentBots.end(), bot) != currentBots.end()) @@ -2841,7 +2810,7 @@ std::string RandomPlayerbotMgr::GetData(uint32 bot, std::string const& type) { r void RandomPlayerbotMgr::SetValue(uint32 bot, std::string const& type, uint32 value, std::string const& data) { - SetEventValue(bot, type, value, sPlayerbotAIConfig->maxRandomBotInWorldTime, data); + SetEventValue(bot, type, value, sPlayerbotAIConfig.maxRandomBotInWorldTime, data); } void RandomPlayerbotMgr::SetValue(Player* bot, std::string const& type, uint32 value, std::string const& data) @@ -2851,7 +2820,7 @@ void RandomPlayerbotMgr::SetValue(Player* bot, std::string const& type, uint32 v bool RandomPlayerbotMgr::HandlePlayerbotConsoleCommand(ChatHandler* handler, char const* args) { - if (!sPlayerbotAIConfig->enabled) + if (!sPlayerbotAIConfig.enabled) { LOG_ERROR("playerbots", "Playerbots system is currently disabled!"); return false; @@ -2868,27 +2837,27 @@ bool RandomPlayerbotMgr::HandlePlayerbotConsoleCommand(ChatHandler* handler, cha if (cmd == "reset") { PlayerbotsDatabase.Execute(PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_DEL_RANDOM_BOTS)); - sRandomPlayerbotMgr->eventCache.clear(); + sRandomPlayerbotMgr.eventCache.clear(); LOG_INFO("playerbots", "Random bots were reset for all players. Please restart the Server."); return true; } if (cmd == "stats") { - sRandomPlayerbotMgr->PrintStats(); + sRandomPlayerbotMgr.PrintStats(); // activatePrintStatsThread(); return true; } if (cmd == "reload") { - sPlayerbotAIConfig->Initialize(); + sPlayerbotAIConfig.Initialize(); return true; } if (cmd == "update") { - sRandomPlayerbotMgr->UpdateAIInternal(0); + sRandomPlayerbotMgr.UpdateAIInternal(0); return true; } @@ -2913,8 +2882,8 @@ bool RandomPlayerbotMgr::HandlePlayerbotConsoleCommand(ChatHandler* handler, cha std::string const name = cmd.size() > prefix.size() + 1 ? cmd.substr(1 + prefix.size()) : "%"; std::vector botIds; - for (std::vector::iterator i = sPlayerbotAIConfig->randomBotAccounts.begin(); - i != sPlayerbotAIConfig->randomBotAccounts.end(); ++i) + for (std::vector::iterator i = sPlayerbotAIConfig.randomBotAccounts.begin(); + i != sPlayerbotAIConfig.randomBotAccounts.end(); ++i) { uint32 account = *i; if (QueryResult results = CharacterDatabase.Query( @@ -2926,7 +2895,7 @@ bool RandomPlayerbotMgr::HandlePlayerbotConsoleCommand(ChatHandler* handler, cha uint32 botId = fields[0].Get(); ObjectGuid guid = ObjectGuid::Create(botId); - if (!sRandomPlayerbotMgr->IsRandomBot(guid.GetCounter())) + if (!sRandomPlayerbotMgr.IsRandomBot(guid.GetCounter())) { continue; } @@ -2957,13 +2926,13 @@ bool RandomPlayerbotMgr::HandlePlayerbotConsoleCommand(ChatHandler* handler, cha bot->GetName().c_str()); ConsoleCommandHandler handler = j->second; - (sRandomPlayerbotMgr->*handler)(bot); + (sRandomPlayerbotMgr.*handler)(bot); } return true; } - // std::vector messages = sRandomPlayerbotMgr->HandlePlayerbotCommand(args); + // std::vector messages = sRandomPlayerbotMgr.HandlePlayerbotCommand(args); // for (std::vector::iterator i = messages.begin(); i != messages.end(); ++i) // { // LOG_INFO("playerbots", "{}", i->c_str()); @@ -3021,15 +2990,15 @@ void RandomPlayerbotMgr::OnBotLoginInternal(Player* const bot) if (_isBotLogging) { LOG_INFO("playerbots", "{}/{} Bot {} logged in", playerBots.size(), - sRandomPlayerbotMgr->GetMaxAllowedBotCount(), bot->GetName().c_str()); + sRandomPlayerbotMgr.GetMaxAllowedBotCount(), bot->GetName().c_str()); - if (playerBots.size() == sRandomPlayerbotMgr->GetMaxAllowedBotCount()) + if (playerBots.size() == sRandomPlayerbotMgr.GetMaxAllowedBotCount()) { _isBotLogging = false; } } - if (sPlayerbotAIConfig->randomBotFixedLevel) + if (sPlayerbotAIConfig.randomBotFixedLevel) { bot->SetPlayerFlag(PLAYER_FLAGS_NO_XP_GAIN); } @@ -3081,18 +3050,18 @@ void RandomPlayerbotMgr::OnPlayerLogin(Player* player) { WorldPosition botPos(player); - // botPos.GetReachableRandomPointOnGround(player, sPlayerbotAIConfig->reactDistance * 2, true); + // botPos.GetReachableRandomPointOnGround(player, sPlayerbotAIConfig.reactDistance * 2, true); // player->TeleportTo(botPos); // player->Relocate(botPos.coord_x, botPos.coord_y, botPos.coord_z, botPos.orientation); if (!player->GetFactionTemplateEntry()) { - botPos.GetReachableRandomPointOnGround(player, sPlayerbotAIConfig->reactDistance * 2, true); + botPos.GetReachableRandomPointOnGround(player, sPlayerbotAIConfig.reactDistance * 2, true); } else { - std::vector dests = sTravelMgr->getRpgTravelDestinations(player, true, true, 200000.0f); + std::vector dests = TravelMgr::instance().getRpgTravelDestinations(player, true, true, 200000.0f); do { @@ -3281,7 +3250,7 @@ void RandomPlayerbotMgr::PrintStats() zoneCount[bot->GetZoneId()]++; - if (sPlayerbotAIConfig->enableNewRpgStrategy) + if (sPlayerbotAIConfig.enableNewRpgStrategy) { rpgStatusCount[botAI->rpgInfo.status]++; rpgStasticTotal += botAI->rpgStatistic; @@ -3355,7 +3324,7 @@ void RandomPlayerbotMgr::PrintStats() LOG_INFO("playerbots", " In Rest: {}", rest); LOG_INFO("playerbots", " Dead: {}", dead); - if (sPlayerbotAIConfig->enableNewRpgStrategy) + if (sPlayerbotAIConfig.enableNewRpgStrategy) { LOG_INFO("playerbots", "Bots rpg status:"); LOG_INFO("playerbots", @@ -3381,8 +3350,8 @@ double RandomPlayerbotMgr::GetBuyMultiplier(Player* bot) if (!value) { value = urand(50, 120); - uint32 validIn = urand(sPlayerbotAIConfig->minRandomBotsPriceChangeInterval, - sPlayerbotAIConfig->maxRandomBotsPriceChangeInterval); + uint32 validIn = urand(sPlayerbotAIConfig.minRandomBotsPriceChangeInterval, + sPlayerbotAIConfig.maxRandomBotsPriceChangeInterval); SetEventValue(id, "buymultiplier", value, validIn); } @@ -3396,8 +3365,8 @@ double RandomPlayerbotMgr::GetSellMultiplier(Player* bot) if (!value) { value = urand(80, 250); - uint32 validIn = urand(sPlayerbotAIConfig->minRandomBotsPriceChangeInterval, - sPlayerbotAIConfig->maxRandomBotsPriceChangeInterval); + uint32 validIn = urand(sPlayerbotAIConfig.minRandomBotsPriceChangeInterval, + sPlayerbotAIConfig.maxRandomBotsPriceChangeInterval); SetEventValue(id, "sellmultiplier", value, validIn); } @@ -3426,7 +3395,7 @@ void RandomPlayerbotMgr::SetTradeDiscount(Player* bot, Player* master, uint32 va std::ostringstream name; name << "trade_discount_" << masterId; - SetEventValue(botId, name.str(), value, sPlayerbotAIConfig->maxRandomBotInWorldTime); + SetEventValue(botId, name.str(), value, sPlayerbotAIConfig.maxRandomBotInWorldTime); } uint32 RandomPlayerbotMgr::GetTradeDiscount(Player* bot, Player* master) @@ -3469,7 +3438,7 @@ void RandomPlayerbotMgr::ChangeStrategy(Player* player) { uint32 bot = player->GetGUID().GetCounter(); - if (frand(0.f, 100.f) > sPlayerbotAIConfig->randomBotRpgChance) + if (frand(0.f, 100.f) > sPlayerbotAIConfig.randomBotRpgChance) { LOG_INFO("playerbots", "Bot #{} <{}>: sent to grind spot", bot, player->GetName().c_str()); ScheduleTeleport(bot, 30); @@ -3479,7 +3448,7 @@ void RandomPlayerbotMgr::ChangeStrategy(Player* player) LOG_INFO("playerbots", "Changing strategy for bot #{} <{}> to RPG", bot, player->GetName().c_str()); LOG_INFO("playerbots", "Bot #{} <{}>: sent to inn", bot, player->GetName().c_str()); RandomTeleportForLevel(player); - SetEventValue(bot, "teleport", 1, sPlayerbotAIConfig->maxRandomBotInWorldTime); + SetEventValue(bot, "teleport", 1, sPlayerbotAIConfig.maxRandomBotInWorldTime); } ScheduleChangeStrategy(bot); @@ -3489,7 +3458,7 @@ void RandomPlayerbotMgr::ChangeStrategyOnce(Player* player) { uint32 bot = player->GetGUID().GetCounter(); - if (frand(0.f, 100.f) > sPlayerbotAIConfig->randomBotRpgChance) // select grind / pvp + if (frand(0.f, 100.f) > sPlayerbotAIConfig.randomBotRpgChance) // select grind / pvp { LOG_INFO("playerbots", "Bot #{} <{}>: sent to grind spot", bot, player->GetName().c_str()); RandomTeleportForLevel(player); @@ -3565,7 +3534,7 @@ ObjectGuid RandomPlayerbotMgr::GetBattleMasterGUID(Player* bot, BattlegroundType for (auto i = begin(Bms); i != end(Bms); ++i) { - CreatureData const* data = sRandomPlayerbotMgr->GetCreatureDataByEntry(*i); + CreatureData const* data = sRandomPlayerbotMgr.GetCreatureDataByEntry(*i); if (!data) continue; @@ -3596,7 +3565,7 @@ ObjectGuid RandomPlayerbotMgr::GetBattleMasterGUID(Player* bot, BattlegroundType if (Bm->getDeathState() == DeathState::Dead) continue; - float dist2 = sServerFacade->GetDistance2d(bot, data->posX, data->posY); + float dist2 = ServerFacade::instance().GetDistance2d(bot, data->posX, data->posY); if (dist2 < dist1) { dist1 = dist2; diff --git a/src/Bot/RandomPlayerbotMgr.h b/src/Bot/RandomPlayerbotMgr.h index 26d09d454e..94c0a01513 100644 --- a/src/Bot/RandomPlayerbotMgr.h +++ b/src/Bot/RandomPlayerbotMgr.h @@ -10,6 +10,7 @@ #include "ObjectGuid.h" #include "PlayerbotMgr.h" #include "GameTime.h" +#include "PlayerbotCommandServer.h" struct BattlegroundInfo { @@ -88,12 +89,11 @@ class botPID class RandomPlayerbotMgr : public PlayerbotHolder { public: - RandomPlayerbotMgr(); - virtual ~RandomPlayerbotMgr(); - static RandomPlayerbotMgr* instance() + static RandomPlayerbotMgr& instance() { static RandomPlayerbotMgr instance; - return &instance; + + return instance; } void LogPlayerLocation(); @@ -192,6 +192,43 @@ class RandomPlayerbotMgr : public PlayerbotHolder void OnBotLoginInternal(Player* const bot) override; private: + RandomPlayerbotMgr() : PlayerbotHolder(), processTicks(0) + { + this->playersLevel = sPlayerbotAIConfig.randombotStartingLevel; + + if (sPlayerbotAIConfig.enabled || sPlayerbotAIConfig.randomBotAutologin) + { + PlayerbotCommandServer::instance().Start(); + } + + BattlegroundData.clear(); // Clear here and here only. + + // Cleanup on server start: orphaned pet data that's often left behind by bot pets that no longer exist in the DB + CharacterDatabase.Execute("DELETE FROM pet_aura WHERE guid NOT IN (SELECT id FROM character_pet)"); + CharacterDatabase.Execute("DELETE FROM pet_spell WHERE guid NOT IN (SELECT id FROM character_pet)"); + CharacterDatabase.Execute("DELETE FROM pet_spell_cooldown WHERE guid NOT IN (SELECT id FROM character_pet)"); + + for (int bracket = BG_BRACKET_ID_FIRST; bracket < MAX_BATTLEGROUND_BRACKETS; ++bracket) + { + for (int queueType = BATTLEGROUND_QUEUE_AV; queueType < MAX_BATTLEGROUND_QUEUE_TYPES; ++queueType) + { + this->BattlegroundData[queueType][bracket] = BattlegroundInfo(); + } + } + + this->BgCheckTimer = 0; + this->LfgCheckTimer = 0; + this->PlayersCheckTimer = 0; + } + + ~RandomPlayerbotMgr() = default; + + RandomPlayerbotMgr(const RandomPlayerbotMgr&) = delete; + RandomPlayerbotMgr& operator=(const RandomPlayerbotMgr&) = delete; + + RandomPlayerbotMgr(RandomPlayerbotMgr&&) = delete; + RandomPlayerbotMgr& operator=(RandomPlayerbotMgr&&) = delete; + // pid values are set in constructor botPID pid = botPID(1, 50, -50, 0, 0, 0); float activityMod = 0.25; diff --git a/src/Db/FlightMasterCache.cpp b/src/Db/FlightMasterCache.cpp index c708e09cb8..effe249936 100644 --- a/src/Db/FlightMasterCache.cpp +++ b/src/Db/FlightMasterCache.cpp @@ -13,7 +13,7 @@ void FlightMasterCache::AddAllianceFlightMaster(uint32 entry, WorldPosition pos) Creature* FlightMasterCache::GetNearestFlightMaster(Player* bot) { std::map& flightMasterCache = - (bot->GetTeamId() == ALLIANCE) ? allianceFlightMasterCache : hordeFlightMasterCache; + (bot->GetTeamId() == TEAM_ALLIANCE) ? allianceFlightMasterCache : hordeFlightMasterCache; Creature* nearestFlightMaster = nullptr; float nearestDistance = std::numeric_limits::max(); diff --git a/src/Db/FlightMasterCache.h b/src/Db/FlightMasterCache.h index 519d6fc7c8..7f8b95310d 100644 --- a/src/Db/FlightMasterCache.h +++ b/src/Db/FlightMasterCache.h @@ -8,10 +8,11 @@ class FlightMasterCache { public: - static FlightMasterCache* Instance() + static FlightMasterCache& Instance() { static FlightMasterCache instance; - return &instance; + + return instance; } Creature* GetNearestFlightMaster(Player* bot); @@ -19,9 +20,17 @@ class FlightMasterCache void AddAllianceFlightMaster(uint32 entry, WorldPosition pos); private: + FlightMasterCache() = default; + ~FlightMasterCache() = default; + + FlightMasterCache(const FlightMasterCache&) = delete; + FlightMasterCache& operator=(const FlightMasterCache&) = delete; + + FlightMasterCache(FlightMasterCache&&) = delete; + FlightMasterCache& operator=(FlightMasterCache&&) = delete; + std::map allianceFlightMasterCache; std::map hordeFlightMasterCache; }; -#define sFlightMasterCache FlightMasterCache::Instance() #endif diff --git a/src/Db/PlayerbotDungeonRepository.cpp b/src/Db/PlayerbotDungeonRepository.cpp index 3ee40e5616..5e1f370b6a 100644 --- a/src/Db/PlayerbotDungeonRepository.cpp +++ b/src/Db/PlayerbotDungeonRepository.cpp @@ -3,9 +3,15 @@ * and/or modify it under version 3 of the License, or (at your option), any later version. */ -#include "PlayerbotDungeonRepository.h" +#include "Log.h" +#include "Timer.h" +#include "DatabaseEnv.h" +#include "Field.h" +#include "World.h" +// Required import due to poor implementation by AC +#include "QueryResult.h" -#include "Playerbots.h" +#include "PlayerbotDungeonRepository.h" std::vector const PlayerbotDungeonRepository::GetDungeonSuggestions() { diff --git a/src/Db/PlayerbotDungeonRepository.h b/src/Db/PlayerbotDungeonRepository.h index 8c709152a8..160a7622c3 100644 --- a/src/Db/PlayerbotDungeonRepository.h +++ b/src/Db/PlayerbotDungeonRepository.h @@ -6,10 +6,9 @@ #ifndef _PLAYERBOT_PLAYERBOTDUNGEONREPOSITORY_H #define _PLAYERBOT_PLAYERBOTDUNGEONREPOSITORY_H -#include #include +#include -#include "Common.h" #include "DBCEnums.h" struct DungeonSuggestion @@ -22,24 +21,31 @@ struct DungeonSuggestion std::string strategy; }; +// @TODO: Completely unused at this moment. class PlayerbotDungeonRepository { public: - PlayerbotDungeonRepository(){}; - ~PlayerbotDungeonRepository(){}; - static PlayerbotDungeonRepository* instance() + static PlayerbotDungeonRepository& instance() { static PlayerbotDungeonRepository instance; - return &instance; + + return instance; } void LoadDungeonSuggestions(); std::vector const GetDungeonSuggestions(); private: + PlayerbotDungeonRepository() = default; + ~PlayerbotDungeonRepository() = default; + + PlayerbotDungeonRepository(const PlayerbotDungeonRepository&) = delete; + PlayerbotDungeonRepository& operator=(const PlayerbotDungeonRepository&) = delete; + + PlayerbotDungeonRepository(PlayerbotDungeonRepository&&) = delete; + PlayerbotDungeonRepository& operator=(PlayerbotDungeonRepository&&) = delete; + std::vector m_dungeonSuggestions; }; -#define sPlayerbotDungeonRepository PlayerbotDungeonRepository::instance() - #endif diff --git a/src/Db/PlayerbotRepository.h b/src/Db/PlayerbotRepository.h index 90dbce54af..b7b9b4b3cc 100644 --- a/src/Db/PlayerbotRepository.h +++ b/src/Db/PlayerbotRepository.h @@ -6,21 +6,20 @@ #ifndef _PLAYERBOT_PLAYERBOTREPOSITORY_H #define _PLAYERBOT_PLAYERBOTREPOSITORY_H +#include +#include #include -#include "Common.h" - -class PlayerbotAI; +#include "PlayerbotAI.h" class PlayerbotRepository { public: - PlayerbotRepository() {} - virtual ~PlayerbotRepository() {} - static PlayerbotRepository* instance() + static PlayerbotRepository& instance() { static PlayerbotRepository instance; - return &instance; + + return instance; } void Save(PlayerbotAI* botAI); @@ -28,10 +27,17 @@ class PlayerbotRepository void Reset(PlayerbotAI* botAI); private: - void SaveValue(uint32 guid, std::string const key, std::string const value); + PlayerbotRepository() = default; + ~PlayerbotRepository() = default; + + PlayerbotRepository(const PlayerbotRepository&) = delete; + PlayerbotRepository& operator=(const PlayerbotRepository&) = delete; + + PlayerbotRepository(PlayerbotRepository&&) = delete; + PlayerbotRepository& operator=(PlayerbotRepository&&) = delete; + + void SaveValue(uint32_t guid, std::string const key, std::string const value); std::string const FormatStrategies(std::string const type, std::vector strategies); }; -#define sPlayerbotRepository PlayerbotRepository::instance() - #endif diff --git a/src/Db/PlayerbotSpellRepository.cpp b/src/Db/PlayerbotSpellRepository.cpp index 6642eeeea2..d745ba3074 100644 --- a/src/Db/PlayerbotSpellRepository.cpp +++ b/src/Db/PlayerbotSpellRepository.cpp @@ -1,3 +1,10 @@ +#include "Log.h" +#include "DBCStores.h" +#include "DatabaseEnv.h" +#include "Field.h" +// Required due to poor implementation on AC side +#include "QueryResult.h" + #include "PlayerbotSpellRepository.h" // caches the result set diff --git a/src/Db/PlayerbotSpellRepository.h b/src/Db/PlayerbotSpellRepository.h index 55046e5956..7b026dd296 100644 --- a/src/Db/PlayerbotSpellRepository.h +++ b/src/Db/PlayerbotSpellRepository.h @@ -6,29 +6,37 @@ #ifndef _PLAYERBOT_PLAYERBOTSPELLREPOSITORY_H #define _PLAYERBOT_PLAYERBOTSPELLREPOSITORY_H -#include "Playerbots.h" +#include + +#include "DBCStructure.h" class PlayerbotSpellRepository { public: - static PlayerbotSpellRepository* Instance() + static PlayerbotSpellRepository& Instance() { static PlayerbotSpellRepository instance; - return &instance; + + return instance; } - void Initialize(); // call once on startup + void Initialize(); - SkillLineAbilityEntry const* GetSkillLine(uint32 spellId) const; - bool IsItemBuyable(uint32 itemId) const; + SkillLineAbilityEntry const* GetSkillLine(uint32_t spellId) const; + bool IsItemBuyable(uint32_t itemId) const; private: PlayerbotSpellRepository() = default; + ~PlayerbotSpellRepository() = default; - std::map skillSpells; - std::set vendorItems; -}; + PlayerbotSpellRepository(const PlayerbotSpellRepository&) = delete; + PlayerbotSpellRepository& operator=(const PlayerbotSpellRepository&) = delete; -#define sPlayerbotSpellRepository PlayerbotSpellRepository::Instance() + PlayerbotSpellRepository(PlayerbotSpellRepository&&) = delete; + PlayerbotSpellRepository& operator=(PlayerbotSpellRepository&&) = delete; + + std::map skillSpells; + std::set vendorItems; +}; #endif diff --git a/src/Mgr/Guild/GuildTaskMgr.cpp b/src/Mgr/Guild/GuildTaskMgr.cpp index 8fb4711dd7..96162c044a 100644 --- a/src/Mgr/Guild/GuildTaskMgr.cpp +++ b/src/Mgr/Guild/GuildTaskMgr.cpp @@ -26,14 +26,14 @@ enum GuildTaskType void GuildTaskMgr::Update(Player* player, Player* guildMaster) { - if (!sPlayerbotAIConfig->guildTaskEnabled) + if (!sPlayerbotAIConfig.guildTaskEnabled) return; if (!GetTaskValue(0, 0, "advert_cleanup")) { CleanupAdverts(); RemoveDuplicatedAdverts(); - SetTaskValue(0, 0, "advert_cleanup", 1, sPlayerbotAIConfig->guildTaskAdvertCleanupTime); + SetTaskValue(0, 0, "advert_cleanup", 1, sPlayerbotAIConfig.guildTaskAdvertCleanupTime); } PlayerbotAI* masterBotAI = GET_PLAYERBOT_AI(guildMaster); @@ -69,8 +69,8 @@ void GuildTaskMgr::Update(Player* player, Player* guildMaster) SetTaskValue(owner, guildId, "killTask", 0, 0); SetTaskValue(owner, guildId, "killCount", 0, 0); SetTaskValue(owner, guildId, "payment", 0, 0); - SetTaskValue(owner, guildId, "thanks", 1, 2 * sPlayerbotAIConfig->maxGuildTaskChangeTime); - SetTaskValue(owner, guildId, "reward", 1, 2 * sPlayerbotAIConfig->maxGuildTaskChangeTime); + SetTaskValue(owner, guildId, "thanks", 1, 2 * sPlayerbotAIConfig.maxGuildTaskChangeTime); + SetTaskValue(owner, guildId, "reward", 1, 2 * sPlayerbotAIConfig.maxGuildTaskChangeTime); uint32 task = CreateTask(player, guildId); @@ -80,11 +80,11 @@ void GuildTaskMgr::Update(Player* player, Player* guildMaster) player->GetName().c_str()); } - uint32 time = urand(sPlayerbotAIConfig->minGuildTaskChangeTime, sPlayerbotAIConfig->maxGuildTaskChangeTime); + uint32 time = urand(sPlayerbotAIConfig.minGuildTaskChangeTime, sPlayerbotAIConfig.maxGuildTaskChangeTime); SetTaskValue(owner, guildId, "activeTask", task, time); SetTaskValue(owner, guildId, "advertisement", 1, - urand(sPlayerbotAIConfig->minGuildTaskAdvertisementTime, - sPlayerbotAIConfig->maxGuildTaskAdvertisementTime)); + urand(sPlayerbotAIConfig.minGuildTaskAdvertisementTime, + sPlayerbotAIConfig.maxGuildTaskAdvertisementTime)); LOG_DEBUG("playerbots", "{} / {}: guild task {} is set for {} secs", guild->GetName().c_str(), player->GetName().c_str(), task, time); @@ -101,8 +101,8 @@ void GuildTaskMgr::Update(Player* player, Player* guildMaster) if (SendAdvertisement(trans, owner, guildId)) { SetTaskValue(owner, guildId, "advertisement", 1, - urand(sPlayerbotAIConfig->minGuildTaskAdvertisementTime, - sPlayerbotAIConfig->maxGuildTaskAdvertisementTime)); + urand(sPlayerbotAIConfig.minGuildTaskAdvertisementTime, + sPlayerbotAIConfig.maxGuildTaskAdvertisementTime)); } else { @@ -118,7 +118,7 @@ void GuildTaskMgr::Update(Player* player, Player* guildMaster) if (SendThanks(trans, owner, guildId, GetTaskValue(owner, guildId, "payment"))) { - SetTaskValue(owner, guildId, "thanks", 1, 2 * sPlayerbotAIConfig->maxGuildTaskChangeTime); + SetTaskValue(owner, guildId, "thanks", 1, 2 * sPlayerbotAIConfig.maxGuildTaskChangeTime); SetTaskValue(owner, guildId, "payment", 0, 0); } else @@ -135,7 +135,7 @@ void GuildTaskMgr::Update(Player* player, Player* guildMaster) if (Reward(trans, owner, guildId)) { - SetTaskValue(owner, guildId, "reward", 1, 2 * sPlayerbotAIConfig->maxGuildTaskChangeTime); + SetTaskValue(owner, guildId, "reward", 1, 2 * sPlayerbotAIConfig.maxGuildTaskChangeTime); SetTaskValue(owner, guildId, "payment", 0, 0); } else @@ -190,7 +190,7 @@ bool GuildTaskMgr::CreateItemTask(Player* player, uint32 guildId) return false; RandomItemBySkillGuildTaskPredicate predicate(player); - uint32 itemId = sRandomItemMgr->GetRandomItem(player->GetLevel() - 5, RANDOM_ITEM_GUILD_TASK, &predicate); + uint32 itemId = sRandomItemMgr.GetRandomItem(player->GetLevel() - 5, RANDOM_ITEM_GUILD_TASK, &predicate); if (!itemId) { LOG_ERROR("playerbots", "{} / {}: no items avaible for item task", @@ -204,9 +204,9 @@ bool GuildTaskMgr::CreateItemTask(Player* player, uint32 guildId) player->GetName().c_str(), itemId, count); SetTaskValue(player->GetGUID().GetCounter(), guildId, "itemCount", count, - sPlayerbotAIConfig->maxGuildTaskChangeTime); + sPlayerbotAIConfig.maxGuildTaskChangeTime); SetTaskValue(player->GetGUID().GetCounter(), guildId, "itemTask", itemId, - sPlayerbotAIConfig->maxGuildTaskChangeTime); + sPlayerbotAIConfig.maxGuildTaskChangeTime); return true; } @@ -239,8 +239,8 @@ bool GuildTaskMgr::CreateKillTask(Player* player, uint32 guildId) if (strstr(name.c_str(), "UNUSED")) continue; - float dist = sServerFacade->GetDistance2d(player, x, y); - if (dist > sPlayerbotAIConfig->guildTaskKillTaskDistance || player->GetMapId() != map) + float dist = ServerFacade::instance().GetDistance2d(player, x, y); + if (dist > sPlayerbotAIConfig.guildTaskKillTaskDistance || player->GetMapId() != map) continue; if (find(ids.begin(), ids.end(), id) == ids.end()) @@ -262,7 +262,7 @@ bool GuildTaskMgr::CreateKillTask(Player* player, uint32 guildId) player->GetName().c_str(), creatureId); SetTaskValue(player->GetGUID().GetCounter(), guildId, "killTask", creatureId, - sPlayerbotAIConfig->maxGuildTaskChangeTime); + sPlayerbotAIConfig.maxGuildTaskChangeTime); return true; } @@ -525,7 +525,7 @@ uint32 GuildTaskMgr::GetMaxItemTaskCount(uint32 itemId) bool GuildTaskMgr::IsGuildTaskItem(uint32 itemId, uint32 guildId) { - if (!sPlayerbotAIConfig->guildTaskEnabled) + if (!sPlayerbotAIConfig.guildTaskEnabled) { return 0; } @@ -553,7 +553,7 @@ bool GuildTaskMgr::IsGuildTaskItem(uint32 itemId, uint32 guildId) std::map GuildTaskMgr::GetTaskValues(uint32 owner, std::string const type, [[maybe_unused]] uint32* validIn /* = nullptr */) { - if (!sPlayerbotAIConfig->guildTaskEnabled) + if (!sPlayerbotAIConfig.guildTaskEnabled) { return std::map(); } @@ -586,7 +586,7 @@ std::map GuildTaskMgr::GetTaskValues(uint32 owner, std::string c uint32 GuildTaskMgr::GetTaskValue(uint32 owner, uint32 guildId, std::string const type, [[maybe_unused]] uint32* validIn /* = nullptr */) { - if (!sPlayerbotAIConfig->guildTaskEnabled) + if (!sPlayerbotAIConfig.guildTaskEnabled) { return 0; } @@ -639,7 +639,7 @@ uint32 GuildTaskMgr::SetTaskValue(uint32 owner, uint32 guildId, std::string cons bool GuildTaskMgr::HandleConsoleCommand(ChatHandler* /* handler */, char const* args) { - if (!sPlayerbotAIConfig->guildTaskEnabled) + if (!sPlayerbotAIConfig.guildTaskEnabled) { LOG_ERROR("playerbots", "Guild task system is currently disabled!"); return false; @@ -703,8 +703,8 @@ bool GuildTaskMgr::HandleConsoleCommand(ChatHandler* /* handler */, char const* if (value == GUILD_TASK_TYPE_ITEM) { name << "ItemTask"; - uint32 itemId = sGuildTaskMgr->GetTaskValue(owner, guildId, "itemTask"); - uint32 itemCount = sGuildTaskMgr->GetTaskValue(owner, guildId, "itemCount"); + uint32 itemId = GuildTaskMgr::instance().GetTaskValue(owner, guildId, "itemTask"); + uint32 itemCount = GuildTaskMgr::instance().GetTaskValue(owner, guildId, "itemCount"); if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId)) { @@ -735,7 +735,7 @@ bool GuildTaskMgr::HandleConsoleCommand(ChatHandler* /* handler */, char const* else if (value == GUILD_TASK_TYPE_KILL) { name << "KillTask"; - uint32 creatureId = sGuildTaskMgr->GetTaskValue(owner, guildId, "killTask"); + uint32 creatureId = GuildTaskMgr::instance().GetTaskValue(owner, guildId, "killTask"); if (CreatureTemplate const* proto = sObjectMgr->GetCreatureTemplate(creatureId)) { @@ -758,22 +758,22 @@ bool GuildTaskMgr::HandleConsoleCommand(ChatHandler* /* handler */, char const* continue; uint32 advertValidIn = 0; - uint32 advert = sGuildTaskMgr->GetTaskValue(owner, guildId, "advertisement", &advertValidIn); + uint32 advert = GuildTaskMgr::instance().GetTaskValue(owner, guildId, "advertisement", &advertValidIn); if (advert && advertValidIn < validIn) name << " advert in " << formatTime(advertValidIn); uint32 thanksValidIn = 0; - uint32 thanks = sGuildTaskMgr->GetTaskValue(owner, guildId, "thanks", &thanksValidIn); + uint32 thanks = GuildTaskMgr::instance().GetTaskValue(owner, guildId, "thanks", &thanksValidIn); if (thanks && thanksValidIn < validIn) name << " thanks in " << formatTime(thanksValidIn); uint32 rewardValidIn = 0; - uint32 reward = sGuildTaskMgr->GetTaskValue(owner, guildId, "reward", &rewardValidIn); + uint32 reward = GuildTaskMgr::instance().GetTaskValue(owner, guildId, "reward", &rewardValidIn); if (reward && rewardValidIn < validIn) name << " reward in " << formatTime(rewardValidIn); uint32 paymentValidIn = 0; - uint32 payment = sGuildTaskMgr->GetTaskValue(owner, guildId, "payment", &paymentValidIn); + uint32 payment = GuildTaskMgr::instance().GetTaskValue(owner, guildId, "payment", &paymentValidIn); if (payment && paymentValidIn < validIn) name << " payment " << ChatHelper::formatMoney(payment) << " in " << formatTime(paymentValidIn); @@ -788,8 +788,8 @@ bool GuildTaskMgr::HandleConsoleCommand(ChatHandler* /* handler */, char const* if (cmd == "cleanup") { - sGuildTaskMgr->CleanupAdverts(); - sGuildTaskMgr->RemoveDuplicatedAdverts(); + GuildTaskMgr::instance().CleanupAdverts(); + GuildTaskMgr::instance().RemoveDuplicatedAdverts(); return true; } @@ -840,10 +840,10 @@ bool GuildTaskMgr::HandleConsoleCommand(ChatHandler* /* handler */, char const* continue; if (reward) - sGuildTaskMgr->Reward(trans, owner, guildId); + GuildTaskMgr::instance().Reward(trans, owner, guildId); if (advert) - sGuildTaskMgr->SendAdvertisement(trans, owner, guildId); + GuildTaskMgr::instance().SendAdvertisement(trans, owner, guildId); } while (result->NextRow()); CharacterDatabase.CommitTransaction(trans); @@ -868,7 +868,7 @@ bool GuildTaskMgr::CheckItemTask(uint32 itemId, uint32 obtained, Player* ownerPl if (!guild) return false; - if (!sRandomPlayerbotMgr->IsRandomBot(bot)) + if (!sRandomPlayerbotMgr.IsRandomBot(bot)) return false; LOG_DEBUG("playerbots", "{} / {}: checking guild task", guild->GetName().c_str(), ownerPlayer->GetName().c_str()); @@ -891,7 +891,7 @@ bool GuildTaskMgr::CheckItemTask(uint32 itemId, uint32 obtained, Player* ownerPl return false; } - uint32 rewardTime = urand(sPlayerbotAIConfig->minGuildTaskRewardTime, sPlayerbotAIConfig->maxGuildTaskRewardTime); + uint32 rewardTime = urand(sPlayerbotAIConfig.minGuildTaskRewardTime, sPlayerbotAIConfig.maxGuildTaskRewardTime); if (byMail) { ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId); @@ -915,7 +915,7 @@ bool GuildTaskMgr::CheckItemTask(uint32 itemId, uint32 obtained, Player* ownerPl { LOG_DEBUG("playerbots", "{} / {}: guild task progress {}/{}", guild->GetName().c_str(), ownerPlayer->GetName().c_str(), obtained, count); - SetTaskValue(owner, guildId, "itemCount", count - obtained, sPlayerbotAIConfig->maxGuildTaskChangeTime); + SetTaskValue(owner, guildId, "itemCount", count - obtained, sPlayerbotAIConfig.maxGuildTaskChangeTime); SetTaskValue(owner, guildId, "thanks", 1, rewardTime - 30); SendCompletionMessage(ownerPlayer, "made a progress with"); } @@ -961,7 +961,7 @@ bool GuildTaskMgr::Reward(CharacterDatabaseTransaction& trans, uint32 owner, uin body << leader->GetName() << "\n"; rewardType = proto->Quality > ITEM_QUALITY_NORMAL ? RANDOM_ITEM_GUILD_TASK_REWARD_EQUIP_BLUE : RANDOM_ITEM_GUILD_TASK_REWARD_EQUIP_GREEN; - itemId = sRandomItemMgr->GetRandomItem(player->GetLevel() - 5, rewardType); + itemId = sRandomItemMgr.GetRandomItem(player->GetLevel() - 5, rewardType); } else if (killTask) { @@ -977,7 +977,7 @@ bool GuildTaskMgr::Reward(CharacterDatabaseTransaction& trans, uint32 owner, uin body << leader->GetName() << "\n"; rewardType = proto->rank == CREATURE_ELITE_RARE ? RANDOM_ITEM_GUILD_TASK_REWARD_TRADE : RANDOM_ITEM_GUILD_TASK_REWARD_TRADE_RARE; - itemId = sRandomItemMgr->GetRandomItem(player->GetLevel(), rewardType); + itemId = sRandomItemMgr.GetRandomItem(player->GetLevel(), rewardType); if (itemId) { ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(itemId); @@ -1086,7 +1086,7 @@ void GuildTaskMgr::CheckKillTaskInternal(Player* player, Unit* victim) LOG_DEBUG("playerbots", "{} / {}: guild task complete", guild->GetName().c_str(), player->GetName().c_str()); SetTaskValue(owner, guildId, "reward", 1, - urand(sPlayerbotAIConfig->minGuildTaskRewardTime, sPlayerbotAIConfig->maxGuildTaskRewardTime)); + urand(sPlayerbotAIConfig.minGuildTaskRewardTime, sPlayerbotAIConfig.maxGuildTaskRewardTime)); SendCompletionMessage(player, "completed"); } @@ -1094,7 +1094,7 @@ void GuildTaskMgr::CheckKillTaskInternal(Player* player, Unit* victim) void GuildTaskMgr::CleanupAdverts() { - uint32 deliverTime = time(nullptr) - sPlayerbotAIConfig->minGuildTaskChangeTime; + uint32 deliverTime = time(nullptr) - sPlayerbotAIConfig.minGuildTaskChangeTime; QueryResult result = CharacterDatabase.Query( "SELECT id, receiver FROM mail WHERE subject LIKE 'Guild Task%%' AND deliver_time <= {}", deliverTime); if (!result) @@ -1200,7 +1200,7 @@ bool GuildTaskMgr::CheckTaskTransfer(std::string const text, Player* ownerPlayer if (!guild) return false; - if (!sRandomPlayerbotMgr->IsRandomBot(bot)) + if (!sRandomPlayerbotMgr.IsRandomBot(bot)) return false; if (text.empty()) diff --git a/src/Mgr/Guild/GuildTaskMgr.h b/src/Mgr/Guild/GuildTaskMgr.h index c050281ca6..6251f2c1e2 100644 --- a/src/Mgr/Guild/GuildTaskMgr.h +++ b/src/Mgr/Guild/GuildTaskMgr.h @@ -7,56 +7,61 @@ #define _PLAYERBOT_GUILDTASKMGR_H #include +#include +#include -#include "Common.h" -#include "Transaction.h" - -class ChatHandler; -class Player; -class Unit; +#include "DatabaseEnvFwd.h" +#include "Unit.h" +#include "Player.h" +#include "Chat.h" class GuildTaskMgr { public: - GuildTaskMgr(){}; - virtual ~GuildTaskMgr(){}; - - static GuildTaskMgr* instance() + static GuildTaskMgr& instance() { static GuildTaskMgr instance; - return &instance; + + return instance; } void Update(Player* owner, Player* guildMaster); static bool HandleConsoleCommand(ChatHandler* handler, char const* args); - bool IsGuildTaskItem(uint32 itemId, uint32 guildId); - bool CheckItemTask(uint32 itemId, uint32 obtained, Player* owner, Player* bot, bool byMail = false); + bool IsGuildTaskItem(uint32_t itemId, uint32_t guildId); + bool CheckItemTask(uint32_t itemId, uint32_t obtained, Player* owner, Player* bot, bool byMail = false); void CheckKillTask(Player* owner, Unit* victim); void CheckKillTaskInternal(Player* owner, Unit* victim); bool CheckTaskTransfer(std::string const text, Player* owner, Player* bot); private: - std::map GetTaskValues(uint32 owner, std::string const type, uint32* validIn = nullptr); - uint32 GetTaskValue(uint32 owner, uint32 guildId, std::string const type, uint32* validIn = nullptr); - uint32 SetTaskValue(uint32 owner, uint32 guildId, std::string const type, uint32 value, uint32 validIn); - uint32 CreateTask(Player* owner, uint32 guildId); - bool SendAdvertisement(CharacterDatabaseTransaction& trans, uint32 owner, uint32 guildId); - bool SendItemAdvertisement(CharacterDatabaseTransaction& trans, uint32 itemId, uint32 owner, uint32 guildId, - uint32 validIn); - bool SendKillAdvertisement(CharacterDatabaseTransaction& trans, uint32 creatureId, uint32 owner, uint32 guildId, - uint32 validIn); - bool SendThanks(CharacterDatabaseTransaction& trans, uint32 owner, uint32 guildId, uint32 payment); - bool Reward(CharacterDatabaseTransaction& trans, uint32 owner, uint32 guildId); - bool CreateItemTask(Player* owner, uint32 guildId); - bool CreateKillTask(Player* owner, uint32 guildId); - uint32 GetMaxItemTaskCount(uint32 itemId); + GuildTaskMgr() = default; + ~GuildTaskMgr() = default; + + GuildTaskMgr(const GuildTaskMgr&) = delete; + GuildTaskMgr& operator=(const GuildTaskMgr&) = delete; + + GuildTaskMgr(GuildTaskMgr&&) = delete; + GuildTaskMgr& operator=(GuildTaskMgr&&) = delete; + + std::map GetTaskValues(uint32_t owner, std::string const type, uint32_t* validIn = nullptr); + uint32_t GetTaskValue(uint32_t owner, uint32_t guildId, std::string const type, uint32_t* validIn = nullptr); + uint32_t SetTaskValue(uint32_t owner, uint32_t guildId, std::string const type, uint32_t value, uint32_t validIn); + uint32_t CreateTask(Player* owner, uint32_t guildId); + bool SendAdvertisement(CharacterDatabaseTransaction& trans, uint32_t owner, uint32_t guildId); + bool SendItemAdvertisement(CharacterDatabaseTransaction& trans, uint32_t itemId, uint32_t owner, uint32_t guildId, + uint32_t validIn); + bool SendKillAdvertisement(CharacterDatabaseTransaction& trans, uint32_t creatureId, uint32_t owner, uint32_t guildId, + uint32_t validIn); + bool SendThanks(CharacterDatabaseTransaction& trans, uint32_t owner, uint32_t guildId, uint32_t payment); + bool Reward(CharacterDatabaseTransaction& trans, uint32_t owner, uint32_t guildId); + bool CreateItemTask(Player* owner, uint32_t guildId); + bool CreateKillTask(Player* owner, uint32_t guildId); + uint32_t GetMaxItemTaskCount(uint32_t itemId); void CleanupAdverts(); void RemoveDuplicatedAdverts(); - void DeleteMail(std::vector buffer); + void DeleteMail(std::vector buffer); void SendCompletionMessage(Player* player, std::string const verb); }; -#define sGuildTaskMgr GuildTaskMgr::instance() - #endif diff --git a/src/Mgr/Guild/PlayerbotGuildMgr.cpp b/src/Mgr/Guild/PlayerbotGuildMgr.cpp index c1f7aa5b2d..001a438cbb 100644 --- a/src/Mgr/Guild/PlayerbotGuildMgr.cpp +++ b/src/Mgr/Guild/PlayerbotGuildMgr.cpp @@ -4,15 +4,12 @@ #include "DatabaseEnv.h" #include "Guild.h" #include "GuildMgr.h" -#include "RandomPlayerbotMgr.h" #include "ScriptMgr.h" -PlayerbotGuildMgr::PlayerbotGuildMgr(){} - void PlayerbotGuildMgr::Init() { _guildCache.clear(); - if (sPlayerbotAIConfig->deleteRandomBotGuilds) + if (sPlayerbotAIConfig.deleteRandomBotGuilds) DeleteBotGuilds(); LoadGuildNames(); @@ -38,7 +35,7 @@ bool PlayerbotGuildMgr::CreateGuild(Player* player, std::string guildName) entry.name = guildName; entry.memberCount = 1; entry.status = 1; - entry.maxMembers = sPlayerbotAIConfig->randomBotGuildSizeMax; + entry.maxMembers = sPlayerbotAIConfig.randomBotGuildSizeMax; entry.faction = player->GetTeamId(); _guildCache[guild->GetId()] = entry; @@ -113,7 +110,7 @@ std::string PlayerbotGuildMgr::AssignToGuild(Player* player) } ); - if (count < sPlayerbotAIConfig->randomBotGuildCount) + if (count < sPlayerbotAIConfig.randomBotGuildCount) { for (auto& key : _shuffled_guild_keys) { @@ -214,7 +211,7 @@ void PlayerbotGuildMgr::ValidateGuildCache() uint32 guildId = it->first; GuildCache cache; cache.name = it->second; - cache.maxMembers = sPlayerbotAIConfig->randomBotGuildSizeMax; + cache.maxMembers = sPlayerbotAIConfig.randomBotGuildSizeMax; Guild* guild = sGuildMgr ->GetGuildById(guildId); if (!guild) @@ -224,7 +221,7 @@ void PlayerbotGuildMgr::ValidateGuildCache() ObjectGuid leaderGuid = guild->GetLeaderGUID(); CharacterCacheEntry const* leaderEntry = sCharacterCache->GetCharacterCacheByGuid(leaderGuid); uint32 leaderAccount = leaderEntry->AccountId; - cache.hasRealPlayer = !(sPlayerbotAIConfig->IsInRandomAccountList(leaderAccount)); + cache.hasRealPlayer = !(sPlayerbotAIConfig.IsInRandomAccountList(leaderAccount)); cache.faction = Player::TeamIdForRace(leaderEntry->Race); if (cache.memberCount == 0) cache.status = 0; // empty @@ -306,7 +303,7 @@ class BotGuildCacheWorldScript : public WorldScript if (_validateTimer >= _validateInterval) // Validate every hour { _validateTimer = 0; - sPlayerbotGuildMgr->ValidateGuildCache(); + PlayerbotGuildMgr::instance().ValidateGuildCache(); LOG_INFO("playerbots", "Scheduled guild cache validation"); } } @@ -319,4 +316,4 @@ class BotGuildCacheWorldScript : public WorldScript void PlayerBotsGuildValidationScript() { new BotGuildCacheWorldScript(); -} \ No newline at end of file +} diff --git a/src/Mgr/Guild/PlayerbotGuildMgr.h b/src/Mgr/Guild/PlayerbotGuildMgr.h index 0df0df7371..5d85ce9e79 100644 --- a/src/Mgr/Guild/PlayerbotGuildMgr.h +++ b/src/Mgr/Guild/PlayerbotGuildMgr.h @@ -5,15 +5,14 @@ #include "Player.h" #include "PlayerbotAI.h" -class PlayerbotAI; - class PlayerbotGuildMgr { public: - static PlayerbotGuildMgr* instance() + static PlayerbotGuildMgr& instance() { static PlayerbotGuildMgr instance; - return &instance; + + return instance; } void Init(); @@ -29,7 +28,15 @@ class PlayerbotGuildMgr bool IsRealGuild(Player* bot); private: - PlayerbotGuildMgr(); + PlayerbotGuildMgr() = default; + ~PlayerbotGuildMgr() = default; + + PlayerbotGuildMgr(const PlayerbotGuildMgr&) = delete; + PlayerbotGuildMgr& operator=(const PlayerbotGuildMgr&) = delete; + + PlayerbotGuildMgr(PlayerbotGuildMgr&&) = delete; + PlayerbotGuildMgr& operator=(PlayerbotGuildMgr&&) = delete; + std::unordered_map _guildNames; struct GuildCache @@ -47,6 +54,4 @@ class PlayerbotGuildMgr void PlayerBotsGuildValidationScript(); -#define sPlayerbotGuildMgr PlayerbotGuildMgr::instance() - -#endif \ No newline at end of file +#endif diff --git a/src/Mgr/Item/ItemVisitors.cpp b/src/Mgr/Item/ItemVisitors.cpp index 5615146f63..5ed8d1b04a 100644 --- a/src/Mgr/Item/ItemVisitors.cpp +++ b/src/Mgr/Item/ItemVisitors.cpp @@ -92,4 +92,4 @@ bool FindItemUsageVisitor::Accept(ItemTemplate const* proto) bool FindUsableNamedItemVisitor::Accept(ItemTemplate const* proto) { return proto && !proto->Name1.empty() && strstri(proto->Name1.c_str(), name.c_str()); -} \ No newline at end of file +} diff --git a/src/Mgr/Item/RandomItemMgr.cpp b/src/Mgr/Item/RandomItemMgr.cpp index 87b8379355..5c0e8c94ab 100644 --- a/src/Mgr/Item/RandomItemMgr.cpp +++ b/src/Mgr/Item/RandomItemMgr.cpp @@ -272,7 +272,7 @@ void RandomItemMgr::BuildRandomItemCache() } } - uint32 maxLevel = sPlayerbotAIConfig->randomBotMaxLevel; + uint32 maxLevel = sPlayerbotAIConfig.randomBotMaxLevel; if (maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); @@ -2092,7 +2092,7 @@ uint32 RandomItemMgr::GetLiveStatWeight(Player* player, uint32 itemId) void RandomItemMgr::BuildEquipCache() { - uint32 maxLevel = sPlayerbotAIConfig->randomBotMaxLevel; + uint32 maxLevel = sPlayerbotAIConfig.randomBotMaxLevel; if (maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); @@ -2415,7 +2415,7 @@ void RandomItemMgr::BuildPotionCache() void RandomItemMgr::BuildFoodCache() { - uint32 maxLevel = sPlayerbotAIConfig->randomBotMaxLevel; + uint32 maxLevel = sPlayerbotAIConfig.randomBotMaxLevel; if (maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); @@ -2548,7 +2548,7 @@ uint32 RandomItemMgr::GetRandomFood(uint32 level, uint32 category) void RandomItemMgr::BuildTradeCache() { - uint32 maxLevel = sPlayerbotAIConfig->randomBotMaxLevel; + uint32 maxLevel = sPlayerbotAIConfig.randomBotMaxLevel; if (maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); diff --git a/src/Mgr/Item/RandomItemMgr.h b/src/Mgr/Item/RandomItemMgr.h index 216ddf9bfc..54e2e63516 100644 --- a/src/Mgr/Item/RandomItemMgr.h +++ b/src/Mgr/Item/RandomItemMgr.h @@ -12,7 +12,6 @@ #include #include "AiFactory.h" -#include "Common.h" #include "ItemTemplate.h" class ChatHandler; @@ -135,12 +134,11 @@ typedef std::map BotEquipCache; class RandomItemMgr { public: - RandomItemMgr(); - virtual ~RandomItemMgr(); - static RandomItemMgr* instance() + static RandomItemMgr& instance() { static RandomItemMgr instance; - return &instance; + + return instance; } public: @@ -191,6 +189,17 @@ class RandomItemMgr bool CheckItemStats(uint8 clazz, uint8 sp, uint8 ap, uint8 tank); private: + // Implemented in RandomItemMgr.cpp + RandomItemMgr(); + // Implemented in RandomItemMgr.cpp + ~RandomItemMgr(); + + RandomItemMgr(const RandomItemMgr&) = delete; + RandomItemMgr& operator=(const RandomItemMgr&) = delete; + + RandomItemMgr(RandomItemMgr&&) = delete; + RandomItemMgr& operator=(RandomItemMgr&&) = delete; + std::map randomItemCache; std::map predicates; BotEquipCache equipCache; diff --git a/src/Mgr/Item/StatsCollector.h b/src/Mgr/Item/StatsCollector.h index 27ef871ec5..1e54546f5d 100644 --- a/src/Mgr/Item/StatsCollector.h +++ b/src/Mgr/Item/StatsCollector.h @@ -87,4 +87,4 @@ class StatsCollector uint32 cls_; }; -#endif \ No newline at end of file +#endif diff --git a/src/Mgr/Move/FleeManager.cpp b/src/Mgr/Move/FleeManager.cpp index 34e17fe391..d3d1a8bb02 100644 --- a/src/Mgr/Move/FleeManager.cpp +++ b/src/Mgr/Move/FleeManager.cpp @@ -34,7 +34,7 @@ void FleeManager::calculateDistanceToCreatures(FleePoint* point) if (!unit) continue; - float d = sServerFacade->GetDistance2d(unit, point->x, point->y); + float d = ServerFacade::instance().GetDistance2d(unit, point->x, point->y); point->sumDistance += d; if (point->minDistance < 0 || point->minDistance > d) point->minDistance = d; @@ -81,11 +81,11 @@ void FleeManager::calculatePossibleDestinations(std::vector& points) enemyOri.push_back(ori); } - float distIncrement = std::max(sPlayerbotAIConfig->followDistance, - (maxAllowedDistance - sPlayerbotAIConfig->tooCloseDistance) / 10.0f); - for (float dist = maxAllowedDistance; dist >= sPlayerbotAIConfig->tooCloseDistance; dist -= distIncrement) + float distIncrement = std::max(sPlayerbotAIConfig.followDistance, + (maxAllowedDistance - sPlayerbotAIConfig.tooCloseDistance) / 10.0f); + for (float dist = maxAllowedDistance; dist >= sPlayerbotAIConfig.tooCloseDistance; dist -= distIncrement) { - float angleIncrement = std::max(M_PI / 20, M_PI / 4 / (1.0 + dist - sPlayerbotAIConfig->tooCloseDistance)); + float angleIncrement = std::max(M_PI / 20, M_PI / 4 / (1.0 + dist - sPlayerbotAIConfig.tooCloseDistance)); for (float add = 0.0f; add < M_PI / 4 + angleIncrement; add += angleIncrement) { for (float angle = add; angle < add + 2 * static_cast(M_PI) + angleIncrement; @@ -97,8 +97,8 @@ void FleeManager::calculatePossibleDestinations(std::vector& points) float x = botPosX + cos(angle) * maxAllowedDistance, y = botPosY + sin(angle) * maxAllowedDistance, z = botPosZ + CONTACT_DISTANCE; if (forceMaxDistance && - sServerFacade->IsDistanceLessThan(sServerFacade->GetDistance2d(bot, x, y), - maxAllowedDistance - sPlayerbotAIConfig->tooCloseDistance)) + ServerFacade::instance().IsDistanceLessThan(ServerFacade::instance().GetDistance2d(bot, x, y), + maxAllowedDistance - sPlayerbotAIConfig.tooCloseDistance)) continue; bot->UpdateAllowedPositionZ(x, y, z); @@ -113,8 +113,8 @@ void FleeManager::calculatePossibleDestinations(std::vector& points) FleePoint* point = new FleePoint(botAI, x, y, z); calculateDistanceToCreatures(point); - if (sServerFacade->IsDistanceGreaterOrEqualThan(point->minDistance - start.minDistance, - sPlayerbotAIConfig->followDistance)) + if (ServerFacade::instance().IsDistanceGreaterOrEqualThan(point->minDistance - start.minDistance, + sPlayerbotAIConfig.followDistance)) points.push_back(point); else delete point; @@ -189,8 +189,8 @@ bool FleeManager::isUseful() creature->GetAttackDistance(bot) * creature->GetAttackDistance(bot)) return true; - // float d = sServerFacade->GetDistance2d(unit, bot); - // if (sServerFacade->IsDistanceLessThan(d, sPlayerbotAIConfig->aggroDistance)) return true; + // float d = ServerFacade::instance().GetDistance2d(unit, bot); + // if (ServerFacade::instance().IsDistanceLessThan(d, sPlayerbotAIConfig.aggroDistance)) return true; } return false; diff --git a/src/Mgr/Security/PlayerbotSecurity.cpp b/src/Mgr/Security/PlayerbotSecurity.cpp index 68bb2db29a..4a3bd36553 100644 --- a/src/Mgr/Security/PlayerbotSecurity.cpp +++ b/src/Mgr/Security/PlayerbotSecurity.cpp @@ -47,7 +47,7 @@ PlayerbotSecurityLevel PlayerbotSecurity::LevelFor(Player* from, DenyReason* rea return PLAYERBOT_SECURITY_DENY_ALL; } - if (sPlayerbotAIConfig->IsInRandomAccountList(account)) + if (sPlayerbotAIConfig.IsInRandomAccountList(account)) { // (duplicate check in case of faction change) if (botAI->IsOpposing(from)) @@ -72,7 +72,7 @@ PlayerbotSecurityLevel PlayerbotSecurity::LevelFor(Player* from, DenyReason* rea return PLAYERBOT_SECURITY_TALK; } - if (sPlayerbotAIConfig->groupInvitationPermission <= 0) + if (sPlayerbotAIConfig.groupInvitationPermission <= 0) { if (reason) *reason = PLAYERBOT_DENY_NONE; @@ -80,7 +80,7 @@ PlayerbotSecurityLevel PlayerbotSecurity::LevelFor(Player* from, DenyReason* rea return PLAYERBOT_SECURITY_TALK; } - if (sPlayerbotAIConfig->groupInvitationPermission <= 1) + if (sPlayerbotAIConfig.groupInvitationPermission <= 1) { int32 levelDiff = int32(bot->GetLevel()) - int32(from->GetLevel()); if (levelDiff > 5) @@ -98,7 +98,7 @@ PlayerbotSecurityLevel PlayerbotSecurity::LevelFor(Player* from, DenyReason* rea int32 botGS = static_cast(botAI->GetEquipGearScore(bot)); int32 fromGS = static_cast(botAI->GetEquipGearScore(from)); - if (sPlayerbotAIConfig->gearscorecheck && botGS && bot->GetLevel() > 15 && botGS > fromGS) + if (sPlayerbotAIConfig.gearscorecheck && botGS && bot->GetLevel() > 15 && botGS > fromGS) { uint32 diffPct = uint32(100 * (botGS - fromGS) / botGS); uint32 reqPct = uint32(12 * sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) / from->GetLevel()); @@ -277,7 +277,7 @@ bool PlayerbotSecurity::CheckLevelFor(PlayerbotSecurityLevel level, bool silent, ObjectGuid guid = from->GetGUID(); time_t lastSaid = whispers[guid][text]; - if (!lastSaid || (time(nullptr) - lastSaid) >= sPlayerbotAIConfig->repeatDelay / 1000) + if (!lastSaid || (time(nullptr) - lastSaid) >= sPlayerbotAIConfig.repeatDelay / 1000) { whispers[guid][text] = time(nullptr); diff --git a/src/Mgr/Text/PlayerbotTextMgr.cpp b/src/Mgr/Text/PlayerbotTextMgr.cpp index 1dce9a29a5..0998a5392f 100644 --- a/src/Mgr/Text/PlayerbotTextMgr.cpp +++ b/src/Mgr/Text/PlayerbotTextMgr.cpp @@ -2,12 +2,14 @@ * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license, you may redistribute it * and/or modify it under version 3 of the License, or (at your option), any later version. */ +#include "DatabaseEnv.h" +#include "WorldSessionMgr.h" +#include "Random.h" +// Required due to a poor implementation by AC +#include "QueryResult.h" #include "PlayerbotTextMgr.h" -#include "Playerbots.h" -#include "WorldSessionMgr.h" - void PlayerbotTextMgr::replaceAll(std::string& str, const std::string& from, const std::string& to) { if (from.empty()) diff --git a/src/Mgr/Text/PlayerbotTextMgr.h b/src/Mgr/Text/PlayerbotTextMgr.h index f4ec2c403c..398d7640ab 100644 --- a/src/Mgr/Text/PlayerbotTextMgr.h +++ b/src/Mgr/Text/PlayerbotTextMgr.h @@ -11,9 +11,6 @@ #include "Common.h" -#define BOT_TEXT1(name) sPlayerbotTextMgr->GetBotText(name) -#define BOT_TEXT2(name, replace) sPlayerbotTextMgr->GetBotText(name, replace) - struct BotTextEntry { BotTextEntry(std::string name, std::map text, uint32 say_type, uint32 reply_type) @@ -63,18 +60,11 @@ enum ChatReplyType class PlayerbotTextMgr { public: - PlayerbotTextMgr() - { - for (uint8 i = 0; i < MAX_LOCALES; ++i) - { - botTextLocalePriority[i] = 0; - } - }; - virtual ~PlayerbotTextMgr(){}; - static PlayerbotTextMgr* instance() + static PlayerbotTextMgr& instance() { static PlayerbotTextMgr instance; - return &instance; + + return instance; } std::string GetBotText(std::string name, std::map placeholders); @@ -95,11 +85,24 @@ class PlayerbotTextMgr void ResetLocalePriority(); private: + PlayerbotTextMgr() + { + for (uint8 i = 0; i < MAX_LOCALES; ++i) + { + botTextLocalePriority[i] = 0; + } + }; + ~PlayerbotTextMgr() = default; + + PlayerbotTextMgr(const PlayerbotTextMgr&) = delete; + PlayerbotTextMgr& operator=(const PlayerbotTextMgr&) = delete; + + PlayerbotTextMgr(PlayerbotTextMgr&&) = delete; + PlayerbotTextMgr& operator=(PlayerbotTextMgr&&) = delete; + std::map> botTexts; std::map botTextChance; uint32 botTextLocalePriority[MAX_LOCALES]; }; -#define sPlayerbotTextMgr PlayerbotTextMgr::instance() - #endif diff --git a/src/Mgr/Travel/TravelMgr.cpp b/src/Mgr/Travel/TravelMgr.cpp index ab70576502..84eef9b99e 100644 --- a/src/Mgr/Travel/TravelMgr.cpp +++ b/src/Mgr/Travel/TravelMgr.cpp @@ -8,17 +8,18 @@ #include #include -#include "CellImpl.h" +#include "Talentspec.h" #include "ChatHelper.h" #include "MMapFactory.h" #include "MapMgr.h" #include "PathGenerator.h" #include "Playerbots.h" -#include "StrategyContext.h" #include "TransportMgr.h" #include "VMapFactory.h" #include "VMapMgr2.h" +#include "Map.h" #include "Corpse.h" +#include "CellImpl.h" WorldPosition::WorldPosition(std::string const str) { @@ -246,7 +247,7 @@ float WorldPosition::distance(WorldPosition* center) return relPoint(center).size(); // this -> mapTransfer | mapTransfer -> center - return sTravelMgr->mapTransDistance(*this, *center); + return TravelMgr::instance().mapTransDistance(*this, *center); }; float WorldPosition::fDist(WorldPosition* center) @@ -255,7 +256,7 @@ float WorldPosition::fDist(WorldPosition* center) return sqrt(sqDistance2d(center)); // this -> mapTransfer | mapTransfer -> center - return sTravelMgr->fastMapTransDistance(*this, *center); + return TravelMgr::instance().fastMapTransDistance(*this, *center); }; float mapTransfer::fDist(WorldPosition start, WorldPosition end) @@ -428,7 +429,7 @@ void WorldPosition::printWKT(std::vector points, std::ostringstre WorldPosition WorldPosition::getDisplayLocation() { - WorldPosition pos = sTravelNodeMap->getMapOffset(getMapId()); + WorldPosition pos = TravelNodeMap::instance().getMapOffset(getMapId()); return offset(const_cast(&pos)); } @@ -630,14 +631,14 @@ void WorldPosition::loadMapAndVMap(uint32 mapId, uint8 x, uint8 y) if (isOverworld() && false || false) { if (!MMAP::MMapFactory::createOrGetMMapMgr()->loadMap(mapId, x, y)) - if (sPlayerbotAIConfig->hasLog(fileName)) + if (sPlayerbotAIConfig.hasLog(fileName)) { std::ostringstream out; - out << sPlayerbotAIConfig->GetTimestampStr(); - out << "+00,\"mmap\", " << x << "," << y << "," << (sTravelMgr->isBadMmap(mapId, x, y) ? "0" : "1") + out << sPlayerbotAIConfig.GetTimestampStr(); + out << "+00,\"mmap\", " << x << "," << y << "," << (TravelMgr::instance().isBadMmap(mapId, x, y) ? "0" : "1") << ","; printWKT(fromGridCoord(GridCoord(x, y)), out, 1, true); - sPlayerbotAIConfig->log(fileName, out.str().c_str()); + sPlayerbotAIConfig.log(fileName, out.str().c_str()); } } else @@ -645,7 +646,7 @@ void WorldPosition::loadMapAndVMap(uint32 mapId, uint8 x, uint8 y) // This needs to be disabled or maps will not load. // Needs more testing to check for impact on movement. if (false) - if (!sTravelMgr->isBadVmap(mapId, x, y)) + if (!TravelMgr::instance().isBadVmap(mapId, x, y)) { // load VMAPs for current map/grid... const MapEntry* i_mapEntry = sMapStore.LookupEntry(mapId); @@ -662,40 +663,40 @@ void WorldPosition::loadMapAndVMap(uint32 mapId, uint8 x, uint8 y) case VMAP::VMAP_LOAD_RESULT_ERROR: // LOG_ERROR("playerbots", "Could not load VMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, // y:{})", mapName, mapId, x, y, x, y); - sTravelMgr->addBadVmap(mapId, x, y); + TravelMgr::instance().addBadVmap(mapId, x, y); break; case VMAP::VMAP_LOAD_RESULT_IGNORED: - sTravelMgr->addBadVmap(mapId, x, y); + TravelMgr::instance().addBadVmap(mapId, x, y); // LOG_INFO("playerbots", "Ignored VMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})", // mapName, mapId, x, y, x, y); break; } - if (sPlayerbotAIConfig->hasLog(fileName)) + if (sPlayerbotAIConfig.hasLog(fileName)) { std::ostringstream out; - out << sPlayerbotAIConfig->GetTimestampStr(); - out << "+00,\"vmap\", " << x << "," << y << ", " << (sTravelMgr->isBadVmap(mapId, x, y) ? "0" : "1") + out << sPlayerbotAIConfig.GetTimestampStr(); + out << "+00,\"vmap\", " << x << "," << y << ", " << (TravelMgr::instance().isBadVmap(mapId, x, y) ? "0" : "1") << ","; printWKT(frommGridCoord(mGridCoord(x, y)), out, 1, true); - sPlayerbotAIConfig->log(fileName, out.str().c_str()); + sPlayerbotAIConfig.log(fileName, out.str().c_str()); } } - if (!sTravelMgr->isBadMmap(mapId, x, y)) + if (!TravelMgr::instance().isBadMmap(mapId, x, y)) { // load navmesh if (!MMAP::MMapFactory::createOrGetMMapMgr()->loadMap(mapId, x, y)) - sTravelMgr->addBadMmap(mapId, x, y); + TravelMgr::instance().addBadMmap(mapId, x, y); - if (sPlayerbotAIConfig->hasLog(fileName)) + if (sPlayerbotAIConfig.hasLog(fileName)) { std::ostringstream out; - out << sPlayerbotAIConfig->GetTimestampStr(); - out << "+00,\"mmap\", " << x << "," << y << "," << (sTravelMgr->isBadMmap(mapId, x, y) ? "0" : "1") + out << sPlayerbotAIConfig.GetTimestampStr(); + out << "+00,\"mmap\", " << x << "," << y << "," << (TravelMgr::instance().isBadMmap(mapId, x, y) ? "0" : "1") << ","; printWKT(fromGridCoord(GridCoord(x, y)), out, 1, true); - sPlayerbotAIConfig->log(fileName, out.str().c_str()); + sPlayerbotAIConfig.log(fileName, out.str().c_str()); } } } @@ -733,21 +734,21 @@ std::vector WorldPosition::getPathStepFrom(WorldPosition startPos Movement::PointsArray points = path.GetPath(); PathType type = path.GetPathType(); - if (sPlayerbotAIConfig->hasLog("pathfind_attempt_point.csv")) + if (sPlayerbotAIConfig.hasLog("pathfind_attempt_point.csv")) { std::ostringstream out; out << std::fixed << std::setprecision(1); printWKT({startPos, *this}, out); - sPlayerbotAIConfig->log("pathfind_attempt_point.csv", out.str().c_str()); + sPlayerbotAIConfig.log("pathfind_attempt_point.csv", out.str().c_str()); } - if (sPlayerbotAIConfig->hasLog("pathfind_attempt.csv") && (type == PATHFIND_INCOMPLETE || type == PATHFIND_NORMAL)) + if (sPlayerbotAIConfig.hasLog("pathfind_attempt.csv") && (type == PATHFIND_INCOMPLETE || type == PATHFIND_NORMAL)) { std::ostringstream out; - out << sPlayerbotAIConfig->GetTimestampStr() << "+00,"; + out << sPlayerbotAIConfig.GetTimestampStr() << "+00,"; out << std::fixed << std::setprecision(1) << type << ","; printWKT(fromPointsArray(points), out, 1); - sPlayerbotAIConfig->log("pathfind_attempt.csv", out.str().c_str()); + sPlayerbotAIConfig.log("pathfind_attempt.csv", out.str().c_str()); } if (type == PATHFIND_INCOMPLETE || type == PATHFIND_NORMAL) @@ -796,7 +797,7 @@ std::vector WorldPosition::getPathFromPath(std::vectortargetPosRecalcDistance) + if (subPath.empty() || currentPos.distance(&subPath.back()) < sPlayerbotAIConfig.targetPosRecalcDistance) break; // Append the path excluding the start (this should be the same as the end of the startPath) @@ -1071,7 +1072,7 @@ std::vector TravelDestination::sortedPoints(WorldPosition* pos) std::vector TravelDestination::nextPoint(WorldPosition* pos, bool ignoreFull) { - return sTravelMgr->getNextPoint(pos, ignoreFull ? points : getPoints()); + return TravelMgr::instance().getNextPoint(pos, ignoreFull ? points : getPoints()); } bool TravelDestination::isFull(bool ignoreFull) @@ -1108,7 +1109,7 @@ bool QuestRelationTravelDestination::isActive(Player* bot) if (!bot->GetMap()->GetEntry()->IsWorldMap() || !bot->CanTakeQuest(questTemplate, false)) return false; - //uint32 dialogStatus = sTravelMgr->getDialogStatus(bot, entry, questTemplate); //not used, shadowed by the next declaration, line marked for removal. + //uint32 dialogStatus = TravelMgr::instance().getDialogStatus(bot, entry, questTemplate); //not used, shadowed by the next declaration, line marked for removal. if (AI_VALUE(bool, "can fight equal")) { @@ -1197,7 +1198,7 @@ bool QuestObjectiveTravelDestination::isActive(Player* bot) if (questTemplate->GetType() == QUEST_TYPE_ELITE && !AI_VALUE(bool, "can fight elite")) return false; - if (!sTravelMgr->getObjectiveStatus(bot, questTemplate, objective)) + if (!TravelMgr::instance().getObjectiveStatus(bot, questTemplate, objective)) return false; WorldPosition botPos(bot); @@ -1435,8 +1436,8 @@ TravelTarget::~TravelTarget() return; releaseVisitors(); - // sTravelMgr->botTargets.erase(std::remove(sTravelMgr->botTargets.begin(), sTravelMgr->botTargets.end(), this), - // sTravelMgr->botTargets.end()); + // TravelMgr::instance().botTargets.erase(std::remove(TravelMgr::instance().botTargets.begin(), TravelMgr::instance().botTargets.end(), this), + // TravelMgr::instance().botTargets.end()); } void TravelTarget::setTarget(TravelDestination* tDestination1, WorldPosition* wPosition1, bool groupCopy1) @@ -1509,7 +1510,7 @@ void TravelTarget::setStatus(TravelStatus status) statusTime = 1; break; case TRAVEL_STATUS_TRAVEL: - statusTime = getMaxTravelTime() * 2 + sPlayerbotAIConfig->maxWaitForMove; + statusTime = getMaxTravelTime() * 2 + sPlayerbotAIConfig.maxWaitForMove; break; case TRAVEL_STATUS_WORK: statusTime = tDestination->getExpireDelay(); @@ -1578,7 +1579,7 @@ bool TravelTarget::isTraveling() if (!botAI->HasStrategy("travel", BOT_STATE_NON_COMBAT)) { - setTarget(sTravelMgr->nullTravelDestination, sTravelMgr->nullWorldPosition, true); + setTarget(TravelMgr::instance().nullTravelDestination, TravelMgr::instance().nullWorldPosition, true); return false; } @@ -1610,7 +1611,7 @@ bool TravelTarget::isWorking() if (!botAI->HasStrategy("travel", BOT_STATE_NON_COMBAT)) { - setTarget(sTravelMgr->nullTravelDestination, sTravelMgr->nullWorldPosition, true); + setTarget(TravelMgr::instance().nullTravelDestination, TravelMgr::instance().nullWorldPosition, true); return false; } @@ -1767,7 +1768,7 @@ void TravelMgr::logQuestError(uint32 errorNr, Quest* quest, uint32 objective, ui void TravelMgr::LoadQuestTravelTable() { - if (!sTravelMgr->quests.empty()) + if (!TravelMgr::instance().quests.empty()) return; // Clearing store (for reloading case) @@ -1960,7 +1961,7 @@ void TravelMgr::LoadQuestTravelTable() bool loadQuestData = true; if (loadQuestData) { - questGuidpMap questMap = GAI_VALUE(questGuidpMap, "quest guidp map"); + questGuidpMap questMap = SharedValueContext::instance().getGlobalValue("quest guidp map")->Get(); for (auto& q : questMap) { @@ -1982,7 +1983,7 @@ void TravelMgr::LoadQuestTravelTable() if (flag & (uint32)QuestRelationFlag::questGiver) { loc = new QuestRelationTravelDestination( - questId, entry, 0, sPlayerbotAIConfig->tooCloseDistance, sPlayerbotAIConfig->sightDistance); + questId, entry, 0, sPlayerbotAIConfig.tooCloseDistance, sPlayerbotAIConfig.sightDistance); loc->setExpireDelay(5 * 60 * 1000); loc->setMaxVisitors(15, 0); container->questGivers.push_back(loc); @@ -1991,7 +1992,7 @@ void TravelMgr::LoadQuestTravelTable() if (flag & (uint32)QuestRelationFlag::questTaker) { loc = new QuestRelationTravelDestination( - questId, entry, 1, sPlayerbotAIConfig->tooCloseDistance, sPlayerbotAIConfig->sightDistance); + questId, entry, 1, sPlayerbotAIConfig.tooCloseDistance, sPlayerbotAIConfig.sightDistance); loc->setExpireDelay(5 * 60 * 1000); loc->setMaxVisitors(15, 0); container->questTakers.push_back(loc); @@ -2010,8 +2011,8 @@ void TravelMgr::LoadQuestTravelTable() objective = 3; loc = new QuestObjectiveTravelDestination(questId, entry, objective, - sPlayerbotAIConfig->tooCloseDistance, - sPlayerbotAIConfig->sightDistance); + sPlayerbotAIConfig.tooCloseDistance, + sPlayerbotAIConfig.sightDistance); loc->setExpireDelay(1 * 60 * 1000); loc->setMaxVisitors(100, 1); container->questObjectives.push_back(loc); @@ -2060,8 +2061,8 @@ void TravelMgr::LoadQuestTravelTable() int32 entry = r.type == 0 ? r.entry : r.entry * -1; - loc = new QuestRelationTravelDestination(r.questId, entry, r.role, sPlayerbotAIConfig->tooCloseDistance, - sPlayerbotAIConfig->sightDistance); loc->setExpireDelay(5 * 60 * 1000); loc->setMaxVisitors(15, 0); + loc = new QuestRelationTravelDestination(r.questId, entry, r.role, sPlayerbotAIConfig.tooCloseDistance, + sPlayerbotAIConfig.sightDistance); loc->setExpireDelay(5 * 60 * 1000); loc->setMaxVisitors(15, 0); for (auto& u : units) { @@ -2098,8 +2099,8 @@ void TravelMgr::LoadQuestTravelTable() uint32 reqEntry = quest->RequiredNpcOrGo[i]; - loc = new QuestObjectiveTravelDestination(questId, reqEntry, i, sPlayerbotAIConfig->tooCloseDistance, - sPlayerbotAIConfig->sightDistance); loc->setExpireDelay(1 * 60 * 1000); loc->setMaxVisitors(100, 1); + loc = new QuestObjectiveTravelDestination(questId, reqEntry, i, sPlayerbotAIConfig.tooCloseDistance, + sPlayerbotAIConfig.sightDistance); loc->setExpireDelay(1 * 60 * 1000); loc->setMaxVisitors(100, 1); for (auto& u : units) { @@ -2149,8 +2150,8 @@ void TravelMgr::LoadQuestTravelTable() int32 entry = l.type == 0 ? l.entry : l.entry * -1; - loc = new QuestObjectiveTravelDestination(questId, entry, i, sPlayerbotAIConfig->tooCloseDistance, - sPlayerbotAIConfig->sightDistance, l.item); loc->setExpireDelay(1 * 60 * 1000); loc->setMaxVisitors(100, 1); + loc = new QuestObjectiveTravelDestination(questId, entry, i, sPlayerbotAIConfig.tooCloseDistance, + sPlayerbotAIConfig.sightDistance, l.item); loc->setExpireDelay(1 * 60 * 1000); loc->setMaxVisitors(100, 1); for (auto& u : units) { @@ -2238,8 +2239,8 @@ void TravelMgr::LoadQuestTravelTable() { if ((cInfo->npcflag & *i) != 0) { - rLoc = new RpgTravelDestination(u.entry, sPlayerbotAIConfig->tooCloseDistance, - sPlayerbotAIConfig->sightDistance); + rLoc = new RpgTravelDestination(u.entry, sPlayerbotAIConfig.tooCloseDistance, + sPlayerbotAIConfig.sightDistance); rLoc->setExpireDelay(5 * 60 * 1000); rLoc->setMaxVisitors(15, 0); @@ -2251,8 +2252,8 @@ void TravelMgr::LoadQuestTravelTable() if (cInfo->mingold > 0) { - gLoc = new GrindTravelDestination(u.entry, sPlayerbotAIConfig->tooCloseDistance, - sPlayerbotAIConfig->sightDistance); + gLoc = new GrindTravelDestination(u.entry, sPlayerbotAIConfig.tooCloseDistance, + sPlayerbotAIConfig.sightDistance); gLoc->setExpireDelay(5 * 60 * 1000); gLoc->setMaxVisitors(100, 0); @@ -2265,8 +2266,8 @@ void TravelMgr::LoadQuestTravelTable() { std::string const nodeName = cInfo->Name; - bLoc = new BossTravelDestination(u.entry, sPlayerbotAIConfig->tooCloseDistance, - sPlayerbotAIConfig->sightDistance); + bLoc = new BossTravelDestination(u.entry, sPlayerbotAIConfig.tooCloseDistance, + sPlayerbotAIConfig.sightDistance); bLoc->setExpireDelay(5 * 60 * 1000); bLoc->setMaxVisitors(0, 0); @@ -2298,8 +2299,8 @@ void TravelMgr::LoadQuestTravelTable() if (iloc == exploreLocs.end()) { - loc = new ExploreTravelDestination(area->ID, sPlayerbotAIConfig->tooCloseDistance, - sPlayerbotAIConfig->sightDistance); + loc = new ExploreTravelDestination(area->ID, sPlayerbotAIConfig.tooCloseDistance, + sPlayerbotAIConfig.sightDistance); loc->setMaxVisitors(1000, 0); loc->setCooldownDelay(1000); loc->setExpireDelay(1000); @@ -2315,23 +2316,23 @@ void TravelMgr::LoadQuestTravelTable() } // Clear these logs files - sPlayerbotAIConfig->openLog("zones.csv", "w"); - sPlayerbotAIConfig->openLog("creatures.csv", "w"); - sPlayerbotAIConfig->openLog("gos.csv", "w"); - sPlayerbotAIConfig->openLog("bot_movement.csv", "w"); - sPlayerbotAIConfig->openLog("bot_pathfinding.csv", "w"); - sPlayerbotAIConfig->openLog("pathfind_attempt.csv", "w"); - sPlayerbotAIConfig->openLog("pathfind_attempt_point.csv", "w"); - sPlayerbotAIConfig->openLog("pathfind_result.csv", "w"); - sPlayerbotAIConfig->openLog("load_map_grid.csv", "w"); - sPlayerbotAIConfig->openLog("strategy.csv", "w"); + sPlayerbotAIConfig.openLog("zones.csv", "w"); + sPlayerbotAIConfig.openLog("creatures.csv", "w"); + sPlayerbotAIConfig.openLog("gos.csv", "w"); + sPlayerbotAIConfig.openLog("bot_movement.csv", "w"); + sPlayerbotAIConfig.openLog("bot_pathfinding.csv", "w"); + sPlayerbotAIConfig.openLog("pathfind_attempt.csv", "w"); + sPlayerbotAIConfig.openLog("pathfind_attempt_point.csv", "w"); + sPlayerbotAIConfig.openLog("pathfind_result.csv", "w"); + sPlayerbotAIConfig.openLog("load_map_grid.csv", "w"); + sPlayerbotAIConfig.openLog("strategy.csv", "w"); - sPlayerbotAIConfig->openLog("unload_grid.csv", "w"); - sPlayerbotAIConfig->openLog("unload_obj.csv", "w"); + sPlayerbotAIConfig.openLog("unload_grid.csv", "w"); + sPlayerbotAIConfig.openLog("unload_obj.csv", "w"); - sTravelNodeMap->loadNodeStore(); + TravelNodeMap::instance().loadNodeStore(); - sTravelNodeMap->generateAll(); + TravelNodeMap::instance().generateAll(); /* bool fullNavPointReload = false; @@ -2340,9 +2341,9 @@ void TravelMgr::LoadQuestTravelTable() if (!fullNavPointReload && true) TravelNodeStore::loadNodes(); - //sTravelNodeMap->loadNodeStore(); + //TravelNodeMap::instance().loadNodeStore(); - for (auto node : sTravelNodeMap->getNodes()) + for (auto node : TravelNodeMap::instance().getNodes()) { node->setLinked(true); } @@ -2384,7 +2385,7 @@ void TravelMgr::LoadQuestTravelTable() else nodeName += " flightMaster"; - sTravelNodeMap->addNode(&pos, nodeName, true, true); + TravelNodeMap::instance().addNode(&pos, nodeName, true, true); break; } @@ -2414,8 +2415,8 @@ void TravelMgr::LoadQuestTravelTable() WorldPosition startPos(startTaxiNode->map_id, startTaxiNode->x, startTaxiNode->y, startTaxiNode->z); WorldPosition endPos(endTaxiNode->map_id, endTaxiNode->x, endTaxiNode->y, endTaxiNode->z); - TravelNode* startNode = sTravelNodeMap->getNode(&startPos, nullptr, 15.0f); - TravelNode* endNode = sTravelNodeMap->getNode(&endPos, nullptr, 15.0f); + TravelNode* startNode = TravelNodeMap::instance().getNode(&startPos, nullptr, 15.0f); + TravelNode* endNode = TravelNodeMap::instance().getNode(&endPos, nullptr, 15.0f); if (!startNode || !endNode) continue; @@ -2448,7 +2449,7 @@ void TravelMgr::LoadQuestTravelTable() if (cInfo->rank == 3 || (cInfo->rank == 1 && !pos.isOverworld() && u.c == 1)) { std::string const nodeName = cInfo->Name; - sTravelNodeMap->addNode(&pos, nodeName, true, true); + TravelNodeMap::instance().addNode(&pos, nodeName, true, true); } } @@ -2475,7 +2476,7 @@ void TravelMgr::LoadQuestTravelTable() pos = WorldPosition(info->mapId, info->positionX, info->positionY, info->positionZ, info->orientation); std::string const nodeName = startNames[i] + " start"; - sTravelNodeMap->addNode(&pos, nodeName, true, true); + TravelNodeMap::instance().addNode(&pos, nodeName, true, true); } } @@ -2530,7 +2531,7 @@ void TravelMgr::LoadQuestTravelTable() if (pos.distance(&lPos) == 0) { - TravelNode* node = sTravelNodeMap->addNode(&pos, data->name, true, true, true, + TravelNode* node = TravelNodeMap::instance().addNode(&pos, data->name, true, true, true, iter.first); if (!prevNode) @@ -2566,7 +2567,7 @@ void TravelMgr::LoadQuestTravelTable() if (pos.distance(&lPos) == 0) { - TravelNode* node = sTravelNodeMap->addNode(&pos, data->name, true, true, true, + TravelNode* node = TravelNodeMap::instance().addNode(&pos, data->name, true, true, true, iter.first); if (node != prevNode) { float totalTime = (p.second->TimeSeg - timeStart) / 1000.0f; @@ -2605,7 +2606,7 @@ void TravelMgr::LoadQuestTravelTable() if (p->delay > 0) { - TravelNode* node = sTravelNodeMap->addNode(&pos, data->name, true, true, true, iter.first); + TravelNode* node = TravelNodeMap::instance().addNode(&pos, data->name, true, true, true, iter.first); if (!prevNode) { @@ -2638,7 +2639,7 @@ void TravelMgr::LoadQuestTravelTable() if (p->delay > 0) { - TravelNode* node = sTravelNodeMap->getNode(&pos, nullptr, 5.0f); + TravelNode* node = TravelNodeMap::instance().getNode(&pos, nullptr, 5.0f); if (node != prevNode) { TravelNodePath travelPath(0.1f, 0.0, (uint8) TravelNodePathType::transport, entry, @@ -2667,13 +2668,13 @@ void TravelMgr::LoadQuestTravelTable() WorldPosition pos = WorldPosition(points, WP_MEAN_CENTROID); - TravelNode* node = sTravelNodeMap->addNode(&pos, pos.getAreaName(), true, true, false); + TravelNode* node = TravelNodeMap::instance().addNode(&pos, pos.getAreaName(), true, true, false); } - LOG_INFO("playerbots", ">> Loaded {} navigation points.", sTravelNodeMap->getNodes().size()); + LOG_INFO("playerbots", ">> Loaded {} navigation points.", TravelNodeMap::instance().getNodes().size()); } - sTravelNodeMap->calcMapOffset(); + TravelNodeMap::instance().calcMapOffset(); loadMapTransfers(); */ @@ -2692,14 +2693,14 @@ void TravelMgr::LoadQuestTravelTable() //PathGenerator std::vector ppath; - uint32 cur = 0, max = sTravelNodeMap->getNodes().size(); + uint32 cur = 0, max = TravelNodeMap::instance().getNodes().size(); - for (auto& startNode : sTravelNodeMap->getNodes()) + for (auto& startNode : TravelNodeMap::instance().getNodes()) { if (!preloadReLinkFullyLinked && startNode->isLinked()) continue; - for (auto& endNode : sTravelNodeMap->getNodes()) + for (auto& endNode : TravelNodeMap::instance().getNodes()) { if (startNode == endNode) continue; @@ -2734,18 +2735,18 @@ void TravelMgr::LoadQuestTravelTable() if (preloadSubPrint && (cur * 50) / max > ((cur - 1) * 50) / max) { - sTravelNodeMap->printMap(); - sTravelNodeMap->printNodeStore(); + TravelNodeMap::instance().printMap(); + TravelNodeMap::instance().printNodeStore(); } } if (!preloadSubPrint) { - sTravelNodeMap->printNodeStore(); - sTravelNodeMap->printMap(); + TravelNodeMap::instance().printNodeStore(); + TravelNodeMap::instance().printMap(); } - LOG_INFO("playerbots", ">> Loaded paths for {} nodes.", sTravelNodeMap->getNodes().size()); + LOG_INFO("playerbots", ">> Loaded paths for {} nodes.", TravelNodeMap::instance().getNodes().size()); } bool removeLowLinkNodes = false || fullNavPointReload || storeNavPointReload; @@ -2754,7 +2755,7 @@ void TravelMgr::LoadQuestTravelTable() { std::vector goodNodes; std::vector remNodes; - for (auto& node : sTravelNodeMap->getNodes()) + for (auto& node : TravelNodeMap::instance().getNodes()) { if (!node->getPosition()->isOverworld()) continue; @@ -2774,9 +2775,9 @@ void TravelMgr::LoadQuestTravelTable() } for (auto& node : remNodes) - sTravelNodeMap->removeNode(node); + TravelNodeMap::instance().removeNode(node); - LOG_INFO("playerbots", ">> Checked {} nodes.", sTravelNodeMap->getNodes().size()); + LOG_INFO("playerbots", ">> Checked {} nodes.", TravelNodeMap::instance().getNodes().size()); } bool cleanUpNodeLinks = false || fullNavPointReload || storeNavPointReload; @@ -2786,22 +2787,22 @@ void TravelMgr::LoadQuestTravelTable() { //Routes uint32 cur = 0; - uint32 max = sTravelNodeMap->getNodes().size(); + uint32 max = TravelNodeMap::instance().getNodes().size(); //Clean up node links - for (auto& startNode : sTravelNodeMap->getNodes()) + for (auto& startNode : TravelNodeMap::instance().getNodes()) { startNode->cropUselessLinks(); cur++; if (cleanUpSubPrint && (cur * 10) / max > ((cur - 1) * 10) / max) { - sTravelNodeMap->printMap(); - sTravelNodeMap->printNodeStore(); + TravelNodeMap::instance().printMap(); + TravelNodeMap::instance().printNodeStore(); } } - LOG_INFO("playerbots", ">> Cleaned paths for {} nodes.", sTravelNodeMap->getNodes().size()); + LOG_INFO("playerbots", ">> Cleaned paths for {} nodes.", TravelNodeMap::instance().getNodes().size()); } bool reCalculateCost = false || fullNavPointReload || storeNavPointReload; @@ -2809,7 +2810,7 @@ void TravelMgr::LoadQuestTravelTable() if (reCalculateCost) { - for (auto& startNode : sTravelNodeMap->getNodes()) + for (auto& startNode : TravelNodeMap::instance().getNodes()) { for (auto& path : *startNode->getLinks()) { @@ -2825,14 +2826,14 @@ void TravelMgr::LoadQuestTravelTable() } } - LOG_INFO("playerbots", ">> Calculated pathcost for {} nodes.", sTravelNodeMap->getNodes().size()); + LOG_INFO("playerbots", ">> Calculated pathcost for {} nodes.", TravelNodeMap::instance().getNodes().size()); } bool mirrorMissingPaths = true || fullNavPointReload || storeNavPointReload; if (mirrorMissingPaths) { - for (auto& startNode : sTravelNodeMap->getNodes()) + for (auto& startNode : TravelNodeMap::instance().getNodes()) { for (auto& path : *startNode->getLinks()) { @@ -2855,16 +2856,16 @@ void TravelMgr::LoadQuestTravelTable() } } - LOG_INFO("playerbots", ">> Reversed missing paths for {} nodes.", sTravelNodeMap->getNodes().size()); + LOG_INFO("playerbots", ">> Reversed missing paths for {} nodes.", TravelNodeMap::instance().getNodes().size()); } */ - sTravelNodeMap->printMap(); - sTravelNodeMap->printNodeStore(); - sTravelNodeMap->saveNodeStore(); + TravelNodeMap::instance().printMap(); + TravelNodeMap::instance().printNodeStore(); + TravelNodeMap::instance().saveNodeStore(); // Creature/gos/zone export. - if (sPlayerbotAIConfig->hasLog("creatures.csv")) + if (sPlayerbotAIConfig.hasLog("creatures.csv")) { for (CreatureData const* cData : WorldPosition().getCreaturesNear()) { @@ -2889,11 +2890,11 @@ void TravelMgr::LoadQuestTravelTable() out << point.getAreaName() << ","; out << std::fixed; - sPlayerbotAIConfig->log("creatures.csv", out.str().c_str()); + sPlayerbotAIConfig.log("creatures.csv", out.str().c_str()); } } - if (sPlayerbotAIConfig->hasLog("vmangoslines.csv")) + if (sPlayerbotAIConfig.hasLog("vmangoslines.csv")) { uint32 mapId = 0; std::vector pos; @@ -2924,7 +2925,7 @@ void TravelMgr::LoadQuestTravelTable() WorldPosition().printWKT(pos, out, 1); out << std::fixed; - sPlayerbotAIConfig->log("vmangoslines.csv", out.str().c_str()); + sPlayerbotAIConfig.log("vmangoslines.csv", out.str().c_str()); static float const ironforgeAreaSouthLimit[] = { -7491.33f, 3093.740f, -7472.04f, -391.880f, -6366.68f, -730.100f, -6063.96f, -1411.76f, @@ -2951,7 +2952,7 @@ void TravelMgr::LoadQuestTravelTable() WorldPosition().printWKT(pos, out, 1); out << std::fixed; - sPlayerbotAIConfig->log("vmangoslines.csv", out.str().c_str()); + sPlayerbotAIConfig.log("vmangoslines.csv", out.str().c_str()); static float const stormwindAreaNorthLimit[] = { -8004.250f, 3714.110f, -8075.000f, -179.000f, -8638.000f, 169.0000f, -9044.000f, 35.00000f, @@ -2979,7 +2980,7 @@ void TravelMgr::LoadQuestTravelTable() WorldPosition().printWKT(pos, out, 1); out << std::fixed; - sPlayerbotAIConfig->log("vmangoslines.csv", out.str().c_str()); + sPlayerbotAIConfig.log("vmangoslines.csv", out.str().c_str()); static float const stormwindAreaSouthLimit[] = { -8725.3378910f, 3535.62402300f, -9525.6992190f, 910.13256800f, -9796.9531250f, 839.06958000f, @@ -3010,7 +3011,7 @@ void TravelMgr::LoadQuestTravelTable() WorldPosition().printWKT(pos, out, 1); out << std::fixed; - sPlayerbotAIConfig->log("vmangoslines.csv", out.str().c_str()); + sPlayerbotAIConfig.log("vmangoslines.csv", out.str().c_str()); mapId = 1; @@ -3044,7 +3045,7 @@ void TravelMgr::LoadQuestTravelTable() WorldPosition().printWKT(pos, out, 1); out << std::fixed; - sPlayerbotAIConfig->log("vmangoslines.csv", out.str().c_str()); + sPlayerbotAIConfig.log("vmangoslines.csv", out.str().c_str()); static float const durotarSouthLimit[] = { 2755.0f, -3766.f, 2225.0f, -3596.f, 1762.0f, -3746.f, 1564.0f, -3943.f, 1184.0f, -3915.f, 737.00f, @@ -3072,7 +3073,7 @@ void TravelMgr::LoadQuestTravelTable() WorldPosition().printWKT(pos, out, 1); out << std::fixed; - sPlayerbotAIConfig->log("vmangoslines.csv", out.str().c_str()); + sPlayerbotAIConfig.log("vmangoslines.csv", out.str().c_str()); static float const valleyoftrialsSouthLimit[] = {-324.f, -3869.f, -774.f, -3992.f, -965.f, -4290.f, -932.f, -4349.f, -828.f, -4414.f, -661.f, -4541.f, -521.f, -4582.f}; @@ -3097,7 +3098,7 @@ void TravelMgr::LoadQuestTravelTable() WorldPosition().printWKT(pos, out, 1); out << std::fixed; - sPlayerbotAIConfig->log("vmangoslines.csv", out.str().c_str()); + sPlayerbotAIConfig.log("vmangoslines.csv", out.str().c_str()); static float const middleToSouthLimit[] = { -2402.010000f, 4255.7000000f, -2475.933105f, 3199.5683590f, // Desolace @@ -3129,7 +3130,7 @@ void TravelMgr::LoadQuestTravelTable() WorldPosition().printWKT(pos, out, 1); out << std::fixed; - sPlayerbotAIConfig->log("vmangoslines.csv", out.str().c_str()); + sPlayerbotAIConfig.log("vmangoslines.csv", out.str().c_str()); static float const orgrimmarSouthLimit[] = { 2132.5076f, -3912.2478f, 1944.4298f, -3855.2583f, 1735.6906f, -3834.2417f, 1654.3671f, -3380.9902f, @@ -3157,7 +3158,7 @@ void TravelMgr::LoadQuestTravelTable() WorldPosition().printWKT(pos, out, 1); out << std::fixed; - sPlayerbotAIConfig->log("vmangoslines.csv", out.str().c_str()); + sPlayerbotAIConfig.log("vmangoslines.csv", out.str().c_str()); static float const feralasThousandNeedlesSouthLimit[] = { -6495.4995f, -4711.9810f, -6674.9995f, -4515.0019f, -6769.5717f, -4122.4272f, -6838.2651f, -3874.2792f, @@ -3187,10 +3188,10 @@ void TravelMgr::LoadQuestTravelTable() WorldPosition().printWKT(pos, out, 1); out << std::fixed; - sPlayerbotAIConfig->log("vmangoslines.csv", out.str().c_str()); + sPlayerbotAIConfig.log("vmangoslines.csv", out.str().c_str()); } - if (sPlayerbotAIConfig->hasLog("gos.csv")) + if (sPlayerbotAIConfig.hasLog("gos.csv")) { for (GameObjectData const* gData : WorldPosition().getGameObjectsNear()) { @@ -3212,11 +3213,11 @@ void TravelMgr::LoadQuestTravelTable() out << point.getAreaName() << ","; out << std::fixed; - sPlayerbotAIConfig->log("gos.csv", out.str().c_str()); + sPlayerbotAIConfig.log("gos.csv", out.str().c_str()); } } - if (sPlayerbotAIConfig->hasLog("zones.csv")) + if (sPlayerbotAIConfig.hasLog("zones.csv")) { std::unordered_map> zoneLocs; @@ -3238,7 +3239,7 @@ void TravelMgr::LoadQuestTravelTable() if (loc.second.empty()) continue; - if (!sTravelNodeMap->getMapOffset(loc.second.front().getMapId()) && loc.second.front().getMapId() != 0) + if (!TravelNodeMap::instance().getMapOffset(loc.second.front().getMapId()) && loc.second.front().getMapId() != 0) continue; std::vector points = loc.second; @@ -3266,13 +3267,13 @@ void TravelMgr::LoadQuestTravelTable() point.printWKT(points, out, 0); - sPlayerbotAIConfig->log("zones.csv", out.str().c_str()); + sPlayerbotAIConfig.log("zones.csv", out.str().c_str()); } } bool printStrategyMap = false; - if (printStrategyMap && sPlayerbotAIConfig->hasLog("strategy.csv")) + if (printStrategyMap && sPlayerbotAIConfig.hasLog("strategy.csv")) { static std::map classes; static std::map> specs; @@ -3328,7 +3329,7 @@ void TravelMgr::LoadQuestTravelTable() // Use randombot 0. std::ostringstream cout; - cout << sPlayerbotAIConfig->randomBotAccountPrefix << 0; + cout << sPlayerbotAIConfig.randomBotAccountPrefix << 0; std::string const accountName = cout.str(); LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ID_BY_USERNAME); @@ -3502,7 +3503,7 @@ void TravelMgr::LoadQuestTravelTable() return false; }); - sPlayerbotAIConfig->log("strategy.csv", "relevance, action, trigger, strategy, classes"); + sPlayerbotAIConfig.log("strategy.csv", "relevance, action, trigger, strategy, classes"); for (auto& actionkey : actionKeys) { @@ -3607,17 +3608,17 @@ void TravelMgr::LoadQuestTravelTable() out << actionkey << "\n"; } - sPlayerbotAIConfig->log("strategy.csv", out.str().c_str()); + sPlayerbotAIConfig.log("strategy.csv", out.str().c_str()); } } /* - sPlayerbotAIConfig->openLog(7, "w"); + sPlayerbotAIConfig.openLog(7, "w"); //Zone area map REMOVE! uint32 k = 0; - for (auto& node : sTravelNodeMap->getNodes()) + for (auto& node : TravelNodeMap::instance().getNodes()) { WorldPosition* pos = node->getPosition(); //map area @@ -3642,7 +3643,7 @@ void TravelMgr::LoadQuestTravelTable() std::ostringstream out; out << std::fixed << area << "," << npos.getDisplayX() << "," << npos.getDisplayY(); - sPlayerbotAIConfig->log(7, out.str().c_str()); + sPlayerbotAIConfig.log(7, out.str().c_str()); } } k++; @@ -3653,7 +3654,7 @@ void TravelMgr::LoadQuestTravelTable() //Explore map output (REMOVE!) - sPlayerbotAIConfig->openLog(5, "w"); + sPlayerbotAIConfig.openLog(5, "w"); for (auto i : exploreLocs) { for (auto j : i.second->getPoints()) @@ -3662,7 +3663,7 @@ void TravelMgr::LoadQuestTravelTable() std::string const name = i.second->getTitle(); name.erase(remove(name.begin(), name.end(), '\"'), name.end()); out << std::fixed << std::setprecision(2) << name.c_str() << "," << i.first << "," << j->getDisplayX() << - "," << j->getDisplayY() << "," << j->getX() << "," << j->getY() << "," << j->getZ(); sPlayerbotAIConfig->log(5, + "," << j->getDisplayY() << "," << j->getX() << "," << j->getY() << "," << j->getZ(); sPlayerbotAIConfig.log(5, out.str().c_str()); } } @@ -3897,7 +3898,7 @@ bool TravelMgr::getObjectiveStatus(Player* bot, Quest const* pQuest, uint32 obje if (bot->GetQuestStatus(questId) != QUEST_STATUS_INCOMPLETE) return false; - QuestStatusData* questStatus = sTravelMgr->getQuestStatus(bot, questId); + QuestStatusData* questStatus = TravelMgr::instance().getQuestStatus(bot, questId); uint32 reqCount = pQuest->RequiredItemCount[objective]; uint32 hasCount = questStatus->ItemCount[objective]; @@ -4097,7 +4098,7 @@ void TravelMgr::setNullTravelTarget(Player* player) TravelTarget* target = playerBotAI->GetAiObjectContext()->GetValue("travel target")->Get(); if (target) - target->setTarget(sTravelMgr->nullTravelDestination, sTravelMgr->nullWorldPosition, true); + target->setTarget(TravelMgr::instance().nullTravelDestination, TravelMgr::instance().nullWorldPosition, true); } void TravelMgr::addMapTransfer(WorldPosition start, WorldPosition end, float portalDistance, bool makeShortcuts) @@ -4146,7 +4147,7 @@ void TravelMgr::addMapTransfer(WorldPosition start, WorldPosition end, float por void TravelMgr::loadMapTransfers() { - for (auto& node : sTravelNodeMap->getNodes()) + for (auto& node : TravelNodeMap::instance().getNodes()) { for (auto& link : *node->getLinks()) { @@ -4233,15 +4234,15 @@ void TravelMgr::printGrid(uint32 mapId, int x, int y, std::string const type) { std::string const fileName = "unload_grid.csv"; - if (sPlayerbotAIConfig->hasLog(fileName)) + if (sPlayerbotAIConfig.hasLog(fileName)) { WorldPosition p = WorldPosition(mapId, 0, 0, 0, 0); std::ostringstream out; - out << sPlayerbotAIConfig->GetTimestampStr(); + out << sPlayerbotAIConfig.GetTimestampStr(); out << "+00, " << 0 << 0 << x << "," << y << ", " << type << ","; p.printWKT(p.fromGridCoord(GridCoord(x, y)), out, 1, true); - sPlayerbotAIConfig->log(fileName, out.str().c_str()); + sPlayerbotAIConfig.log(fileName, out.str().c_str()); } } @@ -4249,7 +4250,7 @@ void TravelMgr::printObj(WorldObject* obj, std::string const type) { std::string fileName = "unload_grid.csv"; - if (sPlayerbotAIConfig->hasLog(fileName)) + if (sPlayerbotAIConfig.hasLog(fileName)) { WorldPosition p = WorldPosition(obj); @@ -4261,40 +4262,40 @@ void TravelMgr::printObj(WorldObject* obj, std::string const type) { std::ostringstream out; - out << sPlayerbotAIConfig->GetTimestampStr(); + out << sPlayerbotAIConfig.GetTimestampStr(); out << "+00, " << obj->GetGUID().GetEntry() << "," << obj->GetGUID().GetCounter() << "," << cell.GridX() << "," << cell.GridY() << ", " << type << ","; p.printWKT(vcell, out, 1, true); - sPlayerbotAIConfig->log(fileName, out.str().c_str()); + sPlayerbotAIConfig.log(fileName, out.str().c_str()); } { std::ostringstream out; - out << sPlayerbotAIConfig->GetTimestampStr(); + out << sPlayerbotAIConfig.GetTimestampStr(); out << "+00, " << obj->GetGUID().GetEntry() << "," << obj->GetGUID().GetCounter() << "," << cell.GridX() << "," << cell.GridY() << ", " << type << ","; p.printWKT(vgrid, out, 1, true); - sPlayerbotAIConfig->log(fileName, out.str().c_str()); + sPlayerbotAIConfig.log(fileName, out.str().c_str()); } } fileName = "unload_obj.csv"; - if (sPlayerbotAIConfig->hasLog(fileName)) + if (sPlayerbotAIConfig.hasLog(fileName)) { WorldPosition p = WorldPosition(obj); Cell cell(obj->GetPositionX(), obj->GetPositionY()); { std::ostringstream out; - out << sPlayerbotAIConfig->GetTimestampStr(); + out << sPlayerbotAIConfig.GetTimestampStr(); out << "+00, " << obj->GetGUID().GetEntry() << "," << obj->GetGUID().GetCounter() << "," << cell.GridX() << "," << cell.GridY() << ", " << type << ","; p.printWKT({p}, out, 0); - sPlayerbotAIConfig->log(fileName, out.str().c_str()); + sPlayerbotAIConfig.log(fileName, out.str().c_str()); } } } diff --git a/src/Mgr/Travel/TravelMgr.h b/src/Mgr/Travel/TravelMgr.h index 39a79a4078..3223444bfe 100644 --- a/src/Mgr/Travel/TravelMgr.h +++ b/src/Mgr/Travel/TravelMgr.h @@ -10,7 +10,6 @@ #include #include "AiObject.h" -#include "Corpse.h" #include "CreatureData.h" #include "GameObject.h" #include "GridDefines.h" @@ -298,11 +297,11 @@ class WorldPosition : public WorldLocation std::vector getPathTo(WorldPosition endPos, Unit* bot) { return endPos.getPathFrom(*this, bot); } - bool isPathTo(std::vector path, float maxDistance = sPlayerbotAIConfig->targetPosRecalcDistance) + bool isPathTo(std::vector path, float maxDistance = sPlayerbotAIConfig.targetPosRecalcDistance) { return !path.empty() && distance(path.back()) < maxDistance; }; - bool cropPathTo(std::vector& path, float maxDistance = sPlayerbotAIConfig->targetPosRecalcDistance); + bool cropPathTo(std::vector& path, float maxDistance = sPlayerbotAIConfig.targetPosRecalcDistance); bool canPathTo(WorldPosition endPos, Unit* bot) { return endPos.isPathTo(getPathTo(endPos, bot)); } float getPathLength(std::vector points) @@ -848,12 +847,11 @@ class TravelTarget : AiObject class TravelMgr { public: - TravelMgr(){}; - - static TravelMgr* instance() + static TravelMgr& instance() { static TravelMgr instance; - return &instance; + + return instance; } void Clear(); @@ -922,7 +920,6 @@ class TravelMgr void printGrid(uint32 mapId, int x, int y, std::string const type); void printObj(WorldObject* obj, std::string const type); - // protected: void logQuestError(uint32 errorNr, Quest* quest, uint32 objective = 0, uint32 unitId = 0, uint32 itemId = 0); std::vector avoidLoaded; @@ -939,8 +936,16 @@ class TravelMgr std::unordered_map, std::vector, boost::hash>> mapTransfersMap; -}; -#define sTravelMgr TravelMgr::instance() +private: + TravelMgr() = default; + ~TravelMgr() = default; + + TravelMgr(const TravelMgr&) = delete; + TravelMgr& operator=(const TravelMgr&) = delete; + + TravelMgr(TravelMgr&&) = delete; + TravelMgr& operator=(TravelMgr&&) = delete; +}; #endif diff --git a/src/Mgr/Travel/TravelNode.cpp b/src/Mgr/Travel/TravelNode.cpp index d3c03ed97e..5d740075da 100644 --- a/src/Mgr/Travel/TravelNode.cpp +++ b/src/Mgr/Travel/TravelNode.cpp @@ -323,7 +323,7 @@ void TravelNode::removeLinkTo(TravelNode* node, bool removePaths) else { // Remove all references to this node. - for (auto& node : sTravelNodeMap->getNodes()) + for (auto& node : TravelNodeMap::instance().getNodes()) { if (node->hasPathTo(this)) node->removeLinkTo(this, removePaths); @@ -397,7 +397,7 @@ bool TravelNode::isUselessLink(TravelNode* farNode) } else { - TravelNodeRoute route = sTravelNodeMap->getRoute(nearNode, farNode, nullptr); + TravelNodeRoute route = TravelNodeMap::instance().getRoute(nearNode, farNode, nullptr); if (route.isEmpty()) continue; @@ -432,7 +432,7 @@ bool TravelNode::cropUselessLinks() this->removeLinkTo(farNode); hasRemoved = true; - if (sPlayerbotAIConfig->hasLog("crop.csv")) + if (sPlayerbotAIConfig.hasLog("crop.csv")) { std::ostringstream out; out << getName() << ","; @@ -440,7 +440,7 @@ bool TravelNode::cropUselessLinks() WorldPosition().printWKT({*getPosition(), *farNode->getPosition()}, out, 1); out << std::fixed; - sPlayerbotAIConfig->log("crop.csv", out.str().c_str()); + sPlayerbotAIConfig.log("crop.csv", out.str().c_str()); } } @@ -449,7 +449,7 @@ bool TravelNode::cropUselessLinks() farNode->removeLinkTo(this); hasRemoved = true; - if (sPlayerbotAIConfig->hasLog("crop.csv")) + if (sPlayerbotAIConfig.hasLog("crop.csv")) { std::ostringstream out; out << getName() << ","; @@ -457,7 +457,7 @@ bool TravelNode::cropUselessLinks() WorldPosition().printWKT({*getPosition(), *farNode->getPosition()}, out, 1); out << std::fixed; - sPlayerbotAIConfig->log("crop.csv", out.str().c_str()); + sPlayerbotAIConfig.log("crop.csv", out.str().c_str()); } } } @@ -496,7 +496,7 @@ bool TravelNode::cropUselessLinks() } else { - TravelNodeRoute route = sTravelNodeMap->getRoute(firstNode, secondNode, false); + TravelNodeRoute route = TravelNodeMap::instance().getRoute(firstNode, secondNode, false); if (route.isEmpty()) continue; @@ -544,7 +544,7 @@ bool TravelNode::cropUselessLinks() } else { - TravelNodeRoute route = sTravelNodeMap->getRoute(firstNode, secondNode, false); + TravelNodeRoute route = TravelNodeMap::instance().getRoute(firstNode, secondNode, false); if (route.isEmpty()) continue; @@ -579,7 +579,7 @@ bool TravelNode::isEqual(TravelNode* compareNode) if (!compareNode->hasLinkTo(this)) return false; - for (auto& node : sTravelNodeMap->getNodes()) + for (auto& node : TravelNodeMap::instance().getNodes()) { if (node == this || node == compareNode) continue; @@ -611,11 +611,11 @@ void TravelNode::print([[maybe_unused]] bool printFailed) out << (isImportant() ? 1 : 0) << ","; out << mapSize; - sPlayerbotAIConfig->log("travelNodes.csv", out.str().c_str()); + sPlayerbotAIConfig.log("travelNodes.csv", out.str().c_str()); std::vector ppath; - for (auto& endNode : sTravelNodeMap->getNodes()) + for (auto& endNode : TravelNodeMap::instance().getNodes()) { if (endNode == this) continue; @@ -665,7 +665,7 @@ void TravelNode::print([[maybe_unused]] bool printFailed) out << std::to_string(path->getMaxLevelCreature()[1]) << ","; out << std::to_string(path->getMaxLevelCreature()[2]); - sPlayerbotAIConfig->log("travelPaths.csv", out.str().c_str()); + sPlayerbotAIConfig.log("travelPaths.csv", out.str().c_str()); } } } @@ -695,8 +695,8 @@ bool TravelPath::makeShortCut(WorldPosition startPos, float maxDist) totalDist += p.point.sqDistance(std::prev(&p)->point); if (curDist < - sPlayerbotAIConfig->tooCloseDistance * - sPlayerbotAIConfig->tooCloseDistance) // We are on the path. This is a good starting point + sPlayerbotAIConfig.tooCloseDistance * + sPlayerbotAIConfig.tooCloseDistance) // We are on the path. This is a good starting point { minDist = curDist; totalDist = curDist; @@ -731,11 +731,11 @@ bool TravelPath::makeShortCut(WorldPosition startPos, float maxDist) WorldPosition beginPos = newPath.begin()->point; // The old path seems to be the best. - if (beginPos.distance(firstNode) < sPlayerbotAIConfig->tooCloseDistance) + if (beginPos.distance(firstNode) < sPlayerbotAIConfig.tooCloseDistance) return false; // We are (nearly) on the new path. Just follow the rest. - if (beginPos.distance(startPos) < sPlayerbotAIConfig->tooCloseDistance) + if (beginPos.distance(startPos) < sPlayerbotAIConfig.tooCloseDistance) { fullPath = newPath; return true; @@ -891,7 +891,7 @@ WorldPosition TravelPath::getNextPoint(WorldPosition startPos, float maxDist, Tr } // We have to move far for next point. Try to make a cropped path. - if (moveDist < sPlayerbotAIConfig->targetPosRecalcDistance && std::next(startP) != ed) + if (moveDist < sPlayerbotAIConfig.targetPosRecalcDistance && std::next(startP) != ed) { // std::vector path = startPos.getPathTo(std::next(startP)->point, nullptr); // startP->point = startPos.lastInRange(path, -1, maxDist); @@ -905,7 +905,7 @@ std::ostringstream const TravelPath::print() { std::ostringstream out; - out << sPlayerbotAIConfig->GetTimestampStr(); + out << sPlayerbotAIConfig.GetTimestampStr(); out << "+00," << "1,"; out << std::fixed; @@ -1031,7 +1031,7 @@ std::ostringstream const TravelNodeRoute::print() { std::ostringstream out; - out << sPlayerbotAIConfig->GetTimestampStr(); + out << sPlayerbotAIConfig.GetTimestampStr(); out << "+00" << ",0," << "\"LINESTRING("; @@ -1046,34 +1046,6 @@ std::ostringstream const TravelNodeRoute::print() return out; } -TravelNodeMap::TravelNodeMap(TravelNodeMap* baseMap) -{ - TravelNode* newNode; - - baseMap->m_nMapMtx.lock_shared(); - - for (auto& node : baseMap->getNodes()) - { - newNode = new TravelNode(node); - - m_nodes.push_back(newNode); - } - - for (auto& node : baseMap->getNodes()) - { - newNode = getNode(node); - - for (auto& path : *node->getPaths()) - { - TravelNode* endNode = getNode(path.first); - - newNode->setPathTo(endNode, path.second); - } - } - - baseMap->m_nMapMtx.unlock_shared(); -} - TravelNode* TravelNodeMap::addNode(WorldPosition pos, std::string const preferedName, bool isImportant, bool checkDuplicate, [[maybe_unused]] bool transport, [[maybe_unused]] uint32 transportId) @@ -1178,7 +1150,7 @@ TravelNode* TravelNodeMap::getNode(WorldPosition pos, [[maybe_unused]] std::vect uint32 c = 0; - std::vector nodes = sTravelNodeMap->getNodes(pos, range); + std::vector nodes = TravelNodeMap::instance().getNodes(pos, range); for (auto& node : nodes) { if (!bot || pos.canPathTo(*node->getPosition(), bot)) @@ -1233,14 +1205,14 @@ TravelNodeRoute TravelNodeMap::getRoute(TravelNode* start, TravelNode* goal, Pla { AiObjectContext* context = botAI->GetAiObjectContext(); - TravelNode* homeNode = sTravelNodeMap->getNode(AI_VALUE(WorldPosition, "home bind"), nullptr, 10.0f); + TravelNode* homeNode = TravelNodeMap::instance().getNode(AI_VALUE(WorldPosition, "home bind"), nullptr, 10.0f); if (homeNode) { - PortalNode* portNode = (PortalNode*)sTravelNodeMap->teleportNodes[bot->GetGUID()][8690]; + PortalNode* portNode = (PortalNode*)TravelNodeMap::instance().teleportNodes[bot->GetGUID()][8690]; { portNode = new PortalNode(start); - sTravelNodeMap->teleportNodes[bot->GetGUID()][8690] = portNode; + TravelNodeMap::instance().teleportNodes[bot->GetGUID()][8690] = portNode; } portNode->SetPortal(start, homeNode, 8690); @@ -1370,7 +1342,7 @@ TravelNodeRoute TravelNodeMap::getRoute(WorldPosition startPos, WorldPosition en WorldPosition startNodePosition = *startNode->getPosition(); WorldPosition endNodePosition = *endNode->getPosition(); - float maxStartDistance = startNode->isTransport() ? 20.0f : sPlayerbotAIConfig->targetPosRecalcDistance; + float maxStartDistance = startNode->isTransport() ? 20.0f : sPlayerbotAIConfig.targetPosRecalcDistance; TravelNodeRoute route = getRoute(startNode, endNode, bot); @@ -1403,10 +1375,10 @@ TravelNodeRoute TravelNodeMap::getRoute(WorldPosition startPos, WorldPosition en if (bot && !bot->HasSpellCooldown(8690)) { startPath.clear(); - TravelNode* botNode = sTravelNodeMap->teleportNodes[bot->GetGUID()][0]; + TravelNode* botNode = TravelNodeMap::instance().teleportNodes[bot->GetGUID()][0]; { botNode = new TravelNode(startPos, "Bot Pos", false); - sTravelNodeMap->teleportNodes[bot->GetGUID()][0] = botNode; + TravelNodeMap::instance().teleportNodes[bot->GetGUID()][0] = botNode; } botNode->setPoint(startPos); @@ -1440,37 +1412,37 @@ TravelPath TravelNodeMap::getFullPath(WorldPosition startPos, WorldPosition endP //[[Node pathfinding system]] // We try to find nodes near the bot and near the end position that have a route between them. // Then bot has to move towards/along the route. - sTravelNodeMap->m_nMapMtx.lock_shared(); + TravelNodeMap::instance().m_nMapMtx.lock_shared(); // Find the route of nodes starting at a node closest to the start position and ending at a node closest to the // endposition. Also returns longPath: The path from the start position to the first node in the route. - TravelNodeRoute route = sTravelNodeMap->getRoute(startPos, endPos, beginPath, bot); + TravelNodeRoute route = TravelNodeMap::instance().getRoute(startPos, endPos, beginPath, bot); if (route.isEmpty()) return movePath; - if (sPlayerbotAIConfig->hasLog("bot_pathfinding.csv")) + if (sPlayerbotAIConfig.hasLog("bot_pathfinding.csv")) { if (botAI->HasStrategy("debug move", BOT_STATE_NON_COMBAT)) { - sPlayerbotAIConfig->openLog("bot_pathfinding.csv", "w"); - sPlayerbotAIConfig->log("bot_pathfinding.csv", route.print().str().c_str()); + sPlayerbotAIConfig.openLog("bot_pathfinding.csv", "w"); + sPlayerbotAIConfig.log("bot_pathfinding.csv", route.print().str().c_str()); } } endPath = route.getNodes().back()->getPosition()->getPathTo(endPos, nullptr); movePath = route.buildPath(beginPath, endPath); - if (sPlayerbotAIConfig->hasLog("bot_pathfinding.csv")) + if (sPlayerbotAIConfig.hasLog("bot_pathfinding.csv")) { if (botAI->HasStrategy("debug move", BOT_STATE_NON_COMBAT)) { - sPlayerbotAIConfig->openLog("bot_pathfinding.csv", "w"); - sPlayerbotAIConfig->log("bot_pathfinding.csv", movePath.print().str().c_str()); + sPlayerbotAIConfig.openLog("bot_pathfinding.csv", "w"); + sPlayerbotAIConfig.log("bot_pathfinding.csv", movePath.print().str().c_str()); } } - sTravelNodeMap->m_nMapMtx.unlock_shared(); + TravelNodeMap::instance().m_nMapMtx.unlock_shared(); return movePath; } @@ -1511,7 +1483,7 @@ TravelNode* TravelNodeMap::addZoneLinkNode(TravelNode* startNode) if (!getNode(pos, nullptr, 100.0f)) { std::string const nodeName = zoneName + " to " + newZoneName; - return sTravelNodeMap->addNode(pos, nodeName, false, true); + return TravelNodeMap::instance().addNode(pos, nodeName, false, true); } zoneName = newZoneName; @@ -1550,7 +1522,7 @@ TravelNode* TravelNodeMap::addRandomExtNode(TravelNode* startNode) WorldPosition point = path[urand(0, path.size() - 1)]; if (!getNode(point, nullptr, 100.0f)) - return sTravelNodeMap->addNode(point, startNode->getName(), false, true); + return TravelNodeMap::instance().addNode(point, startNode->getName(), false, true); } return nullptr; @@ -1606,7 +1578,7 @@ void TravelNodeMap::manageNodes(Unit* bot, bool mapFull) m_nMapMtx.unlock(); } - sTravelNodeMap->m_nMapMtx.lock_shared(); + TravelNodeMap::instance().m_nMapMtx.lock_shared(); if (!rePrint && mapFull) printMap(); @@ -1643,13 +1615,13 @@ void TravelNodeMap::generateNpcNodes() else if (cInfo->npcflag & UNIT_NPC_FLAG_SPIRITGUIDE) nodeName += " spiritguide"; - /*TravelNode* node = */ sTravelNodeMap->addNode(guidP, nodeName, true, true); //node not used, fragment marked for removal. + /*TravelNode* node = */ TravelNodeMap::instance().addNode(guidP, nodeName, true, true); //node not used, fragment marked for removal. } else if (cInfo->rank == 3) { std::string const nodeName = cInfo->Name; - sTravelNodeMap->addNode(guidP, nodeName, true, true); + TravelNodeMap::instance().addNode(guidP, nodeName, true, true); } else if (cInfo->rank == 1 && !guidP.isOverworld()) { @@ -1672,7 +1644,7 @@ void TravelNodeMap::generateNpcNodes() std::string const nodeName = cInfo->Name; - sTravelNodeMap->addNode(guidP, nodeName, true, true); + TravelNodeMap::instance().addNode(guidP, nodeName, true, true); } } @@ -1701,7 +1673,7 @@ void TravelNodeMap::generateStartNodes() std::string const nodeName = startNames[i] + " start"; - sTravelNodeMap->addNode(pos, nodeName, true, true); + TravelNodeMap::instance().addNode(pos, nodeName, true, true); break; } @@ -1733,7 +1705,7 @@ void TravelNodeMap::generateAreaTriggerNodes() else nodeName = inPos.getAreaName(false) + " portal"; - sTravelNodeMap->addNode(inPos, nodeName, true, true); + TravelNodeMap::instance().addNode(inPos, nodeName, true, true); } // Exit nodes @@ -1759,11 +1731,11 @@ void TravelNodeMap::generateAreaTriggerNodes() else nodeName = inPos.getAreaName(false) + " portal"; - //TravelNode* entryNode = sTravelNodeMap->getNode(outPos, nullptr, 20.0f); // Entry side, portal exit. //not used, line marked for removal. + //TravelNode* entryNode = TravelNodeMap::instance().getNode(outPos, nullptr, 20.0f); // Entry side, portal exit. //not used, line marked for removal. - TravelNode* outNode = sTravelNodeMap->addNode(outPos, nodeName, true, true); // Exit size, portal exit. + TravelNode* outNode = TravelNodeMap::instance().addNode(outPos, nodeName, true, true); // Exit size, portal exit. - TravelNode* inNode = sTravelNodeMap->getNode(inPos, nullptr, 5.0f); // Entry side, portal center. + TravelNode* inNode = TravelNodeMap::instance().getNode(inPos, nullptr, 5.0f); // Entry side, portal center. // Portal link from area trigger to area trigger destination. if (outNode && inNode) @@ -1826,7 +1798,7 @@ void TravelNodeMap::generateTransportNodes() if (pos.distance(&lPos) == 0) { TravelNode* node = - sTravelNodeMap->addNode(pos, data->name, true, true, true, itr.first); + TravelNodeMap::instance().addNode(pos, data->name, true, true, true, itr.first); if (!prevNode) { @@ -1866,7 +1838,7 @@ void TravelNodeMap::generateTransportNodes() if (pos.distance(&lPos) == 0) { TravelNode* node = - sTravelNodeMap->addNode(pos, data->name, true, true, true, itr.first); + TravelNodeMap::instance().addNode(pos, data->name, true, true, true, itr.first); if (node != prevNode) { if (p.second->TimeSeg < timeStart) @@ -1911,7 +1883,7 @@ void TravelNodeMap::generateTransportNodes() if (p->delay > 0) { - TravelNode* node = sTravelNodeMap->addNode(pos, data->name, true, true, true, itr.first); + TravelNode* node = TravelNodeMap::instance().addNode(pos, data->name, true, true, true, itr.first); if (!prevNode) { @@ -1946,7 +1918,7 @@ void TravelNodeMap::generateTransportNodes() if (p->delay > 0) { - TravelNode* node = sTravelNodeMap->getNode(pos, nullptr, 5.0f); + TravelNode* node = TravelNodeMap::instance().getNode(pos, nullptr, 5.0f); if (node != prevNode) { @@ -1968,7 +1940,7 @@ void TravelNodeMap::generateTransportNodes() void TravelNodeMap::generateZoneMeanNodes() { // Zone means - for (auto& loc : sTravelMgr->exploreLocs) + for (auto& loc : TravelMgr::instance().exploreLocs) { std::vector points; @@ -1981,7 +1953,7 @@ void TravelNodeMap::generateZoneMeanNodes() WorldPosition pos = WorldPosition(points, WP_MEAN_CENTROID); - /*TravelNode* node = */sTravelNodeMap->addNode(pos, pos.getAreaName(), true, true, false); //node not used, but addNode as side effect, fragment marked for removal. + /*TravelNode* node = */TravelNodeMap::instance().addNode(pos, pos.getAreaName(), true, true, false); //node not used, but addNode as side effect, fragment marked for removal. } } @@ -2006,19 +1978,19 @@ void TravelNodeMap::generateWalkPaths() std::map nodeMaps; - for (auto& startNode : sTravelNodeMap->getNodes()) + for (auto& startNode : TravelNodeMap::instance().getNodes()) { nodeMaps[startNode->getMapId()] = true; } for (auto& map : nodeMaps) { - for (auto& startNode : sTravelNodeMap->getNodes(WorldPosition(map.first, 1, 1))) + for (auto& startNode : TravelNodeMap::instance().getNodes(WorldPosition(map.first, 1, 1))) { if (startNode->isLinked()) continue; - for (auto& endNode : sTravelNodeMap->getNodes(*startNode->getPosition(), 2000.0f)) + for (auto& endNode : TravelNodeMap::instance().getNodes(*startNode->getPosition(), 2000.0f)) { if (startNode == endNode) continue; @@ -2036,7 +2008,7 @@ void TravelNodeMap::generateWalkPaths() } } - LOG_INFO("playerbots", ">> Generated paths for {} nodes.", sTravelNodeMap->getNodes().size()); + LOG_INFO("playerbots", ">> Generated paths for {} nodes.", TravelNodeMap::instance().getNodes().size()); } void TravelNodeMap::generateTaxiPaths() @@ -2066,8 +2038,8 @@ void TravelNodeMap::generateTaxiPaths() WorldPosition startPos(startTaxiNode->map_id, startTaxiNode->x, startTaxiNode->y, startTaxiNode->z); WorldPosition endPos(endTaxiNode->map_id, endTaxiNode->x, endTaxiNode->y, endTaxiNode->z); - TravelNode* startNode = sTravelNodeMap->getNode(startPos, nullptr, 15.0f); - TravelNode* endNode = sTravelNodeMap->getNode(endPos, nullptr, 15.0f); + TravelNode* startNode = TravelNodeMap::instance().getNode(startPos, nullptr, 15.0f); + TravelNode* endNode = TravelNodeMap::instance().getNode(endPos, nullptr, 15.0f); if (!startNode || !endNode) continue; @@ -2090,7 +2062,7 @@ void TravelNodeMap::removeLowNodes() { std::vector goodNodes; std::vector remNodes; - for (auto& node : sTravelNodeMap->getNodes()) + for (auto& node : TravelNodeMap::instance().getNodes()) { if (!node->getPosition()->isOverworld()) continue; @@ -2110,13 +2082,13 @@ void TravelNodeMap::removeLowNodes() } for (auto& node : remNodes) - sTravelNodeMap->removeNode(node); + TravelNodeMap::instance().removeNode(node); } void TravelNodeMap::removeUselessPaths() { // Clean up node links - for (auto& startNode : sTravelNodeMap->getNodes()) + for (auto& startNode : TravelNodeMap::instance().getNodes()) { for (auto& path : *startNode->getPaths()) if (path.second.getComplete() && startNode->hasLinkTo(path.first)) @@ -2127,7 +2099,7 @@ void TravelNodeMap::removeUselessPaths() { uint32 rem = 0; // Clean up node links - for (auto& startNode : sTravelNodeMap->getNodes()) + for (auto& startNode : TravelNodeMap::instance().getNodes()) { if (startNode->cropUselessLinks()) rem++; @@ -2146,7 +2118,7 @@ void TravelNodeMap::removeUselessPaths() void TravelNodeMap::calculatePathCosts() { - for (auto& startNode : sTravelNodeMap->getNodes()) + for (auto& startNode : TravelNodeMap::instance().getNodes()) { for (auto& path : *startNode->getLinks()) { @@ -2162,7 +2134,7 @@ void TravelNodeMap::calculatePathCosts() } } - LOG_INFO("playerbots", ">> Calculated pathcost for {} nodes.", sTravelNodeMap->getNodes().size()); + LOG_INFO("playerbots", ">> Calculated pathcost for {} nodes.", TravelNodeMap::instance().getNodes().size()); } void TravelNodeMap::generatePaths() @@ -2188,7 +2160,7 @@ void TravelNodeMap::generateAll() calcMapOffset(); LOG_INFO("playerbots", "-Generating maptransfers"); - sTravelMgr->loadMapTransfers(); + TravelMgr::instance().loadMapTransfers(); if (hasToGen || hasToFullGen) { @@ -2201,14 +2173,14 @@ void TravelNodeMap::generateAll() void TravelNodeMap::printMap() { - if (!sPlayerbotAIConfig->hasLog("travelNodes.csv") && !sPlayerbotAIConfig->hasLog("travelPaths.csv")) + if (!sPlayerbotAIConfig.hasLog("travelNodes.csv") && !sPlayerbotAIConfig.hasLog("travelPaths.csv")) return; printf("\r [Qgis] \r\x3D"); fflush(stdout); - sPlayerbotAIConfig->openLog("travelNodes.csv", "w"); - sPlayerbotAIConfig->openLog("travelPaths.csv", "w"); + sPlayerbotAIConfig.openLog("travelNodes.csv", "w"); + sPlayerbotAIConfig.openLog("travelPaths.csv", "w"); std::vector anodes = getNodes(); @@ -2224,26 +2196,26 @@ void TravelNodeMap::printNodeStore() { std::string const nodeStore = "TravelNodeStore.h"; - if (!sPlayerbotAIConfig->hasLog(nodeStore)) + if (!sPlayerbotAIConfig.hasLog(nodeStore)) return; printf("\r [Map] \r\x3D"); fflush(stdout); - sPlayerbotAIConfig->openLog(nodeStore, "w"); + sPlayerbotAIConfig.openLog(nodeStore, "w"); std::unordered_map saveNodes; std::vector anodes = getNodes(); - sPlayerbotAIConfig->log(nodeStore, "#pragma once"); - sPlayerbotAIConfig->log(nodeStore, "#include \"TravelMgr.h\""); - sPlayerbotAIConfig->log(nodeStore, "class TravelNodeStore"); - sPlayerbotAIConfig->log(nodeStore, " {"); - sPlayerbotAIConfig->log(nodeStore, " public:"); - sPlayerbotAIConfig->log(nodeStore, " static void loadNodes()"); - sPlayerbotAIConfig->log(nodeStore, " {"); - sPlayerbotAIConfig->log(nodeStore, " TravelNode** nodes = new TravelNode*[%zu];", anodes.size()); + sPlayerbotAIConfig.log(nodeStore, "#pragma once"); + sPlayerbotAIConfig.log(nodeStore, "#include \"TravelMgr.h\""); + sPlayerbotAIConfig.log(nodeStore, "class TravelNodeStore"); + sPlayerbotAIConfig.log(nodeStore, " {"); + sPlayerbotAIConfig.log(nodeStore, " public:"); + sPlayerbotAIConfig.log(nodeStore, " static void loadNodes()"); + sPlayerbotAIConfig.log(nodeStore, " {"); + sPlayerbotAIConfig.log(nodeStore, " TravelNode** nodes = new TravelNode*[%zu];", anodes.size()); for (uint32 i = 0; i < anodes.size(); i++) { @@ -2266,7 +2238,7 @@ void TravelNodeMap::printNodeStore() /* out << std::fixed << std::setprecision(2) << " nodes[" << i << "] = - sTravelNodeMap->addNode(&WorldPosition(" << node->getMapId() << "," << node->getX() << "f," << node->getY() + TravelNodeMap::instance().addNode(&WorldPosition(" << node->getMapId() << "," << node->getX() << "f," << node->getY() << "f," << node->getZ() << "f,"<< node->getO() <<"f), \"" << name << "\", " << (node->isImportant() ? "true" : "false") << ", true"; if (node->isTransport()) @@ -2274,7 +2246,7 @@ void TravelNodeMap::printNodeStore() out << ");"; */ - sPlayerbotAIConfig->log(nodeStore, out.str().c_str()); + sPlayerbotAIConfig.log(nodeStore, out.str().c_str()); saveNodes.insert(std::make_pair(node, i)); } @@ -2297,12 +2269,12 @@ void TravelNodeMap::printNodeStore() // out << std::fixed << std::setprecision(1) << " nodes[" << i << "]->setPathTo(nodes[" << // saveNodes.find(Link.first)->second << "],TravelNodePath("; out << Link.second->print() << "), true);"; - sPlayerbotAIConfig->log(nodeStore, out.str().c_str()); + sPlayerbotAIConfig.log(nodeStore, out.str().c_str()); } } - sPlayerbotAIConfig->log(nodeStore, " }"); - sPlayerbotAIConfig->log(nodeStore, "};"); + sPlayerbotAIConfig.log(nodeStore, " }"); + sPlayerbotAIConfig.log(nodeStore, "};"); printf("\r [Done] \r\x3D"); fflush(stdout); @@ -2322,7 +2294,7 @@ void TravelNodeMap::saveNodeStore() trans->Append(PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_DEL_TRAVELNODE_PATH)); std::unordered_map saveNodes; - std::vector anodes = sTravelNodeMap->getNodes(); + std::vector anodes = TravelNodeMap::instance().getNodes(); for (uint32 i = 0; i < anodes.size(); i++) { diff --git a/src/Mgr/Travel/TravelNode.h b/src/Mgr/Travel/TravelNode.h index 3a86cbb169..41419f8a97 100644 --- a/src/Mgr/Travel/TravelNode.h +++ b/src/Mgr/Travel/TravelNode.h @@ -477,13 +477,11 @@ class TravelNodeStub class TravelNodeMap { public: - TravelNodeMap(){}; - TravelNodeMap(TravelNodeMap* baseMap); - - static TravelNodeMap* instance() + static TravelNodeMap& instance() { static TravelNodeMap instance; - return &instance; + + return instance; } TravelNode* addNode(WorldPosition pos, std::string const preferedName = "Travel Node", bool isImportant = false, @@ -586,6 +584,15 @@ class TravelNodeMap std::unordered_map> teleportNodes; private: + TravelNodeMap() = default; + ~TravelNodeMap() = default; + + TravelNodeMap(const TravelNodeMap&) = delete; + TravelNodeMap& operator=(const TravelNodeMap&) = delete; + + TravelNodeMap(TravelNodeMap&&) = delete; + TravelNodeMap& operator=(TravelNodeMap&&) = delete; + std::vector m_nodes; std::vector> mapOffsets; diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index b9ef257d95..b511369484 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -660,25 +660,25 @@ bool PlayerbotAIConfig::Initialize() } // Assign account types after accounts are created - sRandomPlayerbotMgr->AssignAccountTypes(); + sRandomPlayerbotMgr.AssignAccountTypes(); - if (sPlayerbotAIConfig->enabled) + if (sPlayerbotAIConfig.enabled) { - sRandomPlayerbotMgr->Init(); + sRandomPlayerbotMgr.Init(); } - sPlayerbotGuildMgr->Init(); - sRandomItemMgr->Init(); - sRandomItemMgr->InitAfterAhBot(); - sPlayerbotTextMgr->LoadBotTexts(); - sPlayerbotTextMgr->LoadBotTextChance(); + PlayerbotGuildMgr::instance().Init(); + sRandomItemMgr.Init(); + sRandomItemMgr.InitAfterAhBot(); + PlayerbotTextMgr::instance().LoadBotTexts(); + PlayerbotTextMgr::instance().LoadBotTextChance(); PlayerbotFactory::Init(); AiObjectContext::BuildAllSharedContexts(); - if (sPlayerbotAIConfig->randomBotSuggestDungeons) + if (sPlayerbotAIConfig.randomBotSuggestDungeons) { - sPlayerbotDungeonRepository->LoadDungeonSuggestions(); + PlayerbotDungeonRepository::instance().LoadDungeonSuggestions(); } excludedHunterPetFamilies.clear(); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index fb112fc907..729fc5be16 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -8,11 +8,14 @@ #include #include +#include +#include +#include +#include +#include -#include "Common.h" #include "DBCEnums.h" #include "SharedDefines.h" -#include "Talentspec.h" enum class BotCheatMask : uint32 { @@ -62,11 +65,11 @@ enum NewRpgStatus : int class PlayerbotAIConfig { public: - PlayerbotAIConfig(){}; - static PlayerbotAIConfig* instance() + static PlayerbotAIConfig& instance() { static PlayerbotAIConfig instance; - return &instance; + + return instance; } bool Initialize(); @@ -449,6 +452,16 @@ class PlayerbotAIConfig bool IsRestrictedHealerDPSMap(uint32 mapId) const; std::vector excludedHunterPetFamilies; + +private: + PlayerbotAIConfig() = default; + ~PlayerbotAIConfig() = default; + + PlayerbotAIConfig(const PlayerbotAIConfig&) = delete; + PlayerbotAIConfig& operator=(const PlayerbotAIConfig&) = delete; + + PlayerbotAIConfig(PlayerbotAIConfig&&) = delete; + PlayerbotAIConfig& operator=(PlayerbotAIConfig&&) = delete; }; #define sPlayerbotAIConfig PlayerbotAIConfig::instance() diff --git a/src/Script/PlayerbotCommandScript.cpp b/src/Script/PlayerbotCommandScript.cpp index 4e3c5611f2..a7a0739528 100644 --- a/src/Script/PlayerbotCommandScript.cpp +++ b/src/Script/PlayerbotCommandScript.cpp @@ -76,33 +76,33 @@ class playerbots_commandscript : public CommandScript { if (!strcmp(args, "reset")) { - sPerfMonitor->Reset(); + sPerfMonitor.Reset(); return true; } if (!strcmp(args, "tick")) { - sPerfMonitor->PrintStats(true, false); + sPerfMonitor.PrintStats(true, false); return true; } if (!strcmp(args, "stack")) { - sPerfMonitor->PrintStats(false, true); + sPerfMonitor.PrintStats(false, true); return true; } if (!strcmp(args, "toggle")) { - sPlayerbotAIConfig->perfMonEnabled = !sPlayerbotAIConfig->perfMonEnabled; - if (sPlayerbotAIConfig->perfMonEnabled) + sPlayerbotAIConfig.perfMonEnabled = !sPlayerbotAIConfig.perfMonEnabled; + if (sPlayerbotAIConfig.perfMonEnabled) LOG_INFO("playerbots", "Performance monitor enabled"); else LOG_INFO("playerbots", "Performance monitor disabled"); return true; } - sPerfMonitor->PrintStats(); + sPerfMonitor.PrintStats(); return true; } @@ -122,7 +122,7 @@ class playerbots_commandscript : public CommandScript Player* player = handler->GetSession()->GetPlayer(); std::string key = args; - PlayerbotMgr* mgr = sPlayerbotsMgr->GetPlayerbotMgr(player); + PlayerbotMgr* mgr = PlayerbotsMgr::instance().GetPlayerbotMgr(player); if (mgr) { mgr->HandleSetSecurityKeyCommand(player, key); @@ -151,7 +151,7 @@ class playerbots_commandscript : public CommandScript Player* player = handler->GetSession()->GetPlayer(); - PlayerbotMgr* mgr = sPlayerbotsMgr->GetPlayerbotMgr(player); + PlayerbotMgr* mgr = PlayerbotsMgr::instance().GetPlayerbotMgr(player); if (mgr) { mgr->HandleLinkAccountCommand(player, accountName, key); @@ -168,7 +168,7 @@ class playerbots_commandscript : public CommandScript { Player* player = handler->GetSession()->GetPlayer(); - PlayerbotMgr* mgr = sPlayerbotsMgr->GetPlayerbotMgr(player); + PlayerbotMgr* mgr = PlayerbotsMgr::instance().GetPlayerbotMgr(player); if (mgr) { mgr->HandleViewLinkedAccountsCommand(player); @@ -195,7 +195,7 @@ class playerbots_commandscript : public CommandScript Player* player = handler->GetSession()->GetPlayer(); - PlayerbotMgr* mgr = sPlayerbotsMgr->GetPlayerbotMgr(player); + PlayerbotMgr* mgr = PlayerbotsMgr::instance().GetPlayerbotMgr(player); if (mgr) { mgr->HandleUnlinkAccountCommand(player, accountName); diff --git a/src/Script/Playerbots.cpp b/src/Script/Playerbots.cpp index 8a8e1e0b73..c4487f8986 100644 --- a/src/Script/Playerbots.cpp +++ b/src/Script/Playerbots.cpp @@ -22,7 +22,6 @@ #include "DatabaseEnv.h" #include "DatabaseLoader.h" #include "GuildTaskMgr.h" -#include "Metric.h" #include "PlayerScript.h" #include "PlayerbotAIConfig.h" #include "PlayerbotGuildMgr.h" @@ -98,24 +97,24 @@ class PlayerbotsPlayerScript : public PlayerScript { if (!player->GetSession()->IsBot()) { - sPlayerbotsMgr->AddPlayerbotData(player, false); - sRandomPlayerbotMgr->OnPlayerLogin(player); + PlayerbotsMgr::instance().AddPlayerbotData(player, false); + sRandomPlayerbotMgr.OnPlayerLogin(player); // Before modifying the following messages, please make sure it does not violate the AGPLv3.0 license // especially if you are distributing a repack or hosting a public server // e.g. you can replace the URL with your own repository, // but it should be publicly accessible and include all modifications you've made - if (sPlayerbotAIConfig->enabled) + if (sPlayerbotAIConfig.enabled) { ChatHandler(player->GetSession()).SendSysMessage( "|cff00ff00This server runs with |cff00ccffmod-playerbots|r " "|cffcccccchttps://github.com/mod-playerbots/mod-playerbots|r"); } - if (sPlayerbotAIConfig->enabled || sPlayerbotAIConfig->randomBotAutologin) + if (sPlayerbotAIConfig.enabled || sPlayerbotAIConfig.randomBotAutologin) { std::string roundedTime = - std::to_string(std::ceil((sPlayerbotAIConfig->maxRandomBots * 0.11 / 60) * 10) / 10.0); + std::to_string(std::ceil((sPlayerbotAIConfig.maxRandomBots * 0.11 / 60) * 10) / 10.0); roundedTime = roundedTime.substr(0, roundedTime.find('.') + 2); ChatHandler(player->GetSession()).SendSysMessage( @@ -125,7 +124,8 @@ class PlayerbotsPlayerScript : public PlayerScript } } - bool OnPlayerBeforeTeleport(Player* /*player*/, uint32 /*mapid*/, float /*x*/, float /*y*/, float /*z*/, float /*orientation*/, uint32 /*options*/, Unit* /*target*/) override + bool OnPlayerBeforeTeleport(Player* /*player*/, uint32 /*mapid*/, float /*x*/, float /*y*/, float /*z*/, + float /*orientation*/, uint32 /*options*/, Unit* /*target*/) override { /* for now commmented out until proven its actually required * havent seen any proof CleanVisibilityReferences() is needed @@ -172,7 +172,9 @@ class PlayerbotsPlayerScript : public PlayerScript void OnPlayerAfterUpdate(Player* player, uint32 diff) override { - if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(player)) + PlayerbotAI* const botAI = PlayerbotsMgr::instance().GetPlayerbotAI(player); + + if (botAI != nullptr) { botAI->UpdateAI(diff); } @@ -185,19 +187,26 @@ class PlayerbotsPlayerScript : public PlayerScript bool OnPlayerCanUseChat(Player* player, uint32 type, uint32 /*lang*/, std::string& msg, Player* receiver) override { - if (type == CHAT_MSG_WHISPER) + if (type != CHAT_MSG_WHISPER) { - if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(receiver)) - { - botAI->HandleCommand(type, msg, player); + return true; + } - // hotfix; otherwise the server will crash when whispering logout - // https://github.com/mod-playerbots/mod-playerbots/pull/1838 - // TODO: find the root cause and solve it. (does not happen in party chat) - if (msg == "logout") - return false; - } + PlayerbotAI* const botAI = PlayerbotsMgr::instance().GetPlayerbotAI(receiver); + + if (botAI == nullptr) + { + return true; } + + botAI->HandleCommand(type, msg, player); + + // hotfix; otherwise the server will crash when whispering logout + // https://github.com/mod-playerbots/mod-playerbots/pull/1838 + // TODO: find the root cause and solve it. (does not happen in party chat) + if (msg == "logout") + return false; + return true; } @@ -205,56 +214,77 @@ class PlayerbotsPlayerScript : public PlayerScript { for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) { - if (Player* member = itr->GetSource()) + Player* const member = itr->GetSource(); + + if (member == nullptr) { - if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(member)) - { - botAI->HandleCommand(type, msg, player); - } + continue; + } + + PlayerbotAI* const botAI = PlayerbotsMgr::instance().GetPlayerbotAI(member); + + if (botAI == nullptr) + { + continue; } + + botAI->HandleCommand(type, msg, player); } + return true; } bool OnPlayerCanUseChat(Player* player, uint32 type, uint32 /*lang*/, std::string& msg, Guild* guild) override { - if (type == CHAT_MSG_GUILD) + if (type != CHAT_MSG_GUILD) { - if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player)) + return true; + } + + PlayerbotMgr* playerbotMgr = PlayerbotsMgr::instance().GetPlayerbotMgr(player); + + if (playerbotMgr == nullptr) + { + return true; + } + + for (PlayerBotMap::const_iterator it = playerbotMgr->GetPlayerBotsBegin(); it != playerbotMgr->GetPlayerBotsEnd(); ++it) + { + Player* const bot = it->second; + + if (bot == nullptr) { - for (PlayerBotMap::const_iterator it = playerbotMgr->GetPlayerBotsBegin(); - it != playerbotMgr->GetPlayerBotsEnd(); ++it) - { - if (Player* const bot = it->second) - { - if (bot->GetGuildId() == player->GetGuildId()) - { - GET_PLAYERBOT_AI(bot)->HandleCommand(type, msg, player); - } - } - } + continue; + } + + if (bot->GetGuildId() != player->GetGuildId()) + { + continue; } + + PlayerbotsMgr::instance().GetPlayerbotAI(bot)->HandleCommand(type, msg, player); } + return true; } bool OnPlayerCanUseChat(Player* player, uint32 type, uint32 /*lang*/, std::string& msg, Channel* channel) override { - if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player)) + PlayerbotMgr* const playerbotMgr = PlayerbotsMgr::instance().GetPlayerbotMgr(player); + + if (playerbotMgr != nullptr && channel->GetFlags() & 0x18) { - if (channel->GetFlags() & 0x18) - { - playerbotMgr->HandleCommand(type, msg); - } + playerbotMgr->HandleCommand(type, msg); } - sRandomPlayerbotMgr->HandleCommand(type, msg, player); + sRandomPlayerbotMgr.HandleCommand(type, msg, player); + return true; } bool OnPlayerBeforeAchievementComplete(Player* player, AchievementEntry const* achievement) override { - if ((sRandomPlayerbotMgr->IsRandomBot(player) || sRandomPlayerbotMgr->IsAddclassBot(player)) && + if ((sRandomPlayerbotMgr.IsRandomBot(player) || sRandomPlayerbotMgr.IsAddclassBot(player)) && (achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL))) { return false; @@ -266,11 +296,11 @@ class PlayerbotsPlayerScript : public PlayerScript void OnPlayerGiveXP(Player* player, uint32& amount, Unit* /*victim*/, uint8 /*xpSource*/) override { // early return - if (sPlayerbotAIConfig->randomBotXPRate == 1.0 || !player) + if (sPlayerbotAIConfig.randomBotXPRate == 1.0 || !player) return; // no XP multiplier, when player is no bot. - if (!player->GetSession()->IsBot() || !sRandomPlayerbotMgr->IsRandomBot(player)) + if (!player->GetSession()->IsBot() || !sRandomPlayerbotMgr.IsRandomBot(player)) return; // no XP multiplier, when bot is in a group with a real player. @@ -292,7 +322,7 @@ class PlayerbotsPlayerScript : public PlayerScript } // otherwise apply bot XP multiplier. - amount = static_cast(std::round(static_cast(amount) * sPlayerbotAIConfig->randomBotXPRate)); + amount = static_cast(std::round(static_cast(amount) * sPlayerbotAIConfig.randomBotXPRate)); } }; @@ -303,7 +333,9 @@ class PlayerbotsMiscScript : public MiscScript void OnDestructPlayer(Player* player) override { - if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(player)) + PlayerbotAI* botAI = PlayerbotsMgr::instance().GetPlayerbotAI(player); + + if (botAI != nullptr) { delete botAI; } @@ -360,20 +392,20 @@ class PlayerbotsWorldScript : public WorldScript LOG_INFO("server.loading", " "); LOG_INFO("server.loading", "Load Playerbots Config..."); - sPlayerbotAIConfig->Initialize(); + sPlayerbotAIConfig.Initialize(); LOG_INFO("server.loading", ">> Loaded playerbots config in {} ms", GetMSTimeDiffToNow(oldMSTime)); LOG_INFO("server.loading", " "); - sPlayerbotSpellRepository->Initialize(); + PlayerbotSpellRepository::Instance().Initialize(); LOG_INFO("server.loading", "Playerbots World Thread Processor initialized"); } void OnUpdate(uint32 diff) override { - sPlayerbotWorldProcessor->Update(diff); - sRandomPlayerbotMgr->UpdateAI(diff); // World thread only + PlayerbotWorldThreadProcessor::instance().Update(diff); + sRandomPlayerbotMgr.UpdateAI(diff); // World thread only } }; @@ -385,10 +417,12 @@ class PlayerbotsScript : public PlayerbotScript bool OnPlayerbotCheckLFGQueue(lfg::Lfg5Guids const& guidsList) override { bool nonBotFound = false; + for (ObjectGuid const& guid : guidsList.guids) { Player* player = ObjectAccessor::FindPlayer(guid); - if (guid.IsGroup() || (player && !GET_PLAYERBOT_AI(player))) + + if (guid.IsGroup() || (player && !PlayerbotsMgr::instance().GetPlayerbotAI(player))) { nonBotFound = true; break; @@ -401,32 +435,48 @@ class PlayerbotsScript : public PlayerbotScript void OnPlayerbotCheckKillTask(Player* player, Unit* victim) override { if (player) - sGuildTaskMgr->CheckKillTask(player, victim); + GuildTaskMgr::instance().CheckKillTask(player, victim); } void OnPlayerbotCheckPetitionAccount(Player* player, bool& found) override { - if (found && GET_PLAYERBOT_AI(player)) + if (!found) + { + return; + } + + if (PlayerbotsMgr::instance().GetPlayerbotAI(player) != nullptr) + { found = false; + } } bool OnPlayerbotCheckUpdatesToSend(Player* player) override { - if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(player)) - return botAI->IsRealPlayer(); + PlayerbotAI* botAI = PlayerbotsMgr::instance().GetPlayerbotAI(player); - return true; + if (botAI == nullptr) + { + return true; + } + + return botAI->IsRealPlayer(); } void OnPlayerbotPacketSent(Player* player, WorldPacket const* packet) override { - if (!player) + if (player == nullptr) + { return; + } + + PlayerbotAI* botAI = PlayerbotsMgr::instance().GetPlayerbotAI(player); - if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(player)) + if (botAI != nullptr) { botAI->HandleBotOutgoingPacket(*packet); } + if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player)) { playerbotMgr->HandleMasterOutgoingPacket(*packet); @@ -435,7 +485,7 @@ class PlayerbotsScript : public PlayerbotScript void OnPlayerbotUpdate(uint32 diff) override { - sRandomPlayerbotMgr->UpdateSessions(); // Per-bot updates only + sRandomPlayerbotMgr.UpdateSessions(); // Per-bot updates only } void OnPlayerbotUpdateSessions(Player* player) override @@ -449,20 +499,21 @@ class PlayerbotsScript : public PlayerbotScript { if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player)) { - PlayerbotAI* botAI = GET_PLAYERBOT_AI(player); - if (!botAI || botAI->IsRealPlayer()) + PlayerbotAI* botAI = PlayerbotsMgr::instance().GetPlayerbotAI(player); + + if (botAI == nullptr || botAI->IsRealPlayer()) { playerbotMgr->LogoutAllBots(); } } - sRandomPlayerbotMgr->OnPlayerLogout(player); + sRandomPlayerbotMgr.OnPlayerLogout(player); } void OnPlayerbotLogoutBots() override { LOG_INFO("playerbots", "Logging out all bots..."); - sRandomPlayerbotMgr->LogoutAllBots(); + sRandomPlayerbotMgr.LogoutAllBots(); } }; diff --git a/src/Script/Playerbots.h b/src/Script/Playerbots.h index 72ea9e4f79..006f058f9d 100644 --- a/src/Script/Playerbots.h +++ b/src/Script/Playerbots.h @@ -27,8 +27,8 @@ int strcmpi(char const* s1, char const* s2); #define CAST_ANGLE_IN_FRONT (2.f * static_cast(M_PI) / 3.f) #define EMOTE_ANGLE_IN_FRONT (2.f * static_cast(M_PI) / 6.f) -#define GET_PLAYERBOT_AI(object) sPlayerbotsMgr->GetPlayerbotAI(object) -#define GET_PLAYERBOT_MGR(object) sPlayerbotsMgr->GetPlayerbotMgr(object) +#define GET_PLAYERBOT_AI(object) sPlayerbotsMgr.GetPlayerbotAI(object) +#define GET_PLAYERBOT_MGR(object) sPlayerbotsMgr.GetPlayerbotMgr(object) #define AI_VALUE(type, name) context->GetValue(name)->Get() #define AI_VALUE2(type, name, param) context->GetValue(name, param)->Get() @@ -43,10 +43,10 @@ int strcmpi(char const* s1, char const* s2); #define RESET_AI_VALUE(type, name) context->GetValue(name)->Reset() #define RESET_AI_VALUE2(type, name, param) context->GetValue(name, param)->Reset() -#define PAI_VALUE(type, name) sPlayerbotsMgr->GetPlayerbotAI(player)->GetAiObjectContext()->GetValue(name)->Get() +#define PAI_VALUE(type, name) sPlayerbotsMgr.GetPlayerbotAI(player)->GetAiObjectContext()->GetValue(name)->Get() #define PAI_VALUE2(type, name, param) \ - sPlayerbotsMgr->GetPlayerbotAI(player)->GetAiObjectContext()->GetValue(name, param)->Get() -#define GAI_VALUE(type, name) sSharedValueContext->getGlobalValue(name)->Get() -#define GAI_VALUE2(type, name, param) sSharedValueContext->getGlobalValue(name, param)->Get() + sPlayerbotsMgr.GetPlayerbotAI(player)->GetAiObjectContext()->GetValue(name, param)->Get() +#define GAI_VALUE(type, name) sSharedValueContext.getGlobalValue(name)->Get() +#define GAI_VALUE2(type, name, param) sSharedValueContext.getGlobalValue(name, param)->Get() #endif diff --git a/src/Script/PlayerbotsSecureLogin.cpp b/src/Script/PlayerbotsSecureLogin.cpp index aa5d103d58..fc54a82b7d 100644 --- a/src/Script/PlayerbotsSecureLogin.cpp +++ b/src/Script/PlayerbotsSecureLogin.cpp @@ -29,6 +29,7 @@ namespace return; PlayerbotAI* ai = GET_PLAYERBOT_AI(target); + if (!ai) return; @@ -41,11 +42,7 @@ namespace } } - if (sRandomPlayerbotMgr) - { - sRandomPlayerbotMgr->LogoutPlayerBot(target->GetGUID()); - return; - } + sRandomPlayerbotMgr.LogoutPlayerBot(target->GetGUID()); } } diff --git a/src/Script/WorldThr/PlayerbotOperations.h b/src/Script/WorldThr/PlayerbotOperations.h index cd8851902c..a80321d535 100644 --- a/src/Script/WorldThr/PlayerbotOperations.h +++ b/src/Script/WorldThr/PlayerbotOperations.h @@ -355,7 +355,7 @@ class ArenaGroupFormationOperation : public PlayerbotOperation if (!member || !newGroup->IsMember(memberGuid)) continue; - PlayerbotAI* memberBotAI = sPlayerbotsMgr->GetPlayerbotAI(member); + PlayerbotAI* memberBotAI = PlayerbotsMgr::instance().GetPlayerbotAI(member); if (memberBotAI) memberBotAI->Reset(); @@ -412,13 +412,13 @@ class BotLogoutGroupCleanupOperation : public PlayerbotOperation if (!bot) return false; - PlayerbotAI* botAI = sPlayerbotsMgr->GetPlayerbotAI(bot); + PlayerbotAI* botAI = PlayerbotsMgr::instance().GetPlayerbotAI(bot); if (!botAI) return false; Group* group = bot->GetGroup(); if (group && !bot->InBattleground() && !bot->InBattlegroundQueue() && botAI->HasActivePlayerMaster()) - sPlayerbotRepository->Save(botAI); + PlayerbotRepository::instance().Save(botAI); return true; } @@ -448,7 +448,7 @@ class AddPlayerBotOperation : public PlayerbotOperation bool Execute() override { - sRandomPlayerbotMgr->AddPlayerBot(m_botGuid, m_masterAccountId); + sRandomPlayerbotMgr.AddPlayerBot(m_botGuid, m_masterAccountId); return true; } @@ -483,13 +483,13 @@ class OnBotLoginOperation : public PlayerbotOperation if (!bot) return false; - PlayerbotHolder* holder = sRandomPlayerbotMgr; + PlayerbotHolder* holder = &RandomPlayerbotMgr::instance(); if (m_masterAccountId) { WorldSession* masterSession = sWorldSessionMgr->FindSession(m_masterAccountId); Player* masterPlayer = masterSession ? masterSession->GetPlayer() : nullptr; if (masterPlayer) - holder = GET_PLAYERBOT_MGR(masterPlayer); + holder = PlayerbotsMgr::instance().GetPlayerbotMgr(masterPlayer); } if (!holder) diff --git a/src/Script/WorldThr/PlayerbotWorldThreadProcessor.cpp b/src/Script/WorldThr/PlayerbotWorldThreadProcessor.cpp index c776eb1207..3679d3169a 100644 --- a/src/Script/WorldThr/PlayerbotWorldThreadProcessor.cpp +++ b/src/Script/WorldThr/PlayerbotWorldThreadProcessor.cpp @@ -3,27 +3,12 @@ * and/or modify it under version 3 of the License, or (at your option), any later version. */ -#include "PlayerbotWorldThreadProcessor.h" - -#include "Log.h" -#include "PlayerbotAIConfig.h" - #include -PlayerbotWorldThreadProcessor::PlayerbotWorldThreadProcessor() - : m_enabled(true), m_maxQueueSize(10000), m_batchSize(100), m_queueWarningThreshold(80), - m_timeSinceLastUpdate(0), m_updateInterval(50) // Process at least every 50ms -{ - LOG_INFO("playerbots", "PlayerbotWorldThreadProcessor initialized"); -} - -PlayerbotWorldThreadProcessor::~PlayerbotWorldThreadProcessor() { ClearQueue(); } +#include "PlayerbotWorldThreadProcessor.h" -PlayerbotWorldThreadProcessor* PlayerbotWorldThreadProcessor::instance() -{ - static PlayerbotWorldThreadProcessor instance; - return &instance; -} +#include "Timer.h" +#include "Log.h" void PlayerbotWorldThreadProcessor::Update(uint32 diff) { diff --git a/src/Script/WorldThr/PlayerbotWorldThreadProcessor.h b/src/Script/WorldThr/PlayerbotWorldThreadProcessor.h index e37d2b5ba5..e975b8fbdb 100644 --- a/src/Script/WorldThr/PlayerbotWorldThreadProcessor.h +++ b/src/Script/WorldThr/PlayerbotWorldThreadProcessor.h @@ -6,13 +6,14 @@ #ifndef _PLAYERBOT_WORLD_THREAD_PROCESSOR_H #define _PLAYERBOT_WORLD_THREAD_PROCESSOR_H -#include "Common.h" -#include "PlayerbotOperation.h" - #include #include #include +#include "Log.h" + +#include "PlayerbotOperation.h" + /** * @brief Processes thread-unsafe bot operations in the world thread * @@ -28,15 +29,17 @@ * * Usage: * auto op = std::make_unique(botGuid, params); - * sPlayerbotWorldProcessor->QueueOperation(std::move(op)); + * PlayerbotWorldThreadProcessor::instance().QueueOperation(std::move(op)); */ class PlayerbotWorldThreadProcessor { public: - PlayerbotWorldThreadProcessor(); - ~PlayerbotWorldThreadProcessor(); + static PlayerbotWorldThreadProcessor& instance() + { + static PlayerbotWorldThreadProcessor instance; - static PlayerbotWorldThreadProcessor* instance(); + return instance; + } /** * @brief Update and process queued operations (called from world thread) @@ -103,6 +106,21 @@ class PlayerbotWorldThreadProcessor bool IsEnabled() const { return m_enabled; } private: + PlayerbotWorldThreadProcessor() + : m_enabled(true), + m_maxQueueSize(10000), + m_batchSize(100), + m_queueWarningThreshold(80), + m_timeSinceLastUpdate(0), + m_updateInterval(50) // Process at least every 50ms + { + LOG_INFO("playerbots", "PlayerbotWorldThreadProcessor initialized"); + } + ~PlayerbotWorldThreadProcessor() + { + this->ClearQueue(); + } + /** * @brief Process a single batch of operations * @@ -137,6 +155,4 @@ class PlayerbotWorldThreadProcessor uint32 m_updateInterval; // Minimum ms between updates }; -#define sPlayerbotWorldProcessor PlayerbotWorldThreadProcessor::instance() - #endif diff --git a/src/Script/WorldThr/Queue.cpp b/src/Script/WorldThr/Queue.cpp index 136e1b4381..43b1597f88 100644 --- a/src/Script/WorldThr/Queue.cpp +++ b/src/Script/WorldThr/Queue.cpp @@ -50,7 +50,7 @@ uint32 Queue::Size() void Queue::RemoveExpired() { - if (!sPlayerbotAIConfig->expireActionTime) + if (!sPlayerbotAIConfig.expireActionTime) { return; } @@ -113,7 +113,7 @@ ActionNode* Queue::extractAndDeleteBasket(ActionBasket* basket) void Queue::collectExpiredBaskets(std::list& expiredBaskets) { - uint32 expiryTime = sPlayerbotAIConfig->expireActionTime; + uint32 expiryTime = sPlayerbotAIConfig.expireActionTime; for (ActionBasket* basket : actions) { if (basket->isExpired(expiryTime)) diff --git a/src/Script/WorldThr/Queue.h b/src/Script/WorldThr/Queue.h index b8a486dc85..439b61aa0e 100644 --- a/src/Script/WorldThr/Queue.h +++ b/src/Script/WorldThr/Queue.h @@ -56,7 +56,7 @@ class Queue /** * @brief Removes and deletes expired actions from the queue * - * Uses sPlayerbotAIConfig->expireActionTime to determine if actions have expired. + * Uses sPlayerbotAIConfig.expireActionTime to determine if actions have expired. * Both the ActionNode and ActionBasket are deleted for expired actions. */ void RemoveExpired(); diff --git a/src/Util/BroadcastHelper.cpp b/src/Util/BroadcastHelper.cpp index 19979d3d9f..246344bdaf 100644 --- a/src/Util/BroadcastHelper.cpp +++ b/src/Util/BroadcastHelper.cpp @@ -28,29 +28,29 @@ bool BroadcastHelper::BroadcastTest(PlayerbotAI* ai, Player* /* bot */) int32 rand = urand(0, 1); - if (rand == 1 && ai->SayToChannel(BOT_TEXT2("Posted to trade, %rand1, %rand2, %rand3", placeholders), ChatChannelId::TRADE)) + if (rand == 1 && ai->SayToChannel(PlayerbotTextMgr::instance().GetBotText("Posted to trade, %rand1, %rand2, %rand3", placeholders), ChatChannelId::TRADE)) return true; - else if (ai->SayToChannel(BOT_TEXT2("Posted to GuildRecruitment, %rand1, %rand2, %rand3", placeholders), ChatChannelId::GUILD_RECRUITMENT)) + else if (ai->SayToChannel(PlayerbotTextMgr::instance().GetBotText("Posted to GuildRecruitment, %rand1, %rand2, %rand3", placeholders), ChatChannelId::GUILD_RECRUITMENT)) return true; - return ai->SayToChannel(BOT_TEXT2("Posted to trade, %rand1, %rand2, %rand3", placeholders), ChatChannelId::TRADE); + return ai->SayToChannel(PlayerbotTextMgr::instance().GetBotText("Posted to trade, %rand1, %rand2, %rand3", placeholders), ChatChannelId::TRADE); //int32 rand = urand(1, 8); - if (rand == 1 && ai->SayToGuild(BOT_TEXT2("Posted to guild, %rand1, %rand2, %rand3", placeholders))) + if (rand == 1 && ai->SayToGuild(PlayerbotTextMgr::instance().GetBotText("Posted to guild, %rand1, %rand2, %rand3", placeholders))) return true; - else if (rand == 2 && ai->SayToWorld(BOT_TEXT2("Posted to world, %rand1, %rand2, %rand3", placeholders))) + else if (rand == 2 && ai->SayToWorld(PlayerbotTextMgr::instance().GetBotText("Posted to world, %rand1, %rand2, %rand3", placeholders))) return true; - else if (rand == 3 && ai->SayToChannel(BOT_TEXT2("Posted to general, %rand1, %rand2, %rand3", placeholders), ChatChannelId::GENERAL)) + else if (rand == 3 && ai->SayToChannel(PlayerbotTextMgr::instance().GetBotText("Posted to general, %rand1, %rand2, %rand3", placeholders), ChatChannelId::GENERAL)) return true; - else if (rand == 4 && ai->SayToChannel(BOT_TEXT2("Posted to trade, %rand1, %rand2, %rand3", placeholders), ChatChannelId::TRADE)) + else if (rand == 4 && ai->SayToChannel(PlayerbotTextMgr::instance().GetBotText("Posted to trade, %rand1, %rand2, %rand3", placeholders), ChatChannelId::TRADE)) return true; - else if (rand == 5 && ai->SayToChannel(BOT_TEXT2("Posted to LFG, %rand1, %rand2, %rand3", placeholders), ChatChannelId::LOOKING_FOR_GROUP)) + else if (rand == 5 && ai->SayToChannel(PlayerbotTextMgr::instance().GetBotText("Posted to LFG, %rand1, %rand2, %rand3", placeholders), ChatChannelId::LOOKING_FOR_GROUP)) return true; - else if (rand == 6 && ai->SayToChannel(BOT_TEXT2("Posted to LocalDefense, %rand1, %rand2, %rand3", placeholders), ChatChannelId::LOCAL_DEFENSE)) + else if (rand == 6 && ai->SayToChannel(PlayerbotTextMgr::instance().GetBotText("Posted to LocalDefense, %rand1, %rand2, %rand3", placeholders), ChatChannelId::LOCAL_DEFENSE)) return true; - else if (rand == 7 && ai->SayToChannel(BOT_TEXT2("Posted to WorldDefense, %rand1, %rand2, %rand3", placeholders), ChatChannelId::WORLD_DEFENSE)) + else if (rand == 7 && ai->SayToChannel(PlayerbotTextMgr::instance().GetBotText("Posted to WorldDefense, %rand1, %rand2, %rand3", placeholders), ChatChannelId::WORLD_DEFENSE)) return true; - else if (rand == 8 && ai->SayToChannel(BOT_TEXT2("Posted to GuildRecruitment, %rand1, %rand2, %rand3", placeholders), ChatChannelId::GUILD_RECRUITMENT)) + else if (rand == 8 && ai->SayToChannel(PlayerbotTextMgr::instance().GetBotText("Posted to GuildRecruitment, %rand1, %rand2, %rand3", placeholders), ChatChannelId::GUILD_RECRUITMENT)) return true; return false; @@ -63,7 +63,7 @@ bool BroadcastHelper::BroadcastTest(PlayerbotAI* ai, Player* /* bot */) */ bool BroadcastHelper::BroadcastToChannelWithGlobalChance(PlayerbotAI* ai, std::string message, std::list> toChannels) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; if (message.empty()) { @@ -74,14 +74,14 @@ bool BroadcastHelper::BroadcastToChannelWithGlobalChance(PlayerbotAI* ai, std::s { uint32 roll = urand(1, 100); uint32 chance = pair.second; - uint32 broadcastRoll = urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue); + uint32 broadcastRoll = urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue); switch (pair.first) { case TO_GUILD: { if (roll <= chance - && broadcastRoll <= sPlayerbotAIConfig->broadcastToGuildGlobalChance + && broadcastRoll <= sPlayerbotAIConfig.broadcastToGuildGlobalChance && ai->SayToGuild(message)) { return true; @@ -91,7 +91,7 @@ bool BroadcastHelper::BroadcastToChannelWithGlobalChance(PlayerbotAI* ai, std::s case TO_WORLD: { if (roll <= chance - && broadcastRoll <= sPlayerbotAIConfig->broadcastToWorldGlobalChance + && broadcastRoll <= sPlayerbotAIConfig.broadcastToWorldGlobalChance && ai->SayToWorld(message)) { return true; @@ -101,7 +101,7 @@ bool BroadcastHelper::BroadcastToChannelWithGlobalChance(PlayerbotAI* ai, std::s case TO_GENERAL: { if (roll <= chance - && broadcastRoll <= sPlayerbotAIConfig->broadcastToGeneralGlobalChance + && broadcastRoll <= sPlayerbotAIConfig.broadcastToGeneralGlobalChance && ai->SayToChannel(message, ChatChannelId::GENERAL)) { return true; @@ -111,7 +111,7 @@ bool BroadcastHelper::BroadcastToChannelWithGlobalChance(PlayerbotAI* ai, std::s case TO_TRADE: { if (roll <= chance - && broadcastRoll <= sPlayerbotAIConfig->broadcastToTradeGlobalChance + && broadcastRoll <= sPlayerbotAIConfig.broadcastToTradeGlobalChance && ai->SayToChannel(message, ChatChannelId::TRADE)) { return true; @@ -121,7 +121,7 @@ bool BroadcastHelper::BroadcastToChannelWithGlobalChance(PlayerbotAI* ai, std::s case TO_LOOKING_FOR_GROUP: { if (roll <= chance - && broadcastRoll <= sPlayerbotAIConfig->broadcastToLFGGlobalChance + && broadcastRoll <= sPlayerbotAIConfig.broadcastToLFGGlobalChance && ai->SayToChannel(message, ChatChannelId::LOOKING_FOR_GROUP)) { return true; @@ -131,7 +131,7 @@ bool BroadcastHelper::BroadcastToChannelWithGlobalChance(PlayerbotAI* ai, std::s case TO_LOCAL_DEFENSE: { if (roll <= chance - && broadcastRoll <= sPlayerbotAIConfig->broadcastToLocalDefenseGlobalChance + && broadcastRoll <= sPlayerbotAIConfig.broadcastToLocalDefenseGlobalChance && ai->SayToChannel(message, ChatChannelId::LOCAL_DEFENSE)) { return true; @@ -141,7 +141,7 @@ bool BroadcastHelper::BroadcastToChannelWithGlobalChance(PlayerbotAI* ai, std::s case TO_WORLD_DEFENSE: { if (roll <= chance - && broadcastRoll <= sPlayerbotAIConfig->broadcastToWorldDefenseGlobalChance + && broadcastRoll <= sPlayerbotAIConfig.broadcastToWorldDefenseGlobalChance && ai->SayToChannel(message, ChatChannelId::WORLD_DEFENSE)) { return true; @@ -151,7 +151,7 @@ bool BroadcastHelper::BroadcastToChannelWithGlobalChance(PlayerbotAI* ai, std::s case TO_GUILD_RECRUITMENT: { if (roll <= chance - && broadcastRoll <= sPlayerbotAIConfig->broadcastToGuildRecruitmentGlobalChance + && broadcastRoll <= sPlayerbotAIConfig.broadcastToGuildRecruitmentGlobalChance && ai->SayToChannel(message, ChatChannelId::GUILD_RECRUITMENT)) { return true; @@ -168,14 +168,14 @@ bool BroadcastHelper::BroadcastToChannelWithGlobalChance(PlayerbotAI* ai, std::s bool BroadcastHelper::BroadcastLootingItem(PlayerbotAI* ai, Player* bot, ItemTemplate const* proto) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; std::map placeholders; placeholders["%item_link"] = ai->GetChatHelper()->FormatItem(proto); AreaTableEntry const* current_area = ai->GetCurrentArea(); AreaTableEntry const* current_zone = ai->GetCurrentZone(); - placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); - placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); placeholders["%my_level"] = std::to_string(bot->GetLevel()); @@ -183,71 +183,71 @@ bool BroadcastHelper::BroadcastLootingItem(PlayerbotAI* ai, Player* bot, ItemTem switch (proto->Quality) { case ITEM_QUALITY_POOR: - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemPoor) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceLootingItemPoor) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_looting_item_poor", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_looting_item_poor", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } break; case ITEM_QUALITY_NORMAL: - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemNormal) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceLootingItemNormal) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_looting_item_normal", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_looting_item_normal", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } break; case ITEM_QUALITY_UNCOMMON: - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemUncommon) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceLootingItemUncommon) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_looting_item_uncommon", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_looting_item_uncommon", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } break; case ITEM_QUALITY_RARE: - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemRare) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceLootingItemRare) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_looting_item_rare", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_looting_item_rare", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } break; case ITEM_QUALITY_EPIC: - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemEpic) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceLootingItemEpic) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_looting_item_epic", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_looting_item_epic", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } break; case ITEM_QUALITY_LEGENDARY: - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemLegendary) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceLootingItemLegendary) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_looting_item_legendary", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_looting_item_legendary", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } break; case ITEM_QUALITY_ARTIFACT: - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemArtifact) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceLootingItemArtifact) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_looting_item_artifact", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_looting_item_artifact", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } @@ -261,23 +261,23 @@ bool BroadcastHelper::BroadcastLootingItem(PlayerbotAI* ai, Player* bot, ItemTem bool BroadcastHelper::BroadcastQuestAccepted(PlayerbotAI* ai, Player* bot, const Quest* quest) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestAccepted) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceQuestAccepted) { std::map placeholders; placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest); AreaTableEntry const* current_area = ai->GetCurrentArea(); AreaTableEntry const* current_zone = ai->GetCurrentZone(); - placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); - placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); placeholders["%my_level"] = std::to_string(bot->GetLevel()); return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_quest_accepted_generic", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_quest_accepted_generic", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } @@ -287,13 +287,13 @@ bool BroadcastHelper::BroadcastQuestAccepted(PlayerbotAI* ai, Player* bot, const bool BroadcastHelper::BroadcastQuestUpdateAddKill(PlayerbotAI* ai, Player* bot, Quest const* quest, uint32 availableCount, uint32 requiredCount, std::string obectiveName) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; std::map placeholders; AreaTableEntry const* current_area = ai->GetCurrentArea(); AreaTableEntry const* current_zone = ai->GetCurrentZone(); - placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); - placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest); placeholders["%quest_obj_name"] = obectiveName; placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); @@ -305,20 +305,20 @@ bool BroadcastHelper::BroadcastQuestUpdateAddKill(PlayerbotAI* ai, Player* bot, placeholders["%quest_obj_full_formatted"] = ai->GetChatHelper()->FormatQuestObjective(obectiveName, availableCount, requiredCount); if (availableCount < requiredCount - && urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestUpdateObjectiveProgress) + && urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceQuestUpdateObjectiveProgress) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_quest_update_add_kill_objective_progress", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_quest_update_add_kill_objective_progress", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } else if (availableCount == requiredCount - && urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestUpdateObjectiveCompleted) + && urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceQuestUpdateObjectiveCompleted) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_quest_update_add_kill_objective_completed", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_quest_update_add_kill_objective_completed", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } @@ -328,13 +328,13 @@ bool BroadcastHelper::BroadcastQuestUpdateAddKill(PlayerbotAI* ai, Player* bot, bool BroadcastHelper::BroadcastQuestUpdateAddItem(PlayerbotAI* ai, Player* bot, Quest const* quest, uint32 availableCount, uint32 requiredCount, const ItemTemplate* proto) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; std::map placeholders; AreaTableEntry const* current_area = ai->GetCurrentArea(); AreaTableEntry const* current_zone = ai->GetCurrentZone(); - placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); - placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest); std::string itemLinkFormatted = ai->GetChatHelper()->FormatItem(proto); placeholders["%item_link"] = itemLinkFormatted; @@ -347,20 +347,20 @@ bool BroadcastHelper::BroadcastQuestUpdateAddItem(PlayerbotAI* ai, Player* bot, placeholders["%quest_obj_full_formatted"] = ai->GetChatHelper()->FormatQuestObjective(itemLinkFormatted, availableCount, requiredCount); if (availableCount < requiredCount - && urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestUpdateObjectiveProgress) + && urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceQuestUpdateObjectiveProgress) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_quest_update_add_item_objective_progress", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_quest_update_add_item_objective_progress", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } else if (availableCount == requiredCount - && urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestUpdateObjectiveCompleted) + && urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceQuestUpdateObjectiveCompleted) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_quest_update_add_item_objective_completed", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_quest_update_add_item_objective_completed", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } @@ -370,23 +370,23 @@ bool BroadcastHelper::BroadcastQuestUpdateAddItem(PlayerbotAI* ai, Player* bot, bool BroadcastHelper::BroadcastQuestUpdateFailedTimer(PlayerbotAI* ai, Player* bot, Quest const* quest) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestUpdateFailedTimer) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceQuestUpdateFailedTimer) { std::map placeholders; placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest); AreaTableEntry const* current_area = ai->GetCurrentArea(); AreaTableEntry const* current_zone = ai->GetCurrentZone(); - placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); - placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); placeholders["%my_level"] = std::to_string(bot->GetLevel()); return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_quest_update_failed_timer", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_quest_update_failed_timer", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } @@ -396,23 +396,23 @@ bool BroadcastHelper::BroadcastQuestUpdateFailedTimer(PlayerbotAI* ai, Player* b bool BroadcastHelper::BroadcastQuestUpdateComplete(PlayerbotAI* ai, Player* bot, Quest const* quest) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestUpdateComplete) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceQuestUpdateComplete) { std::map placeholders; placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest); AreaTableEntry const* current_area = ai->GetCurrentArea(); AreaTableEntry const* current_zone = ai->GetCurrentZone(); - placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); - placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); placeholders["%my_level"] = std::to_string(bot->GetLevel()); return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_quest_update_complete", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_quest_update_complete", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } @@ -422,23 +422,23 @@ bool BroadcastHelper::BroadcastQuestUpdateComplete(PlayerbotAI* ai, Player* bot, bool BroadcastHelper::BroadcastQuestTurnedIn(PlayerbotAI* ai, Player* bot, Quest const* quest) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestTurnedIn) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceQuestTurnedIn) { std::map placeholders; placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest); AreaTableEntry const* current_area = ai->GetCurrentArea(); AreaTableEntry const* current_zone = ai->GetCurrentZone(); - placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); - placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); placeholders["%my_level"] = std::to_string(bot->GetLevel()); return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_quest_turned_in", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_quest_turned_in", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } @@ -448,14 +448,14 @@ bool BroadcastHelper::BroadcastQuestTurnedIn(PlayerbotAI* ai, Player* bot, Quest bool BroadcastHelper::BroadcastKill(PlayerbotAI* ai, Player* bot, Creature *creature) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; std::map placeholders; placeholders["%victim_name"] = creature->GetName(); AreaTableEntry const* current_area = ai->GetCurrentArea(); AreaTableEntry const* current_zone = ai->GetCurrentZone(); - placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); - placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); placeholders["%victim_level"] = creature->GetLevel(); placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); @@ -468,24 +468,24 @@ bool BroadcastHelper::BroadcastKill(PlayerbotAI* ai, Player* bot, Creature *crea if (creature->IsPet()) { - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillPet) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceKillPet) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_killed_pet", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_killed_pet", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } } else if (creature->IsPlayer()) { - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillPlayer) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceKillPlayer) { placeholders["%victim_class"] = ai->GetChatHelper()->FormatClass(creature->getClass()); return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_killed_player", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_killed_player", placeholders), { {TO_WORLD_DEFENSE, 50}, {TO_LOCAL_DEFENSE, 50}, {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } @@ -495,61 +495,61 @@ bool BroadcastHelper::BroadcastKill(PlayerbotAI* ai, Player* bot, Creature *crea switch (creature->GetCreatureTemplate()->rank) { case CREATURE_ELITE_NORMAL: - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillNormal) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceKillNormal) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_killed_normal", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_killed_normal", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } break; case CREATURE_ELITE_ELITE: - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillElite) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceKillElite) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_killed_elite", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_killed_elite", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } break; case CREATURE_ELITE_RAREELITE: - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillRareelite) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceKillRareelite) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_killed_rareelite", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_killed_rareelite", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } break; case CREATURE_ELITE_WORLDBOSS: - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillWorldboss) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceKillWorldboss) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_killed_worldboss", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_killed_worldboss", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } break; case CREATURE_ELITE_RARE: - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillRare) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceKillRare) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_killed_rare", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_killed_rare", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } break; case CREATURE_UNKNOWN: - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillUnknown) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceKillUnknown) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_killed_unknown", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_killed_unknown", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } @@ -564,43 +564,43 @@ bool BroadcastHelper::BroadcastKill(PlayerbotAI* ai, Player* bot, Creature *crea bool BroadcastHelper::BroadcastLevelup(PlayerbotAI* ai, Player* bot) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; uint32 level = bot->GetLevel(); std::map placeholders; AreaTableEntry const* current_area = ai->GetCurrentArea(); AreaTableEntry const* current_zone = ai->GetCurrentZone(); - placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); - placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); placeholders["%my_level"] = std::to_string(level); - if (level == sPlayerbotAIConfig->randomBotMaxLevel - && urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLevelupMaxLevel) + if (level == sPlayerbotAIConfig.randomBotMaxLevel + && urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceLevelupMaxLevel) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_levelup_max_level", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_levelup_max_level", placeholders), { {TO_GUILD, 30}, {TO_WORLD, 90}, {TO_GENERAL, 100} } ); } // It's divisible by 10 else if (level % 10 == 0 - && urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLevelupTenX) + && urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceLevelupTenX) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_levelup_10x", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_levelup_10x", placeholders), { {TO_GUILD, 50}, {TO_WORLD, 90}, {TO_GENERAL, 100} } ); } - else if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLevelupGeneric) + else if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceLevelupGeneric) { return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("broadcast_levelup_generic", placeholders), + PlayerbotTextMgr::instance().GetBotText("broadcast_levelup_generic", placeholders), { {TO_GUILD, 90}, {TO_WORLD, 90}, {TO_GENERAL, 100} } ); } @@ -610,9 +610,9 @@ bool BroadcastHelper::BroadcastLevelup(PlayerbotAI* ai, Player* bot) bool BroadcastHelper::BroadcastGuildMemberPromotion(PlayerbotAI* ai, Player* /* bot */, Player* player) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceGuildManagement) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceGuildManagement) { std::map placeholders; placeholders["%other_name"] = player->GetName(); @@ -620,7 +620,7 @@ bool BroadcastHelper::BroadcastGuildMemberPromotion(PlayerbotAI* ai, Player* /* placeholders["%other_race"] = ai->GetChatHelper()->FormatRace(player->getRace()); placeholders["%other_level"] = std::to_string(player->GetLevel()); - return ai->SayToGuild(BOT_TEXT2("broadcast_guild_promotion", placeholders)); + return ai->SayToGuild(PlayerbotTextMgr::instance().GetBotText("broadcast_guild_promotion", placeholders)); } return false; @@ -628,7 +628,7 @@ bool BroadcastHelper::BroadcastGuildMemberPromotion(PlayerbotAI* ai, Player* /* bool BroadcastHelper::BroadcastGuildMemberDemotion(PlayerbotAI* ai, Player* /* bot */, Player* player) { - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceGuildManagement) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceGuildManagement) { std::map placeholders; placeholders["%other_name"] = player->GetName(); @@ -636,7 +636,7 @@ bool BroadcastHelper::BroadcastGuildMemberDemotion(PlayerbotAI* ai, Player* /* b placeholders["%other_race"] = ai->GetChatHelper()->FormatRace(player->getRace()); placeholders["%other_level"] = std::to_string(player->GetLevel()); - return ai->SayToGuild(BOT_TEXT2("broadcast_guild_demotion", placeholders)); + return ai->SayToGuild(PlayerbotTextMgr::instance().GetBotText("broadcast_guild_demotion", placeholders)); } return false; @@ -644,25 +644,25 @@ bool BroadcastHelper::BroadcastGuildMemberDemotion(PlayerbotAI* ai, Player* /* b bool BroadcastHelper::BroadcastGuildGroupOrRaidInvite(PlayerbotAI* ai, Player* /* bot */, Player* player, Group* group) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; std::map placeholders; placeholders["%name"] = player->GetName(); AreaTableEntry const* current_area = ai->GetCurrentArea(); AreaTableEntry const* current_zone = ai->GetCurrentZone(); - placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); - placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); //TODO move texts to sql! if (group && group->isRaidGroup()) { if (urand(0, 3)) { - return ai->SayToGuild(BOT_TEXT2("Hey anyone want to raid in %zone_name", placeholders)); + return ai->SayToGuild(PlayerbotTextMgr::instance().GetBotText("Hey anyone want to raid in %zone_name", placeholders)); } else { - return ai->SayToGuild(BOT_TEXT2("Hey %name I'm raiding in %zone_name do you wan to join me?", placeholders)); + return ai->SayToGuild(PlayerbotTextMgr::instance().GetBotText("Hey %name I'm raiding in %zone_name do you wan to join me?", placeholders)); } } else @@ -670,11 +670,11 @@ bool BroadcastHelper::BroadcastGuildGroupOrRaidInvite(PlayerbotAI* ai, Player* / //(bot->GetTeam() == ALLIANCE ? LANG_COMMON : LANG_ORCISH) if (urand(0, 3)) { - return ai->SayToGuild(BOT_TEXT2("Hey anyone wanna group up in %zone_name?", placeholders)); + return ai->SayToGuild(PlayerbotTextMgr::instance().GetBotText("Hey anyone wanna group up in %zone_name?", placeholders)); } else { - return ai->SayToGuild(BOT_TEXT2("Hey %name do you want join my group? I'm heading for %zone_name", placeholders)); + return ai->SayToGuild(PlayerbotTextMgr::instance().GetBotText("Hey %name do you want join my group? I'm heading for %zone_name", placeholders)); } } @@ -683,9 +683,9 @@ bool BroadcastHelper::BroadcastGuildGroupOrRaidInvite(PlayerbotAI* ai, Player* / bool BroadcastHelper::BroadcastSuggestInstance(PlayerbotAI* ai, std::vector& allowedInstances, Player* bot) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestInstance) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceSuggestInstance) { std::map placeholders; placeholders["%my_role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); @@ -701,7 +701,7 @@ bool BroadcastHelper::BroadcastSuggestInstance(PlayerbotAI* ai, std::vector& quests, Player* bot) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestQuest) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceSuggestQuest) { int index = rand() % quests.size(); @@ -730,7 +730,7 @@ bool BroadcastHelper::BroadcastSuggestQuest(PlayerbotAI* ai, std::vector return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("suggest_quest", placeholders), + PlayerbotTextMgr::instance().GetBotText("suggest_quest", placeholders), { {TO_LOOKING_FOR_GROUP, 50}, {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } @@ -740,9 +740,9 @@ bool BroadcastHelper::BroadcastSuggestQuest(PlayerbotAI* ai, std::vector bool BroadcastHelper::BroadcastSuggestGrindMaterials(PlayerbotAI* ai, std::string item, Player* bot) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestGrindMaterials) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceSuggestGrindMaterials) { std::map placeholders; @@ -755,7 +755,7 @@ bool BroadcastHelper::BroadcastSuggestGrindMaterials(PlayerbotAI* ai, std::strin return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("suggest_trade", placeholders), + PlayerbotTextMgr::instance().GetBotText("suggest_trade", placeholders), { {TO_TRADE, 50}, {TO_LOOKING_FOR_GROUP, 50}, {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } @@ -765,9 +765,9 @@ bool BroadcastHelper::BroadcastSuggestGrindMaterials(PlayerbotAI* ai, std::strin bool BroadcastHelper::BroadcastSuggestGrindReputation(PlayerbotAI* ai, std::vector levels, std::vector allowedFactions, Player* bot) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestGrindReputation) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceSuggestGrindReputation) { std::map placeholders; @@ -787,7 +787,7 @@ bool BroadcastHelper::BroadcastSuggestGrindReputation(PlayerbotAI* ai, std::vect return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("suggest_faction", placeholders), + PlayerbotTextMgr::instance().GetBotText("suggest_faction", placeholders), { {TO_LOOKING_FOR_GROUP, 50}, {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } ); } @@ -797,9 +797,9 @@ bool BroadcastHelper::BroadcastSuggestGrindReputation(PlayerbotAI* ai, std::vect bool BroadcastHelper::BroadcastSuggestSell(PlayerbotAI* ai, const ItemTemplate* proto, uint32 count, uint32 price, Player* bot) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestSell) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceSuggestSell) { std::map placeholders; @@ -814,7 +814,7 @@ bool BroadcastHelper::BroadcastSuggestSell(PlayerbotAI* ai, const ItemTemplate* return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("suggest_sell", placeholders), + PlayerbotTextMgr::instance().GetBotText("suggest_sell", placeholders), { {TO_TRADE, 90}, {TO_GENERAL, 100} } ); } @@ -824,24 +824,24 @@ bool BroadcastHelper::BroadcastSuggestSell(PlayerbotAI* ai, const ItemTemplate* bool BroadcastHelper::BroadcastSuggestSomething(PlayerbotAI* ai, Player* bot) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestSomething) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceSuggestSomething) { std::map placeholders; placeholders["%my_role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); AreaTableEntry const* current_area = ai->GetCurrentArea(); AreaTableEntry const* current_zone = ai->GetCurrentZone(); - placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); - placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); placeholders["%my_level"] = std::to_string(bot->GetLevel()); return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("suggest_something", placeholders), + PlayerbotTextMgr::instance().GetBotText("suggest_something", placeholders), { {TO_GUILD, 10}, {TO_WORLD, 70}, {TO_GENERAL, 100} } ); } @@ -851,29 +851,29 @@ bool BroadcastHelper::BroadcastSuggestSomething(PlayerbotAI* ai, Player* bot) bool BroadcastHelper::BroadcastSuggestSomethingToxic(PlayerbotAI* ai, Player* bot) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestSomethingToxic) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceSuggestSomethingToxic) { //items std::vector botItems = ai->GetInventoryAndEquippedItems(); std::map placeholders; - placeholders["%random_inventory_item_link"] = botItems.size() > 0 ? ai->GetChatHelper()->FormatItem(botItems[rand() % botItems.size()]->GetTemplate()) : BOT_TEXT1("string_empty_link"); + placeholders["%random_inventory_item_link"] = botItems.size() > 0 ? ai->GetChatHelper()->FormatItem(botItems[rand() % botItems.size()]->GetTemplate()) : PlayerbotTextMgr::instance().GetBotText("string_empty_link"); placeholders["%my_role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); AreaTableEntry const* current_area = ai->GetCurrentArea(); AreaTableEntry const* current_zone = ai->GetCurrentZone(); - placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); - placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); placeholders["%my_level"] = std::to_string(bot->GetLevel()); return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("suggest_something_toxic", placeholders), + PlayerbotTextMgr::instance().GetBotText("suggest_something_toxic", placeholders), { {TO_GUILD, 10}, {TO_WORLD, 70}, {TO_GENERAL, 100} } ); } @@ -883,9 +883,9 @@ bool BroadcastHelper::BroadcastSuggestSomethingToxic(PlayerbotAI* ai, Player* bo bool BroadcastHelper::BroadcastSuggestToxicLinks(PlayerbotAI* ai, Player* bot) { - if (!sPlayerbotAIConfig->enableBroadcasts) + if (!sPlayerbotAIConfig.enableBroadcasts) return false; - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestToxicLinks) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceSuggestToxicLinks) { //quests std::vector incompleteQuests; @@ -908,8 +908,8 @@ bool BroadcastHelper::BroadcastSuggestToxicLinks(PlayerbotAI* ai, Player* bot) std::map placeholders; - placeholders["%random_inventory_item_link"] = botItems.size() > 0 ? ai->GetChatHelper()->FormatItem(botItems[rand() % botItems.size()]->GetTemplate()) : BOT_TEXT1("string_empty_link"); - placeholders["%prefix"] = sPlayerbotAIConfig->toxicLinksPrefix; + placeholders["%random_inventory_item_link"] = botItems.size() > 0 ? ai->GetChatHelper()->FormatItem(botItems[rand() % botItems.size()]->GetTemplate()) : PlayerbotTextMgr::instance().GetBotText("string_empty_link"); + placeholders["%prefix"] = sPlayerbotAIConfig.toxicLinksPrefix; if (incompleteQuests.size() > 0) { @@ -924,15 +924,15 @@ bool BroadcastHelper::BroadcastSuggestToxicLinks(PlayerbotAI* ai, Player* bot) placeholders["%my_role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); AreaTableEntry const* current_area = ai->GetCurrentArea(); AreaTableEntry const* current_zone = ai->GetCurrentZone(); - placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); - placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : PlayerbotTextMgr::instance().GetBotText("string_unknown_area"); placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); placeholders["%my_level"] = std::to_string(bot->GetLevel()); return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("suggest_toxic_links", placeholders), + PlayerbotTextMgr::instance().GetBotText("suggest_toxic_links", placeholders), { {TO_GUILD, 10}, {TO_WORLD, 70}, {TO_GENERAL, 100} } ); } @@ -942,7 +942,7 @@ bool BroadcastHelper::BroadcastSuggestToxicLinks(PlayerbotAI* ai, Player* bot) bool BroadcastHelper::BroadcastSuggestThunderfury(PlayerbotAI* ai, Player* bot) { - if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestThunderfury) + if (urand(1, sPlayerbotAIConfig.broadcastChanceMaxValue) <= sPlayerbotAIConfig.broadcastChanceSuggestThunderfury) { std::map placeholders; ItemTemplate const* thunderfuryProto = sObjectMgr->GetItemTemplate(19019); @@ -950,7 +950,7 @@ bool BroadcastHelper::BroadcastSuggestThunderfury(PlayerbotAI* ai, Player* bot) return BroadcastToChannelWithGlobalChance( ai, - BOT_TEXT2("thunderfury_spam", placeholders), + PlayerbotTextMgr::instance().GetBotText("thunderfury_spam", placeholders), { {TO_WORLD, 70}, {TO_GENERAL, 100} } ); } diff --git a/src/Util/BroadcastHelper.h b/src/Util/BroadcastHelper.h index 099d6bf192..c79d837aad 100644 --- a/src/Util/BroadcastHelper.h +++ b/src/Util/BroadcastHelper.h @@ -145,4 +145,4 @@ class BroadcastHelper PlayerbotAI* ai, Player* bot ); -}; \ No newline at end of file +}; diff --git a/src/Util/ServerFacade.cpp b/src/Util/ServerFacade.cpp index d69944c04f..12a77de635 100644 --- a/src/Util/ServerFacade.cpp +++ b/src/Util/ServerFacade.cpp @@ -4,8 +4,8 @@ */ #include "ServerFacade.h" +#include "Player.h" -#include "Playerbots.h" #include "TargetedMovementGenerator.h" float ServerFacade::GetDistance2d(Unit* unit, WorldObject* wo) @@ -25,13 +25,13 @@ float ServerFacade::GetDistance2d(Unit* unit, float x, float y) bool ServerFacade::IsDistanceLessThan(float dist1, float dist2) { - // return dist1 - dist2 < sPlayerbotAIConfig->targetPosRecalcDistance; + // return dist1 - dist2 < sPlayerbotAIConfig.targetPosRecalcDistance; return dist1 < dist2; } bool ServerFacade::IsDistanceGreaterThan(float dist1, float dist2) { - // return dist1 - dist2 > sPlayerbotAIConfig->targetPosRecalcDistance; + // return dist1 - dist2 > sPlayerbotAIConfig.targetPosRecalcDistance; return dist1 > dist2; } diff --git a/src/Util/ServerFacade.h b/src/Util/ServerFacade.h index 6668fa9562..978b8e7681 100644 --- a/src/Util/ServerFacade.h +++ b/src/Util/ServerFacade.h @@ -6,8 +6,6 @@ #ifndef _PLAYERBOT_SERVERFACADE_H #define _PLAYERBOT_SERVERFACADE_H -#include "Common.h" - class Player; class Unit; class WorldObject; @@ -29,12 +27,13 @@ class ServerFacade /** * @brief Get singleton instance. * - * @return ServerFacade* Pointer to the singleton instance. + * @return ServerFacade& Reference to the singleton instance. */ - static ServerFacade* instance() + static ServerFacade& instance() { static ServerFacade instance; - return &instance; + + return instance; } public: @@ -123,7 +122,4 @@ class ServerFacade void SendPacket(Player* player, WorldPacket* packet); }; -/** Global singleton accessor. */ -#define sServerFacade ServerFacade::instance() - #endif