mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-13 17:09:08 +00:00
Compare commits
1 Commits
opcode-cra
...
directory_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6003dbc1b5 |
26
README.md
26
README.md
@@ -2,8 +2,6 @@
|
|||||||
<a href="https://github.com/liyunfan1223/mod-playerbots/blob/master/README.md">English</a>
|
<a href="https://github.com/liyunfan1223/mod-playerbots/blob/master/README.md">English</a>
|
||||||
|
|
|
|
||||||
<a href="https://github.com/liyunfan1223/mod-playerbots/blob/master/README_CN.md">中文</a>
|
<a href="https://github.com/liyunfan1223/mod-playerbots/blob/master/README_CN.md">中文</a>
|
||||||
|
|
|
||||||
<a href="https://github.com/brighton-chi/mod-playerbots/blob/readme/README_ES.md">Español</a>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
@@ -18,25 +16,23 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
# Playerbots Module
|
# Playerbots Module
|
||||||
`mod-playerbots` is an [AzerothCore](https://www.azerothcore.org/) module that adds player-like bots to a server. The project is based off [IKE3's Playerbots](https://github.com/ike3/mangosbot) and requires a custom branch of AzerothCore to compile and run: [liyunfan1223/azerothcore-wotlk/tree/Playerbot](https://github.com/liyunfan1223/azerothcore-wotlk/tree/Playerbot).
|
`mod-playerbots` is an [AzerothCore](https://www.azerothcore.org/) module that adds player-like bots to a server. The project is based off [IKE3's Playerbots](https://github.com/ike3/mangosbot). Features include:
|
||||||
|
|
||||||
Features include:
|
- Bots that utilize real player data, allowing players to interact with their other characters, form parties, level up, and more;
|
||||||
|
- Random bots that wander through the world and behave like players, simulating the MMO experience;
|
||||||
- The ability to log in alt characters as bots, allowing players to interact with their other characters, form parties, level up, and more;
|
- Bots capable of running raids and battlegrounds;
|
||||||
- Random bots that wander through the world, complete quests, and otherwise behave like players, simulating the MMO experience;
|
|
||||||
- Bots capable of running most raids and battlegrounds;
|
|
||||||
- Highly configurable settings to define how bots behave;
|
- Highly configurable settings to define how bots behave;
|
||||||
- Excellent performance, even when running thousands of bots.
|
- Excellent performance, even when running thousands of bots.
|
||||||
|
|
||||||
**This project is still under development**. If you encounter any errors or experience crashes, we kindly request that you [report them as GitHub issues](https://github.com/liyunfan1223/mod-playerbots/issues/new?template=bug_report.md). Your valuable feedback will help us improve this project collaboratively.
|
**This project is still under development**. If you encounter any errors or experience crashes, we kindly request that you [report them as GitHub issues](https://github.com/liyunfan1223/mod-playerbots/issues/new?template=bug_report.md). Your valuable feedback will help us improve this project collaboratively.
|
||||||
|
|
||||||
`mod-playerbots` has a **[Discord server](https://discord.gg/NQm5QShwf9)** where you can discuss the project, ask questions, and get involved in the community!
|
**Playerbots Module** has a **[Discord server](https://discord.gg/NQm5QShwf9)** where you can discuss the project.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Classic Installation
|
### Classic Installation
|
||||||
|
|
||||||
As noted above, `mod-playerbots` requires a custom branch of AzerothCore: [liyunfan1223/azerothcore-wotlk/tree/Playerbot](https://github.com/liyunfan1223/azerothcore-wotlk/tree/Playerbot). To install the module, simply run:
|
`mod-playerbots` requires a custom branch of AzerothCore to work: [liyunfan1223/azerothcore-wotlk/tree/Playerbot](https://github.com/liyunfan1223/azerothcore-wotlk/tree/Playerbot). To install the module, simply run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/liyunfan1223/azerothcore-wotlk.git --branch=Playerbot
|
git clone https://github.com/liyunfan1223/azerothcore-wotlk.git --branch=Playerbot
|
||||||
@@ -85,21 +81,21 @@ Use `docker compose up -d --build` to build and run the server. For more informa
|
|||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
The [Playerbots Wiki](https://github.com/liyunfan1223/mod-playerbots/wiki) contains an extensive overview of addons, commands, raids with programmed bot strategies, and recommended performance configurations. Please note that documentation may be incomplete or out-of-date in some sections. Contributions are welcome.
|
The [Playerbots Wiki](https://github.com/liyunfan1223/mod-playerbots/wiki) contains an extensive overview of addons, commands, and recommended configurations. Please note that documentation may be incomplete or out-of-date in some sections. Contributions are welcome.
|
||||||
|
|
||||||
## Frequently Asked Questions
|
## Frequently Asked Questions
|
||||||
|
|
||||||
- **Why aren't my bots casting spells?** Please make sure that the necessary English DBC file (enUS) is present.
|
- **Why aren't my bots casting spells?** Please make sure that the necessary English DBC file (enUS) is present.
|
||||||
- **What platforms are supported?** We support Ubuntu, Windows, and macOS. Other Linux distros may work, but will not receive support.
|
- **What platforms are supported?** We support Ubuntu, Windows, and macOS. Other Linux distros may work, but will not receive support.
|
||||||
- **Why isn't my source compiling?** Please ensure that you are compiling with the required [custom branch of AzerothCore](https://github.com/liyunfan1223/azerothcore-wotlk/tree/Playerbot). Additionally, please [check the build status of our CI](https://github.com/liyunfan1223/mod-playerbots/actions). If the latest build is failing, rever to the last successful commit until we address the issue.
|
- **Why isn't my source compiling?** Please [check the build status of our CI](https://github.com/liyunfan1223/mod-playerbots/actions). If the latest build is failing, rever to the last successful commit until we address the issue.
|
||||||
|
|
||||||
## Addons
|
## Addons
|
||||||
|
|
||||||
Typically, bots are controlled via chat commands. For larger bot groups, this can be unwieldy. As an alternative, community members have developed client Add-Ons to allow controlling bots through the in-game UI. We recommend you check out their projects:
|
Typically, bots are controlled via chat commands. For larger bot groups, this can be unwieldy. As an alternative, community members have developed client Add-Ons to allow controlling bots through the in-game UI. We recommend you check out their projects:
|
||||||
|
|
||||||
- [Multibot](https://github.com/Macx-Lio/MultiBot) (by Macx-Lio), which includes English, Chinese, French, German, Korean, Russian, and Spanish support [note: active development is temporarily continuing on a fork in Macx-Lio's absence (https://github.com/Wishmaster117/MultiBot)]
|
- [Multibot](https://github.com/Macx-Lio/MultiBot) (by Macx-Lio)
|
||||||
- [Unbot Addon (zh)](https://github.com/liyunfan1223/unbot-addon) (Chinese version by Liyunfan) [note: no longer under active development]
|
- [Unbot Addon (zh)](https://github.com/liyunfan1223/unbot-addon) (Chinese version by Liyunfan)
|
||||||
- [Unbot Addon (en)](https://github.com/noisiver/unbot-addon/tree/english) (English version translated by @Revision) [note: no longer under active development]
|
- [Unbot Addon (en)](https://github.com/noisiver/unbot-addon/tree/english) (English version translated by @Revision)
|
||||||
|
|
||||||
## Acknowledgements
|
## Acknowledgements
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
DROP TABLE IF EXISTS `playerbots_account_keys`;
|
DROP TABLE IF EXISTS `playerbot_account_keys`;
|
||||||
|
|
||||||
CREATE TABLE `playerbots_account_keys` (
|
CREATE TABLE `playerbot_account_keys` (
|
||||||
`account_id` INT PRIMARY KEY,
|
`account_id` INT PRIMARY KEY,
|
||||||
`security_key` VARCHAR(255) NOT NULL,
|
`security_key` VARCHAR(255) NOT NULL,
|
||||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
DROP TABLE IF EXISTS `playerbots_account_links`;
|
DROP TABLE IF EXISTS `playerbot_account_links`;
|
||||||
|
|
||||||
CREATE TABLE `playerbots_account_links` (
|
CREATE TABLE `playerbot_account_links` (
|
||||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
`account_id` INT NOT NULL,
|
`account_id` INT NOT NULL,
|
||||||
`linked_account_id` INT NOT NULL,
|
`linked_account_id` INT NOT NULL,
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
DROP TABLE IF EXISTS `playerbots_account_type`;
|
|
||||||
CREATE TABLE `playerbots_account_type` (
|
|
||||||
`account_id` int unsigned NOT NULL,
|
|
||||||
`account_type` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '0 = unassigned, 1 = RNDbot, 2 = AddClass',
|
|
||||||
`assignment_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
PRIMARY KEY (`account_id`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Playerbot account type assignments';
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +0,0 @@
|
|||||||
DROP TABLE IF EXISTS `playerbot_account_keys`;
|
|
||||||
CREATE TABLE IF NOT EXISTS `playerbots_account_keys` (
|
|
||||||
`account_id` INT PRIMARY KEY,
|
|
||||||
`security_key` VARCHAR(255) NOT NULL,
|
|
||||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
||||||
) ENGINE=INNODB DEFAULT CHARSET=latin1;
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `playerbot_account_links`;
|
|
||||||
CREATE TABLE IF NOT EXISTS `playerbots_account_links` (
|
|
||||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
|
||||||
`account_id` INT NOT NULL,
|
|
||||||
`linked_account_id` INT NOT NULL,
|
|
||||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
UNIQUE KEY `account_link` (`account_id`, `linked_account_id`)
|
|
||||||
) ENGINE=INNODB DEFAULT CHARSET=latin1;
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
-- Create playerbots_account_type table for tracking accounts assignments
|
|
||||||
DROP TABLE IF EXISTS `playerbots_account_type`;
|
|
||||||
CREATE TABLE `playerbots_account_type` (
|
|
||||||
`account_id` int unsigned NOT NULL,
|
|
||||||
`account_type` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '0 = unassigned, 1 = RNDbot, 2 = AddClass',
|
|
||||||
`assignment_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
PRIMARY KEY (`account_id`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Playerbot account type assignments';
|
|
||||||
|
|
||||||
1475
data/sql/playerbots/updates/db_playerbots/2024_08_07_00.sql
Normal file
1475
data/sql/playerbots/updates/db_playerbots/2024_08_07_00.sql
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
|||||||
DELETE FROM spell_dbc WHERE ID = 30758;
|
|
||||||
INSERT INTO spell_dbc (`ID`,`Category`,`DispelType`,`Mechanic`,`Attributes`,`AttributesEx`,`AttributesEx2`,`AttributesEx3`,`AttributesEx4`,`AttributesEx5`,`AttributesEx6`,`AttributesEx7`,`ShapeshiftMask`,`unk_320_2`,`ShapeshiftExclude`,`unk_320_3`,`Targets`,`TargetCreatureType`,`RequiresSpellFocus`,`FacingCasterFlags`,`CasterAuraState`,`TargetAuraState`,`ExcludeCasterAuraState`,`ExcludeTargetAuraState`,`CasterAuraSpell`,`TargetAuraSpell`,`ExcludeCasterAuraSpell`,`ExcludeTargetAuraSpell`,`CastingTimeIndex`,`RecoveryTime`,`CategoryRecoveryTime`,`InterruptFlags`,`AuraInterruptFlags`,`ChannelInterruptFlags`,`ProcTypeMask`,`ProcChance`,`ProcCharges`,`MaxLevel`,`BaseLevel`,`SpellLevel`,`DurationIndex`,`PowerType`,`ManaCost`,`ManaCostPerLevel`,`ManaPerSecond`,`ManaPerSecondPerLevel`,`RangeIndex`,`Speed`,`ModalNextSpell`,`CumulativeAura`,`Totem_1`,`Totem_2`,`Reagent_1`,`Reagent_2`,`Reagent_3`,`Reagent_4`,`Reagent_5`,`Reagent_6`,`Reagent_7`,`Reagent_8`,`ReagentCount_1`,`ReagentCount_2`,`ReagentCount_3`,`ReagentCount_4`,`ReagentCount_5`,`ReagentCount_6`,`ReagentCount_7`,`ReagentCount_8`,`EquippedItemClass`,`EquippedItemSubclass`,`EquippedItemInvTypes`,`Effect_1`,`Effect_2`,`Effect_3`,`EffectDieSides_1`,`EffectDieSides_2`,`EffectDieSides_3`,`EffectRealPointsPerLevel_1`,`EffectRealPointsPerLevel_2`,`EffectRealPointsPerLevel_3`,`EffectBasePoints_1`,`EffectBasePoints_2`,`EffectBasePoints_3`,`EffectMechanic_1`,`EffectMechanic_2`,`EffectMechanic_3`,`ImplicitTargetA_1`,`ImplicitTargetA_2`,`ImplicitTargetA_3`,`ImplicitTargetB_1`,`ImplicitTargetB_2`,`ImplicitTargetB_3`,`EffectRadiusIndex_1`,`EffectRadiusIndex_2`,`EffectRadiusIndex_3`,`EffectAura_1`,`EffectAura_2`,`EffectAura_3`,`EffectAuraPeriod_1`,`EffectAuraPeriod_2`,`EffectAuraPeriod_3`,`EffectMultipleValue_1`,`EffectMultipleValue_2`,`EffectMultipleValue_3`,`EffectChainTargets_1`,`EffectChainTargets_2`,`EffectChainTargets_3`,`EffectItemType_1`,`EffectItemType_2`,`EffectItemType_3`,`EffectMiscValue_1`,`EffectMiscValue_2`,`EffectMiscValue_3`,`EffectMiscValueB_1`,`EffectMiscValueB_2`,`EffectMiscValueB_3`,`EffectTriggerSpell_1`,`EffectTriggerSpell_2`,`EffectTriggerSpell_3`,`EffectPointsPerCombo_1`,`EffectPointsPerCombo_2`,`EffectPointsPerCombo_3`,`EffectSpellClassMaskA_1`,`EffectSpellClassMaskA_2`,`EffectSpellClassMaskA_3`,`EffectSpellClassMaskB_1`,`EffectSpellClassMaskB_2`,`EffectSpellClassMaskB_3`,`EffectSpellClassMaskC_1`,`EffectSpellClassMaskC_2`,`EffectSpellClassMaskC_3`,`SpellVisualID_1`,`SpellVisualID_2`,`SpellIconID`,`ActiveIconID`,`SpellPriority`,`Name_Lang_enUS`,`Name_Lang_enGB`,`Name_Lang_koKR`,`Name_Lang_frFR`,`Name_Lang_deDE`,`Name_Lang_enCN`,`Name_Lang_zhCN`,`Name_Lang_enTW`,`Name_Lang_zhTW`,`Name_Lang_esES`,`Name_Lang_esMX`,`Name_Lang_ruRU`,`Name_Lang_ptPT`,`Name_Lang_ptBR`,`Name_Lang_itIT`,`Name_Lang_Unk`,`Name_Lang_Mask`,`NameSubtext_Lang_enUS`,`NameSubtext_Lang_enGB`,`NameSubtext_Lang_koKR`,`NameSubtext_Lang_frFR`,`NameSubtext_Lang_deDE`,`NameSubtext_Lang_enCN`,`NameSubtext_Lang_zhCN`,`NameSubtext_Lang_enTW`,`NameSubtext_Lang_zhTW`,`NameSubtext_Lang_esES`,`NameSubtext_Lang_esMX`,`NameSubtext_Lang_ruRU`,`NameSubtext_Lang_ptPT`,`NameSubtext_Lang_ptBR`,`NameSubtext_Lang_itIT`,`NameSubtext_Lang_Unk`,`NameSubtext_Lang_Mask`,`Description_Lang_enUS`,`Description_Lang_enGB`,`Description_Lang_koKR`,`Description_Lang_frFR`,`Description_Lang_deDE`,`Description_Lang_enCN`,`Description_Lang_zhCN`,`Description_Lang_enTW`,`Description_Lang_zhTW`,`Description_Lang_esES`,`Description_Lang_esMX`,`Description_Lang_ruRU`,`Description_Lang_ptPT`,`Description_Lang_ptBR`,`Description_Lang_itIT`,`Description_Lang_Unk`,`Description_Lang_Mask`,`AuraDescription_Lang_enUS`,`AuraDescription_Lang_enGB`,`AuraDescription_Lang_koKR`,`AuraDescription_Lang_frFR`,`AuraDescription_Lang_deDE`,`AuraDescription_Lang_enCN`,`AuraDescription_Lang_zhCN`,`AuraDescription_Lang_enTW`,`AuraDescription_Lang_zhTW`,`AuraDescription_Lang_esES`,`AuraDescription_Lang_esMX`,`AuraDescription_Lang_ruRU`,`AuraDescription_Lang_ptPT`,`AuraDescription_Lang_ptBR`,`AuraDescription_Lang_itIT`,`AuraDescription_Lang_Unk`,`AuraDescription_Lang_Mask`,`ManaCostPct`,`StartRecoveryCategory`,`StartRecoveryTime`,`MaxTargetLevel`,`SpellClassSet`,`SpellClassMask_1`,`SpellClassMask_2`,`SpellClassMask_3`,`MaxTargets`,`DefenseType`,`PreventionType`,`StanceBarOrder`,`EffectChainAmplitude_1`,`EffectChainAmplitude_2`,`EffectChainAmplitude_3`,`MinFactionID`,`MinReputation`,`RequiredAuraVision`,`RequiredTotemCategoryID_1`,`RequiredTotemCategoryID_2`,`RequiredAreasID`,`SchoolMask`,`RuneCostID`,`SpellMissileID`,`PowerDisplayID`,`EffectBonusMultiplier_1`,`EffectBonusMultiplier_2`,`EffectBonusMultiplier_3`,`SpellDescriptionVariableID`,`SpellDifficultyID`)
|
|
||||||
VALUES (30758,0,0,0,696254720,132128,268976133,269680640,8388736,393224,4100,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,52,0,0,0,0,10,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,'aedm','','','','','','','','','','','','','','','',16712190,'','','','','','','','','','','','','','','','',16712172,'','','','','','','','','','','','','','','','',16712188,'','','','','','','','','','','','','','','','',16712188,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0);
|
|
||||||
@@ -19,7 +19,6 @@
|
|||||||
#include "CreatureData.h"
|
#include "CreatureData.h"
|
||||||
#include "EmoteAction.h"
|
#include "EmoteAction.h"
|
||||||
#include "Engine.h"
|
#include "Engine.h"
|
||||||
#include "EventProcessor.h"
|
|
||||||
#include "ExternalEventHelper.h"
|
#include "ExternalEventHelper.h"
|
||||||
#include "GameObjectData.h"
|
#include "GameObjectData.h"
|
||||||
#include "GameTime.h"
|
#include "GameTime.h"
|
||||||
@@ -157,7 +156,7 @@ PlayerbotAI::PlayerbotAI(Player* bot)
|
|||||||
masterIncomingPacketHandlers.AddHandler(CMSG_GAMEOBJ_USE, "use game object");
|
masterIncomingPacketHandlers.AddHandler(CMSG_GAMEOBJ_USE, "use game object");
|
||||||
masterIncomingPacketHandlers.AddHandler(CMSG_AREATRIGGER, "area trigger");
|
masterIncomingPacketHandlers.AddHandler(CMSG_AREATRIGGER, "area trigger");
|
||||||
// masterIncomingPacketHandlers.AddHandler(CMSG_GAMEOBJ_USE, "use game object");
|
// masterIncomingPacketHandlers.AddHandler(CMSG_GAMEOBJ_USE, "use game object");
|
||||||
// masterIncomingPacketHandlers.AddHandler(CMSG_LOOT_ROLL, "loot roll");
|
masterIncomingPacketHandlers.AddHandler(CMSG_LOOT_ROLL, "loot roll");
|
||||||
masterIncomingPacketHandlers.AddHandler(CMSG_GOSSIP_HELLO, "gossip hello");
|
masterIncomingPacketHandlers.AddHandler(CMSG_GOSSIP_HELLO, "gossip hello");
|
||||||
masterIncomingPacketHandlers.AddHandler(CMSG_QUESTGIVER_HELLO, "gossip hello");
|
masterIncomingPacketHandlers.AddHandler(CMSG_QUESTGIVER_HELLO, "gossip hello");
|
||||||
masterIncomingPacketHandlers.AddHandler(CMSG_ACTIVATETAXI, "activate taxi");
|
masterIncomingPacketHandlers.AddHandler(CMSG_ACTIVATETAXI, "activate taxi");
|
||||||
@@ -212,8 +211,7 @@ PlayerbotAI::PlayerbotAI(Player* bot)
|
|||||||
masterIncomingPacketHandlers.AddHandler(CMSG_PUSHQUESTTOPARTY, "quest share");
|
masterIncomingPacketHandlers.AddHandler(CMSG_PUSHQUESTTOPARTY, "quest share");
|
||||||
botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_COMPLETE, "quest update complete");
|
botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_COMPLETE, "quest update complete");
|
||||||
botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_ADD_KILL, "quest update add kill");
|
botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_ADD_KILL, "quest update add kill");
|
||||||
// SMSG_QUESTUPDATE_ADD_ITEM no longer used
|
// botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_ADD_ITEM, "quest update add item"); // SMSG_QUESTUPDATE_ADD_ITEM no longer used
|
||||||
// botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_ADD_ITEM, "quest update add item");
|
|
||||||
botOutgoingPacketHandlers.AddHandler(SMSG_QUEST_CONFIRM_ACCEPT, "confirm quest");
|
botOutgoingPacketHandlers.AddHandler(SMSG_QUEST_CONFIRM_ACCEPT, "confirm quest");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -722,8 +720,6 @@ void PlayerbotAI::HandleTeleportAck()
|
|||||||
// SetNextCheckDelay(urand(2000, 5000));
|
// SetNextCheckDelay(urand(2000, 5000));
|
||||||
if (sPlayerbotAIConfig->applyInstanceStrategies)
|
if (sPlayerbotAIConfig->applyInstanceStrategies)
|
||||||
ApplyInstanceStrategies(bot->GetMapId(), true);
|
ApplyInstanceStrategies(bot->GetMapId(), true);
|
||||||
if (sPlayerbotAIConfig->restrictHealerDPS)
|
|
||||||
EvaluateHealerDpsStrategy();
|
|
||||||
Reset(true);
|
Reset(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -800,7 +796,6 @@ bool PlayerbotAI::IsAllowedCommand(std::string const text)
|
|||||||
unsecuredCommands.insert("sendmail");
|
unsecuredCommands.insert("sendmail");
|
||||||
unsecuredCommands.insert("invite");
|
unsecuredCommands.insert("invite");
|
||||||
unsecuredCommands.insert("leave");
|
unsecuredCommands.insert("leave");
|
||||||
unsecuredCommands.insert("lfg");
|
|
||||||
unsecuredCommands.insert("rpg status");
|
unsecuredCommands.insert("rpg status");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1052,9 +1047,6 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chanName == "World")
|
|
||||||
return;
|
|
||||||
|
|
||||||
// do not reply to self but always try to reply to real player
|
// do not reply to self but always try to reply to real player
|
||||||
if (guid1 != bot->GetGUID())
|
if (guid1 != bot->GetGUID())
|
||||||
{
|
{
|
||||||
@@ -1297,6 +1289,11 @@ void PlayerbotAI::DoNextAction(bool min)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bot->HasUnitState(UNIT_STATE_IN_FLIGHT))
|
||||||
|
{
|
||||||
|
SetNextCheckDelay(sPlayerbotAIConfig->passiveDelay);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Change engine if just died
|
// Change engine if just died
|
||||||
bool isBotAlive = bot->IsAlive();
|
bool isBotAlive = bot->IsAlive();
|
||||||
@@ -1426,9 +1423,6 @@ void PlayerbotAI::DoNextAction(bool min)
|
|||||||
master = newMaster;
|
master = newMaster;
|
||||||
botAI->SetMaster(newMaster);
|
botAI->SetMaster(newMaster);
|
||||||
botAI->ResetStrategies();
|
botAI->ResetStrategies();
|
||||||
|
|
||||||
if (!bot->InBattleground())
|
|
||||||
{
|
|
||||||
botAI->ChangeStrategy("+follow", BOT_STATE_NON_COMBAT);
|
botAI->ChangeStrategy("+follow", BOT_STATE_NON_COMBAT);
|
||||||
|
|
||||||
if (botAI->GetMaster() == botAI->GetGroupMaster())
|
if (botAI->GetMaster() == botAI->GetGroupMaster())
|
||||||
@@ -1436,12 +1430,6 @@ void PlayerbotAI::DoNextAction(bool min)
|
|||||||
else
|
else
|
||||||
botAI->TellMaster(!urand(0, 2) ? "Hello!" : "Hi!");
|
botAI->TellMaster(!urand(0, 2) ? "Hello!" : "Hi!");
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// we're in a battleground, stay with the pack and focus on objective
|
|
||||||
botAI->ChangeStrategy("-follow", BOT_STATE_NON_COMBAT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (master && master->IsInWorld())
|
if (master && master->IsInWorld())
|
||||||
@@ -1766,7 +1754,7 @@ bool PlayerbotAI::IsRangedDps(Player* player, bool bySpec) { return IsRanged(pla
|
|||||||
|
|
||||||
bool PlayerbotAI::IsHealAssistantOfIndex(Player* player, int index)
|
bool PlayerbotAI::IsHealAssistantOfIndex(Player* player, int index)
|
||||||
{
|
{
|
||||||
Group* group = player->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -1778,11 +1766,6 @@ bool PlayerbotAI::IsHealAssistantOfIndex(Player* player, int index)
|
|||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
|
|
||||||
if (!member)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsHeal(member)) // Check if the member is a healer
|
if (IsHeal(member)) // Check if the member is a healer
|
||||||
{
|
{
|
||||||
bool isAssistant = group->IsAssistant(member->GetGUID());
|
bool isAssistant = group->IsAssistant(member->GetGUID());
|
||||||
@@ -1802,7 +1785,7 @@ bool PlayerbotAI::IsHealAssistantOfIndex(Player* player, int index)
|
|||||||
|
|
||||||
bool PlayerbotAI::IsRangedDpsAssistantOfIndex(Player* player, int index)
|
bool PlayerbotAI::IsRangedDpsAssistantOfIndex(Player* player, int index)
|
||||||
{
|
{
|
||||||
Group* group = player->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -1814,11 +1797,6 @@ bool PlayerbotAI::IsRangedDpsAssistantOfIndex(Player* player, int index)
|
|||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
|
|
||||||
if (!member)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsRangedDps(member)) // Check if the member is a ranged DPS
|
if (IsRangedDps(member)) // Check if the member is a ranged DPS
|
||||||
{
|
{
|
||||||
bool isAssistant = group->IsAssistant(member->GetGUID());
|
bool isAssistant = group->IsAssistant(member->GetGUID());
|
||||||
@@ -1851,35 +1829,6 @@ bool PlayerbotAI::HasAggro(Unit* unit)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 PlayerbotAI::GetAssistTankIndex(Player* player)
|
|
||||||
{
|
|
||||||
Group* group = player->GetGroup();
|
|
||||||
if (!group)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
int counter = 0;
|
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
|
||||||
{
|
|
||||||
Player* member = ref->GetSource();
|
|
||||||
|
|
||||||
if (!member)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player == member)
|
|
||||||
{
|
|
||||||
return counter;
|
|
||||||
}
|
|
||||||
if (IsTank(member, true) && group->IsAssistant(member->GetGUID()))
|
|
||||||
{
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 PlayerbotAI::GetGroupSlotIndex(Player* player)
|
int32 PlayerbotAI::GetGroupSlotIndex(Player* player)
|
||||||
{
|
{
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
@@ -1891,12 +1840,6 @@ int32 PlayerbotAI::GetGroupSlotIndex(Player* player)
|
|||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
|
|
||||||
if (!member)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player == member)
|
if (player == member)
|
||||||
{
|
{
|
||||||
return counter;
|
return counter;
|
||||||
@@ -1921,12 +1864,6 @@ int32 PlayerbotAI::GetRangedIndex(Player* player)
|
|||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
|
|
||||||
if (!member)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player == member)
|
if (player == member)
|
||||||
{
|
{
|
||||||
return counter;
|
return counter;
|
||||||
@@ -1954,12 +1891,6 @@ int32 PlayerbotAI::GetClassIndex(Player* player, uint8 cls)
|
|||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
|
|
||||||
if (!member)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player == member)
|
if (player == member)
|
||||||
{
|
{
|
||||||
return counter;
|
return counter;
|
||||||
@@ -1986,12 +1917,6 @@ int32 PlayerbotAI::GetRangedDpsIndex(Player* player)
|
|||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
|
|
||||||
if (!member)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player == member)
|
if (player == member)
|
||||||
{
|
{
|
||||||
return counter;
|
return counter;
|
||||||
@@ -2019,12 +1944,6 @@ int32 PlayerbotAI::GetMeleeIndex(Player* player)
|
|||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
|
|
||||||
if (!member)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player == member)
|
if (player == member)
|
||||||
{
|
{
|
||||||
return counter;
|
return counter;
|
||||||
@@ -2196,12 +2115,6 @@ bool PlayerbotAI::IsMainTank(Player* player)
|
|||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
|
|
||||||
if (!member)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsTank(member) && member->IsAlive())
|
if (IsTank(member) && member->IsAlive())
|
||||||
{
|
{
|
||||||
return player->GetGUID() == member->GetGUID();
|
return player->GetGUID() == member->GetGUID();
|
||||||
@@ -2210,62 +2123,6 @@ bool PlayerbotAI::IsMainTank(Player* player)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayerbotAI::IsBotMainTank(Player* player)
|
|
||||||
{
|
|
||||||
if (!player->GetSession()->IsBot() || !IsTank(player))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsMainTank(player))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Group* group = player->GetGroup();
|
|
||||||
if (!group)
|
|
||||||
{
|
|
||||||
return true; // If no group, consider the bot as main tank
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 botAssistTankIndex = GetAssistTankIndex(player);
|
|
||||||
|
|
||||||
if (botAssistTankIndex == -1)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
|
||||||
{
|
|
||||||
Player* member = gref->GetSource();
|
|
||||||
if (!member)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 memberAssistTankIndex = GetAssistTankIndex(member);
|
|
||||||
|
|
||||||
if (memberAssistTankIndex == -1)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (memberAssistTankIndex == botAssistTankIndex && player == member)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (memberAssistTankIndex < botAssistTankIndex && member->GetSession()->IsBot())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 PlayerbotAI::GetGroupTankNum(Player* player)
|
uint32 PlayerbotAI::GetGroupTankNum(Player* player)
|
||||||
{
|
{
|
||||||
Group* group = player->GetGroup();
|
Group* group = player->GetGroup();
|
||||||
@@ -2277,12 +2134,6 @@ uint32 PlayerbotAI::GetGroupTankNum(Player* player)
|
|||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
|
|
||||||
if (!member)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsTank(member) && member->IsAlive())
|
if (IsTank(member) && member->IsAlive())
|
||||||
{
|
{
|
||||||
result++;
|
result++;
|
||||||
@@ -2295,7 +2146,7 @@ bool PlayerbotAI::IsAssistTank(Player* player) { return IsTank(player) && !IsMai
|
|||||||
|
|
||||||
bool PlayerbotAI::IsAssistTankOfIndex(Player* player, int index)
|
bool PlayerbotAI::IsAssistTankOfIndex(Player* player, int index)
|
||||||
{
|
{
|
||||||
Group* group = player->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -2304,12 +2155,6 @@ bool PlayerbotAI::IsAssistTankOfIndex(Player* player, int index)
|
|||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
|
|
||||||
if (!member)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (group->IsAssistant(member->GetGUID()) && IsAssistTank(member))
|
if (group->IsAssistant(member->GetGUID()) && IsAssistTank(member))
|
||||||
{
|
{
|
||||||
if (index == counter)
|
if (index == counter)
|
||||||
@@ -2323,12 +2168,6 @@ bool PlayerbotAI::IsAssistTankOfIndex(Player* player, int index)
|
|||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
|
|
||||||
if (!member)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!group->IsAssistant(member->GetGUID()) && IsAssistTank(member))
|
if (!group->IsAssistant(member->GetGUID()) && IsAssistTank(member))
|
||||||
{
|
{
|
||||||
if (index == counter)
|
if (index == counter)
|
||||||
@@ -2508,6 +2347,7 @@ std::string PlayerbotAI::GetLocalizedCreatureName(uint32 entry)
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string PlayerbotAI::GetLocalizedGameObjectName(uint32 entry)
|
std::string PlayerbotAI::GetLocalizedGameObjectName(uint32 entry)
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
@@ -2536,11 +2376,6 @@ std::vector<Player*> PlayerbotAI::GetPlayersInGroup()
|
|||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
|
|
||||||
if (!member)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GET_PLAYERBOT_AI(member) && !GET_PLAYERBOT_AI(member)->IsRealPlayer())
|
if (GET_PLAYERBOT_AI(member) && !GET_PLAYERBOT_AI(member)->IsRealPlayer())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -3091,18 +2926,6 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((bot->GetShapeshiftForm() == FORM_FLIGHT || bot->GetShapeshiftForm() == FORM_FLIGHT_EPIC) && !bot->IsInCombat())
|
|
||||||
{
|
|
||||||
if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster()))
|
|
||||||
{
|
|
||||||
LOG_DEBUG(
|
|
||||||
"playerbots",
|
|
||||||
"Can cast spell failed. In flight form (not in combat). - target name: {}, spellid: {}, bot name: {}",
|
|
||||||
target->GetName(), spellid, bot->GetName());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 CastingTime = !spellInfo->IsChanneled() ? spellInfo->CalcCastTime(bot) : spellInfo->GetDuration();
|
uint32 CastingTime = !spellInfo->IsChanneled() ? spellInfo->CalcCastTime(bot) : spellInfo->GetDuration();
|
||||||
// bool interruptOnMove = spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT;
|
// bool interruptOnMove = spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT;
|
||||||
if ((CastingTime || spellInfo->IsAutoRepeatRangedSpell()) && bot->isMoving())
|
if ((CastingTime || spellInfo->IsAutoRepeatRangedSpell()) && bot->isMoving())
|
||||||
@@ -3117,10 +2940,7 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell,
|
|||||||
|
|
||||||
if (!itemTarget)
|
if (!itemTarget)
|
||||||
{
|
{
|
||||||
// Exception for Deep Freeze (44572) - allow cast for damage on immune targets (e.g., bosses)
|
|
||||||
if (target->IsImmunedToSpell(spellInfo))
|
if (target->IsImmunedToSpell(spellInfo))
|
||||||
{
|
|
||||||
if (spellid != 44572) // Deep Freeze
|
|
||||||
{
|
{
|
||||||
if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster()))
|
if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster()))
|
||||||
{
|
{
|
||||||
@@ -3129,8 +2949,6 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell,
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Otherwise, allow Deep Freeze even if immune
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bot != target && sServerFacade->GetDistance2d(bot, target) > sPlayerbotAIConfig->sightDistance)
|
if (bot != target && sServerFacade->GetDistance2d(bot, target) > sPlayerbotAIConfig->sightDistance)
|
||||||
{
|
{
|
||||||
@@ -3325,24 +3143,6 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget)
|
|||||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||||
if (pet && pet->HasSpell(spellId))
|
if (pet && pet->HasSpell(spellId))
|
||||||
{
|
{
|
||||||
// List of spell IDs for which we do NOT want to toggle auto-cast or send message
|
|
||||||
// We are excluding Spell Lock and Devour Magic because they are casted in the GenericWarlockStrategy
|
|
||||||
// Without this exclusion, the skill would be togged for auto-cast and the player would
|
|
||||||
// be spammed with messages about enabling/disabling auto-cast
|
|
||||||
switch (spellId)
|
|
||||||
{
|
|
||||||
case 19244: // Spell Lock rank 1
|
|
||||||
case 19647: // Spell Lock rank 2
|
|
||||||
case 19505: // Devour Magic rank 1
|
|
||||||
case 19731: // Devour Magic rank 2
|
|
||||||
case 19734: // Devour Magic rank 3
|
|
||||||
case 19736: // Devour Magic rank 4
|
|
||||||
case 27276: // Devour Magic rank 5
|
|
||||||
case 27277: // Devour Magic rank 6
|
|
||||||
case 48011: // Devour Magic rank 7
|
|
||||||
// No message - just break out of the switch and let normal cast logic continue
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
bool autocast = false;
|
bool autocast = false;
|
||||||
for (unsigned int& m_autospell : pet->m_autospells)
|
for (unsigned int& m_autospell : pet->m_autospells)
|
||||||
{
|
{
|
||||||
@@ -3360,7 +3160,6 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget)
|
|||||||
TellMaster(out);
|
TellMaster(out);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// aiObjectContext->GetValue<LastMovement&>("last movement")->Get().Set(nullptr);
|
// aiObjectContext->GetValue<LastMovement&>("last movement")->Get().Set(nullptr);
|
||||||
// aiObjectContext->GetValue<time_t>("stay time")->Set(0);
|
// aiObjectContext->GetValue<time_t>("stay time")->Set(0);
|
||||||
@@ -3501,8 +3300,7 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget)
|
|||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << "Spell cast failed - ";
|
out << "Spell cast failed - ";
|
||||||
out << "Spell ID: " << spellId << " (" << ChatHelper::FormatSpell(spellInfo) << "), ";
|
out << "Spell ID: " << spellId << " (" << ChatHelper::FormatSpell(spellInfo) << "), ";
|
||||||
out << "Error Code: " << static_cast<int>(result) << " (0x" << std::hex << static_cast<int>(result)
|
out << "Error Code: " << static_cast<int>(result) << " (0x" << std::hex << static_cast<int>(result) << std::dec << "), ";
|
||||||
<< std::dec << "), ";
|
|
||||||
out << "Bot: " << bot->GetName() << ", ";
|
out << "Bot: " << bot->GetName() << ", ";
|
||||||
|
|
||||||
// Check spell target type
|
// Check spell target type
|
||||||
@@ -4556,28 +4354,26 @@ bool PlayerbotAI::AllowActivity(ActivityType activityType, bool checkNow)
|
|||||||
|
|
||||||
uint32 PlayerbotAI::AutoScaleActivity(uint32 mod)
|
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 maxDiff = sWorldUpdateTime.GetMaxUpdateTimeOfCurrentTable();
|
||||||
uint32 diffLimitFloor = sPlayerbotAIConfig->botActiveAloneSmartScaleDiffLimitfloor;
|
uint32 diffLimitFloor = sPlayerbotAIConfig->botActiveAloneSmartScaleDiffLimitfloor;
|
||||||
uint32 diffLimitCeiling = sPlayerbotAIConfig->botActiveAloneSmartScaleDiffLimitCeiling;
|
uint32 diffLimitCeiling = sPlayerbotAIConfig->botActiveAloneSmartScaleDiffLimitCeiling;
|
||||||
|
double spreadSize = (double)(diffLimitCeiling - diffLimitFloor) / 6;
|
||||||
|
|
||||||
if (diffLimitCeiling <= diffLimitFloor)
|
// apply scaling
|
||||||
{
|
|
||||||
// Perfrom binary decision if ceiling <= floor: Either all bots are active or none are
|
|
||||||
return (maxDiff > diffLimitCeiling) ? 0 : mod;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maxDiff > diffLimitCeiling)
|
if (maxDiff > diffLimitCeiling)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (maxDiff > diffLimitFloor + (4 * spreadSize))
|
||||||
|
return (mod * 1) / 10;
|
||||||
|
if (maxDiff > diffLimitFloor + (3 * spreadSize))
|
||||||
|
return (mod * 3) / 10;
|
||||||
|
if (maxDiff > diffLimitFloor + (2 * spreadSize))
|
||||||
|
return (mod * 5) / 10;
|
||||||
|
if (maxDiff > diffLimitFloor + (1 * spreadSize))
|
||||||
|
return (mod * 7) / 10;
|
||||||
|
if (maxDiff > diffLimitFloor)
|
||||||
|
return (mod * 9) / 10;
|
||||||
|
|
||||||
if (maxDiff <= diffLimitFloor)
|
|
||||||
return mod;
|
return mod;
|
||||||
|
|
||||||
// Calculate lag progress from floor to ceiling (0 to 1)
|
|
||||||
double lagProgress = (maxDiff - diffLimitFloor) / (double)(diffLimitCeiling - diffLimitFloor);
|
|
||||||
|
|
||||||
// Apply the percentage of active bots (the complement of lag progress) to the mod value
|
|
||||||
return static_cast<uint32>(mod * (1 - lagProgress));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayerbotAI::IsOpposing(Player* player) { return IsOpposing(player->getRace(), bot->getRace()); }
|
bool PlayerbotAI::IsOpposing(Player* player) { return IsOpposing(player->getRace(), bot->getRace()); }
|
||||||
@@ -4602,48 +4398,9 @@ void PlayerbotAI::RemoveShapeshift()
|
|||||||
// RemoveAura("tree of life");
|
// RemoveAura("tree of life");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mirrors Blizzard’s GetAverageItemLevel rules :
|
|
||||||
// https://wowpedia.fandom.com/wiki/API_GetAverageItemLevel
|
|
||||||
uint32 PlayerbotAI::GetEquipGearScore(Player* player)
|
|
||||||
{
|
|
||||||
constexpr uint8 TOTAL_SLOTS = 17; // every slot except Body & Tabard
|
|
||||||
uint32 sumLevel = 0;
|
|
||||||
|
|
||||||
/* ---------- 0. Detect “ignore off-hand” situations --------- */
|
|
||||||
Item* main = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
|
|
||||||
Item* off = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
|
|
||||||
|
|
||||||
bool ignoreOffhand = false; // true → divisor = 16
|
|
||||||
if (main)
|
|
||||||
{
|
|
||||||
bool twoHand = (main->GetTemplate()->InventoryType == INVTYPE_2HWEAPON);
|
|
||||||
if (twoHand && !player->HasAura(SPELL_TITAN_GRIP))
|
|
||||||
ignoreOffhand = true; // classic 2-hander
|
|
||||||
}
|
|
||||||
else if (!off) // both hands empty
|
|
||||||
ignoreOffhand = true;
|
|
||||||
|
|
||||||
/* ---------- 1. Sum up item-levels -------------------------- */
|
|
||||||
for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
|
|
||||||
{
|
|
||||||
if (slot == EQUIPMENT_SLOT_BODY || slot == EQUIPMENT_SLOT_TABARD)
|
|
||||||
continue; // Blizzard never counts these
|
|
||||||
|
|
||||||
if (ignoreOffhand && slot == EQUIPMENT_SLOT_OFFHAND)
|
|
||||||
continue; // skip off-hand in 2-H case
|
|
||||||
|
|
||||||
if (Item* it = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
|
||||||
sumLevel += it->GetTemplate()->ItemLevel; // missing items add 0
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- 2. Divide by 17 or 16 -------------------------- */
|
|
||||||
const uint8 divisor = ignoreOffhand ? TOTAL_SLOTS - 1 : TOTAL_SLOTS; // 16 or 17
|
|
||||||
return sumLevel / divisor;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE : function rewritten as flags "withBags" and "withBank" not used, and _fillGearScoreData sometimes attribute
|
// NOTE : function rewritten as flags "withBags" and "withBank" not used, and _fillGearScoreData sometimes attribute
|
||||||
// one-hand/2H Weapon in wrong slots
|
// one-hand/2H Weapon in wrong slots
|
||||||
/*uint32 PlayerbotAI::GetEquipGearScore(Player* player)
|
uint32 PlayerbotAI::GetEquipGearScore(Player* player)
|
||||||
{
|
{
|
||||||
// This function aims to calculate the equipped gear score
|
// This function aims to calculate the equipped gear score
|
||||||
|
|
||||||
@@ -4669,7 +4426,7 @@ uint32 PlayerbotAI::GetEquipGearScore(Player* player)
|
|||||||
|
|
||||||
uint32 gs = uint32(sum / count);
|
uint32 gs = uint32(sum / count);
|
||||||
return gs;
|
return gs;
|
||||||
}*/
|
}
|
||||||
|
|
||||||
/*uint32 PlayerbotAI::GetEquipGearScore(Player* player, bool withBags, bool withBank)
|
/*uint32 PlayerbotAI::GetEquipGearScore(Player* player, bool withBags, bool withBank)
|
||||||
{
|
{
|
||||||
@@ -4902,7 +4659,7 @@ void PlayerbotAI::_fillGearScoreData(Player* player, Item* item, std::vector<uin
|
|||||||
case INVTYPE_SHOULDERS:
|
case INVTYPE_SHOULDERS:
|
||||||
(*gearScore)[EQUIPMENT_SLOT_SHOULDERS] = std::max((*gearScore)[EQUIPMENT_SLOT_SHOULDERS], level);
|
(*gearScore)[EQUIPMENT_SLOT_SHOULDERS] = std::max((*gearScore)[EQUIPMENT_SLOT_SHOULDERS], level);
|
||||||
break;
|
break;
|
||||||
case INVTYPE_BODY: // Shouldn't be considered when calculating average ilevel
|
case INVTYPE_BODY: //Shouldn't be considered when calculating average ilevel
|
||||||
(*gearScore)[EQUIPMENT_SLOT_BODY] = std::max((*gearScore)[EQUIPMENT_SLOT_BODY], level);
|
(*gearScore)[EQUIPMENT_SLOT_BODY] = std::max((*gearScore)[EQUIPMENT_SLOT_BODY], level);
|
||||||
break;
|
break;
|
||||||
case INVTYPE_CHEST:
|
case INVTYPE_CHEST:
|
||||||
@@ -5260,13 +5017,13 @@ Item* PlayerbotAI::FindAmmo() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find Consumable
|
// Find Consumable
|
||||||
Item* PlayerbotAI::FindConsumable(uint32 itemId) const
|
Item* PlayerbotAI::FindConsumable(uint32 displayId) const
|
||||||
{
|
{
|
||||||
return FindItemInInventory(
|
return FindItemInInventory(
|
||||||
[itemId](ItemTemplate const* pItemProto) -> bool
|
[displayId](ItemTemplate const* pItemProto) -> bool
|
||||||
{
|
{
|
||||||
return (pItemProto->Class == ITEM_CLASS_CONSUMABLE || pItemProto->Class == ITEM_CLASS_TRADE_GOODS) &&
|
return (pItemProto->Class == ITEM_CLASS_CONSUMABLE || pItemProto->Class == ITEM_CLASS_TRADE_GOODS) &&
|
||||||
pItemProto->ItemId == itemId;
|
pItemProto->DisplayInfoID == displayId;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5280,8 +5037,7 @@ Item* PlayerbotAI::FindBandage() const
|
|||||||
|
|
||||||
Item* PlayerbotAI::FindOpenableItem() const
|
Item* PlayerbotAI::FindOpenableItem() const
|
||||||
{
|
{
|
||||||
return FindItemInInventory(
|
return FindItemInInventory([this](ItemTemplate const* itemTemplate) -> bool
|
||||||
[this](ItemTemplate const* itemTemplate) -> bool
|
|
||||||
{
|
{
|
||||||
return (itemTemplate->Flags & ITEM_FLAG_HAS_LOOT) &&
|
return (itemTemplate->Flags & ITEM_FLAG_HAS_LOOT) &&
|
||||||
(itemTemplate->LockID == 0 || !this->bot->GetItemByEntry(itemTemplate->ItemId)->IsLocked());
|
(itemTemplate->LockID == 0 || !this->bot->GetItemByEntry(itemTemplate->ItemId)->IsLocked());
|
||||||
@@ -5290,8 +5046,7 @@ Item* PlayerbotAI::FindOpenableItem() const
|
|||||||
|
|
||||||
Item* PlayerbotAI::FindLockedItem() const
|
Item* PlayerbotAI::FindLockedItem() const
|
||||||
{
|
{
|
||||||
return FindItemInInventory(
|
return FindItemInInventory([this](ItemTemplate const* itemTemplate) -> bool
|
||||||
[this](ItemTemplate const* itemTemplate) -> bool
|
|
||||||
{
|
{
|
||||||
if (!this->bot->HasSkill(SKILL_LOCKPICKING)) // Ensure bot has Lockpicking skill
|
if (!this->bot->HasSkill(SKILL_LOCKPICKING)) // Ensure bot has Lockpicking skill
|
||||||
return false;
|
return false;
|
||||||
@@ -5326,34 +5081,36 @@ Item* PlayerbotAI::FindLockedItem() const
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const uint32 uPriorizedSharpStoneIds[8] = {ADAMANTITE_SHARPENING_DISPLAYID, FEL_SHARPENING_DISPLAYID,
|
||||||
|
ELEMENTAL_SHARPENING_DISPLAYID, DENSE_SHARPENING_DISPLAYID,
|
||||||
|
SOLID_SHARPENING_DISPLAYID, HEAVY_SHARPENING_DISPLAYID,
|
||||||
|
COARSE_SHARPENING_DISPLAYID, ROUGH_SHARPENING_DISPLAYID};
|
||||||
|
|
||||||
|
static const uint32 uPriorizedWeightStoneIds[7] = {ADAMANTITE_WEIGHTSTONE_DISPLAYID, FEL_WEIGHTSTONE_DISPLAYID,
|
||||||
|
DENSE_WEIGHTSTONE_DISPLAYID, SOLID_WEIGHTSTONE_DISPLAYID,
|
||||||
|
HEAVY_WEIGHTSTONE_DISPLAYID, COARSE_WEIGHTSTONE_DISPLAYID,
|
||||||
|
ROUGH_WEIGHTSTONE_DISPLAYID};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FindStoneFor()
|
||||||
|
* return Item* Returns sharpening/weight stone item eligible to enchant a bot weapon
|
||||||
|
*
|
||||||
|
* params:weapon Item* the weap<61>n the function should search and return a enchanting item for
|
||||||
|
* return nullptr if no relevant item is found in bot inventory, else return a sharpening or weight
|
||||||
|
* stone based on the weapon subclass
|
||||||
|
*
|
||||||
|
*/
|
||||||
Item* PlayerbotAI::FindStoneFor(Item* weapon) const
|
Item* PlayerbotAI::FindStoneFor(Item* weapon) const
|
||||||
{
|
{
|
||||||
if (!weapon)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
const ItemTemplate* item_template = weapon->GetTemplate();
|
|
||||||
if (!item_template)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
static const std::vector<uint32_t> uPrioritizedSharpStoneIds = {
|
|
||||||
ADAMANTITE_SHARPENING_STONE, FEL_SHARPENING_STONE, ELEMENTAL_SHARPENING_STONE, DENSE_SHARPENING_STONE,
|
|
||||||
SOLID_SHARPENING_STONE, HEAVY_SHARPENING_STONE, COARSE_SHARPENING_STONE, ROUGH_SHARPENING_STONE
|
|
||||||
};
|
|
||||||
|
|
||||||
static const std::vector<uint32_t> uPrioritizedWeightStoneIds = {
|
|
||||||
ADAMANTITE_WEIGHTSTONE, FEL_WEIGHTSTONE, DENSE_WEIGHTSTONE, SOLID_WEIGHTSTONE,
|
|
||||||
HEAVY_WEIGHTSTONE, COARSE_WEIGHTSTONE, ROUGH_WEIGHTSTONE
|
|
||||||
};
|
|
||||||
|
|
||||||
Item* stone = nullptr;
|
Item* stone = nullptr;
|
||||||
ItemTemplate const* pProto = weapon->GetTemplate();
|
ItemTemplate const* pProto = weapon->GetTemplate();
|
||||||
if (pProto && (pProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD || pProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2 ||
|
if (pProto && (pProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD || pProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2 ||
|
||||||
pProto->SubClass == ITEM_SUBCLASS_WEAPON_AXE || pProto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2 ||
|
pProto->SubClass == ITEM_SUBCLASS_WEAPON_AXE || pProto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2 ||
|
||||||
pProto->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER || pProto->SubClass == ITEM_SUBCLASS_WEAPON_POLEARM))
|
pProto->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER))
|
||||||
{
|
{
|
||||||
for (uint8 i = 0; i < std::size(uPrioritizedSharpStoneIds); ++i)
|
for (uint8 i = 0; i < std::size(uPriorizedSharpStoneIds); ++i)
|
||||||
{
|
{
|
||||||
stone = FindConsumable(uPrioritizedSharpStoneIds[i]);
|
stone = FindConsumable(uPriorizedSharpStoneIds[i]);
|
||||||
if (stone)
|
if (stone)
|
||||||
{
|
{
|
||||||
return stone;
|
return stone;
|
||||||
@@ -5361,12 +5118,11 @@ static const std::vector<uint32_t> uPrioritizedWeightStoneIds = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (pProto &&
|
else if (pProto &&
|
||||||
(pProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE || pProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE2 ||
|
(pProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE || pProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE2))
|
||||||
pProto->SubClass == ITEM_SUBCLASS_WEAPON_STAFF || pProto->SubClass == ITEM_SUBCLASS_WEAPON_FIST))
|
|
||||||
{
|
{
|
||||||
for (uint8 i = 0; i < std::size(uPrioritizedWeightStoneIds); ++i)
|
for (uint8 i = 0; i < std::size(uPriorizedWeightStoneIds); ++i)
|
||||||
{
|
{
|
||||||
stone = FindConsumable(uPrioritizedWeightStoneIds[i]);
|
stone = FindConsumable(uPriorizedWeightStoneIds[i]);
|
||||||
if (stone)
|
if (stone)
|
||||||
{
|
{
|
||||||
return stone;
|
return stone;
|
||||||
@@ -5379,7 +5135,6 @@ static const std::vector<uint32_t> uPrioritizedWeightStoneIds = {
|
|||||||
|
|
||||||
Item* PlayerbotAI::FindOilFor(Item* weapon) const
|
Item* PlayerbotAI::FindOilFor(Item* weapon) const
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!weapon)
|
if (!weapon)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
@@ -5387,61 +5142,36 @@ Item* PlayerbotAI::FindOilFor(Item* weapon) const
|
|||||||
if (!item_template)
|
if (!item_template)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
static const std::vector<uint32_t> uPrioritizedWizardOilIds = {
|
// static const will only get created once whatever the call amout
|
||||||
BRILLIANT_WIZARD_OIL, SUPERIOR_WIZARD_OIL, WIZARD_OIL, LESSER_WIZARD_OIL, MINOR_WIZARD_OIL,
|
static const std::vector<uint32_t> uPriorizedWizardOilIds = {
|
||||||
BRILLIANT_MANA_OIL, SUPERIOR_MANA_OIL, LESSER_MANA_OIL, MINOR_MANA_OIL};
|
MINOR_WIZARD_OIL, MINOR_MANA_OIL, LESSER_WIZARD_OIL, LESSER_MANA_OIL, BRILLIANT_WIZARD_OIL,
|
||||||
|
BRILLIANT_MANA_OIL, WIZARD_OIL, SUPERIOR_MANA_OIL, SUPERIOR_WIZARD_OIL};
|
||||||
|
|
||||||
static const std::vector<uint32_t> uPrioritizedManaOilIds = {
|
// static const will only get created once whatever the call amout
|
||||||
BRILLIANT_MANA_OIL, SUPERIOR_MANA_OIL, LESSER_MANA_OIL, MINOR_MANA_OIL,
|
static const std::vector<uint32_t> uPriorizedManaOilIds = {
|
||||||
BRILLIANT_WIZARD_OIL, SUPERIOR_WIZARD_OIL, WIZARD_OIL, LESSER_WIZARD_OIL, MINOR_WIZARD_OIL};
|
MINOR_MANA_OIL, MINOR_WIZARD_OIL, LESSER_MANA_OIL, LESSER_WIZARD_OIL, BRILLIANT_MANA_OIL,
|
||||||
|
BRILLIANT_WIZARD_OIL, SUPERIOR_MANA_OIL, WIZARD_OIL, SUPERIOR_WIZARD_OIL};
|
||||||
|
|
||||||
Item* oil = nullptr;
|
Item* oil = nullptr;
|
||||||
int botClass = bot->getClass();
|
if (item_template->SubClass == ITEM_SUBCLASS_WEAPON_SWORD ||
|
||||||
int specTab = AiFactory::GetPlayerSpecTab(bot);
|
item_template->SubClass == ITEM_SUBCLASS_WEAPON_STAFF || item_template->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER)
|
||||||
|
|
||||||
const std::vector<uint32_t>* prioritizedOils = nullptr;
|
|
||||||
switch (botClass)
|
|
||||||
{
|
{
|
||||||
case CLASS_PRIEST:
|
for (const auto& id : uPriorizedWizardOilIds)
|
||||||
prioritizedOils = (specTab == 2) ? &uPrioritizedWizardOilIds : &uPrioritizedManaOilIds;
|
|
||||||
break;
|
|
||||||
case CLASS_MAGE:
|
|
||||||
prioritizedOils = &uPrioritizedWizardOilIds;
|
|
||||||
break;
|
|
||||||
case CLASS_DRUID:
|
|
||||||
if (specTab == 0) // Balance
|
|
||||||
prioritizedOils = &uPrioritizedWizardOilIds;
|
|
||||||
else if (specTab == 1) // Feral
|
|
||||||
prioritizedOils = nullptr;
|
|
||||||
else // Restoration (specTab == 2) or any other/unspecified spec
|
|
||||||
prioritizedOils = &uPrioritizedManaOilIds;
|
|
||||||
break;
|
|
||||||
case CLASS_HUNTER:
|
|
||||||
prioritizedOils = &uPrioritizedManaOilIds;
|
|
||||||
break;
|
|
||||||
case CLASS_PALADIN:
|
|
||||||
if (specTab == 1) // Protection
|
|
||||||
prioritizedOils = &uPrioritizedWizardOilIds;
|
|
||||||
else if (specTab == 2) // Retribution
|
|
||||||
prioritizedOils = nullptr;
|
|
||||||
else // Holy (specTab == 0) or any other/unspecified spec
|
|
||||||
prioritizedOils = &uPrioritizedManaOilIds;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
prioritizedOils = &uPrioritizedManaOilIds;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prioritizedOils)
|
|
||||||
{
|
|
||||||
for (const auto& id : *prioritizedOils)
|
|
||||||
{
|
{
|
||||||
oil = FindConsumable(id);
|
oil = FindConsumable(id);
|
||||||
if (oil)
|
if (oil)
|
||||||
{
|
|
||||||
return oil;
|
return oil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (item_template->SubClass == ITEM_SUBCLASS_WEAPON_MACE ||
|
||||||
|
item_template->SubClass == ITEM_SUBCLASS_WEAPON_MACE2)
|
||||||
|
{
|
||||||
|
for (const auto& id : uPriorizedManaOilIds)
|
||||||
|
{
|
||||||
|
oil = FindConsumable(id);
|
||||||
|
if (oil)
|
||||||
|
return oil;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return oil;
|
return oil;
|
||||||
@@ -6271,35 +6001,6 @@ ChatChannelSource PlayerbotAI::GetChatChannelSource(Player* bot, uint32 type, st
|
|||||||
return ChatChannelSource::SRC_UNDEFINED;
|
return ChatChannelSource::SRC_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayerbotAI::CheckLocationDistanceByLevel(Player* player, const WorldLocation& loc, bool fromStartUp)
|
|
||||||
{
|
|
||||||
if (player->GetLevel() > 16)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
float dis = 0.0f;
|
|
||||||
if (fromStartUp)
|
|
||||||
{
|
|
||||||
PlayerInfo const* pInfo = sObjectMgr->GetPlayerInfo(player->getRace(true), player->getClass());
|
|
||||||
if (loc.GetMapId() != pInfo->mapId)
|
|
||||||
return false;
|
|
||||||
dis = loc.GetExactDist(pInfo->positionX, pInfo->positionY, pInfo->positionZ);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (loc.GetMapId() != player->GetMapId())
|
|
||||||
return false;
|
|
||||||
dis = loc.GetExactDist(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
float bound = 10000.0f;
|
|
||||||
if (player->GetLevel() <= 4)
|
|
||||||
bound = 500.0f;
|
|
||||||
else if (player->GetLevel() <= 10)
|
|
||||||
bound = 2500.0f;
|
|
||||||
|
|
||||||
return dis <= bound;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<const Quest*> PlayerbotAI::GetAllCurrentQuests()
|
std::vector<const Quest*> PlayerbotAI::GetAllCurrentQuests()
|
||||||
{
|
{
|
||||||
std::vector<const Quest*> result;
|
std::vector<const Quest*> result;
|
||||||
@@ -6569,33 +6270,3 @@ SpellFamilyNames PlayerbotAI::Class2SpellFamilyName(uint8 cls)
|
|||||||
}
|
}
|
||||||
return SPELLFAMILY_GENERIC;
|
return SPELLFAMILY_GENERIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerbotAI::AddTimedEvent(std::function<void()> callback, uint32 delayMs)
|
|
||||||
{
|
|
||||||
class LambdaEvent final : public BasicEvent
|
|
||||||
{
|
|
||||||
std::function<void()> _cb;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit LambdaEvent(std::function<void()> cb) : _cb(std::move(cb)) {}
|
|
||||||
bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override
|
|
||||||
{
|
|
||||||
_cb();
|
|
||||||
return true; // remove after execution
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Every Player already owns an EventMap called m_Events
|
|
||||||
bot->m_Events.AddEvent(new LambdaEvent(std::move(callback)), bot->m_Events.CalculateTime(delayMs));
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerbotAI::EvaluateHealerDpsStrategy()
|
|
||||||
{
|
|
||||||
if (!IsHeal(bot, true))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (sPlayerbotAIConfig->IsRestrictedHealerDPSMap(bot->GetMapId()))
|
|
||||||
ChangeStrategy("-healer dps", BOT_STATE_COMBAT);
|
|
||||||
else
|
|
||||||
ChangeStrategy("+healer dps", BOT_STATE_COMBAT);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -46,27 +46,27 @@ struct GameObjectData;
|
|||||||
|
|
||||||
enum StrategyType : uint32;
|
enum StrategyType : uint32;
|
||||||
|
|
||||||
enum HealingItemId
|
enum HealingItemDisplayId
|
||||||
{
|
{
|
||||||
HEALTHSTONE = 5512,
|
HEALTHSTONE_DISPLAYID = 8026,
|
||||||
MAJOR_HEALING_POTION = 13446,
|
MAJOR_HEALING_POTION = 24152,
|
||||||
WHIPPER_ROOT_TUBER = 11951,
|
WHIPPER_ROOT_TUBER = 21974,
|
||||||
NIGHT_DRAGON_BREATH = 11952,
|
NIGHT_DRAGON_BREATH = 21975,
|
||||||
LIMITED_INVULNERABILITY_POTION = 3387,
|
LIMITED_INVULNERABILITY_POTION = 24213,
|
||||||
GREATER_DREAMLESS_SLEEP_POTION = 22886,
|
GREATER_DREAMLESS_SLEEP_POTION = 17403,
|
||||||
SUPERIOR_HEALING_POTION = 3928,
|
SUPERIOR_HEALING_POTION = 15714,
|
||||||
CRYSTAL_RESTORE = 11564,
|
CRYSTAL_RESTORE = 2516,
|
||||||
DREAMLESS_SLEEP_POTION = 12190,
|
DREAMLESS_SLEEP_POTION = 17403,
|
||||||
GREATER_HEALING_POTION = 1710,
|
GREATER_HEALING_POTION = 15713,
|
||||||
HEALING_POTION = 929,
|
HEALING_POTION = 15712,
|
||||||
LESSER_HEALING_POTION = 858,
|
LESSER_HEALING_POTION = 15711,
|
||||||
DISCOLORED_HEALING_POTION = 3391,
|
DISCOLORED_HEALING_POTION = 15736,
|
||||||
MINOR_HEALING_POTION = 118,
|
MINOR_HEALING_POTION = 15710,
|
||||||
VOLATILE_HEALING_POTION = 28100,
|
VOLATILE_HEALING_POTION = 24212,
|
||||||
SUPER_HEALING_POTION = 22829,
|
SUPER_HEALING_POTION = 37807,
|
||||||
CRYSTAL_HEALING_POTION = 13462,
|
CRYSTAL_HEALING_POTION = 47132,
|
||||||
FEL_REGENERATION_POTION = 28101,
|
FEL_REGENERATION_POTION = 37864,
|
||||||
MAJOR_DREAMLESS_SLEEP_POTION = 20002
|
MAJOR_DREAMLESS_SLEEP_POTION = 37845
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BotState
|
enum BotState
|
||||||
@@ -152,7 +152,6 @@ static std::map<ChatChannelSource, std::string> ChatChannelSourceStr = {
|
|||||||
{SRC_RAID, "SRC_RAID"},
|
{SRC_RAID, "SRC_RAID"},
|
||||||
|
|
||||||
{SRC_UNDEFINED, "SRC_UNDEFINED"}};
|
{SRC_UNDEFINED, "SRC_UNDEFINED"}};
|
||||||
|
|
||||||
enum ChatChannelId
|
enum ChatChannelId
|
||||||
{
|
{
|
||||||
GENERAL = 1,
|
GENERAL = 1,
|
||||||
@@ -163,66 +162,60 @@ enum ChatChannelId
|
|||||||
GUILD_RECRUITMENT = 25,
|
GUILD_RECRUITMENT = 25,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RoguePoisonId
|
enum RoguePoisonDisplayId
|
||||||
{
|
{
|
||||||
INSTANT_POISON = 6947,
|
DEADLY_POISON_DISPLAYID = 13707,
|
||||||
INSTANT_POISON_II = 6949,
|
INSTANT_POISON_DISPLAYID = 13710,
|
||||||
INSTANT_POISON_III = 6950,
|
WOUND_POISON_DISPLAYID = 37278
|
||||||
INSTANT_POISON_IV = 8926,
|
|
||||||
INSTANT_POISON_V = 8927,
|
|
||||||
INSTANT_POISON_VI = 8928,
|
|
||||||
INSTANT_POISON_VII = 21927,
|
|
||||||
INSTANT_POISON_VIII = 43230,
|
|
||||||
INSTANT_POISON_IX = 43231,
|
|
||||||
DEADLY_POISON = 2892,
|
|
||||||
DEADLY_POISON_II = 2893,
|
|
||||||
DEADLY_POISON_III = 8984,
|
|
||||||
DEADLY_POISON_IV = 8985,
|
|
||||||
DEADLY_POISON_V = 20844,
|
|
||||||
DEADLY_POISON_VI = 22053,
|
|
||||||
DEADLY_POISON_VII = 22054,
|
|
||||||
DEADLY_POISON_VIII = 43232,
|
|
||||||
DEADLY_POISON_IX = 43233
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SharpeningStoneId
|
enum SharpeningStoneDisplayId
|
||||||
{
|
{
|
||||||
ROUGH_SHARPENING_STONE = 2862,
|
ROUGH_SHARPENING_DISPLAYID = 24673,
|
||||||
COARSE_SHARPENING_STONE = 2863,
|
COARSE_SHARPENING_DISPLAYID = 24674,
|
||||||
HEAVY_SHARPENING_STONE = 2871,
|
HEAVY_SHARPENING_DISPLAYID = 24675,
|
||||||
SOLID_SHARPENING_STONE = 7964,
|
SOLID_SHARPENING_DISPLAYID = 24676,
|
||||||
DENSE_SHARPENING_STONE = 12404,
|
DENSE_SHARPENING_DISPLAYID = 24677,
|
||||||
ELEMENTAL_SHARPENING_STONE = 18262,
|
CONSECRATED_SHARPENING_DISPLAYID =
|
||||||
FEL_SHARPENING_STONE = 23528,
|
24674, // will not be used because bot can not know if it will face undead targets
|
||||||
ADAMANTITE_SHARPENING_STONE = 23529
|
ELEMENTAL_SHARPENING_DISPLAYID = 21072,
|
||||||
|
FEL_SHARPENING_DISPLAYID = 39192,
|
||||||
|
ADAMANTITE_SHARPENING_DISPLAYID = 39193
|
||||||
};
|
};
|
||||||
|
|
||||||
enum WeightstoneId
|
enum WeightStoneDisplayId
|
||||||
{
|
{
|
||||||
ROUGH_WEIGHTSTONE = 3239,
|
ROUGH_WEIGHTSTONE_DISPLAYID = 24683,
|
||||||
COARSE_WEIGHTSTONE = 3240,
|
COARSE_WEIGHTSTONE_DISPLAYID = 24684,
|
||||||
HEAVY_WEIGHTSTONE = 3241,
|
HEAVY_WEIGHTSTONE_DISPLAYID = 24685,
|
||||||
SOLID_WEIGHTSTONE = 7965,
|
SOLID_WEIGHTSTONE_DISPLAYID = 24686,
|
||||||
DENSE_WEIGHTSTONE = 12643,
|
DENSE_WEIGHTSTONE_DISPLAYID = 24687,
|
||||||
FEL_WEIGHTSTONE = 28420,
|
FEL_WEIGHTSTONE_DISPLAYID = 39548,
|
||||||
ADAMANTITE_WEIGHTSTONE = 28421
|
ADAMANTITE_WEIGHTSTONE_DISPLAYID = 39549
|
||||||
};
|
};
|
||||||
|
|
||||||
enum WizardOilId
|
enum WizardOilDisplayId
|
||||||
{
|
{
|
||||||
MINOR_WIZARD_OIL = 20744,
|
MINOR_WIZARD_OIL = 9731,
|
||||||
LESSER_WIZARD_OIL = 20746,
|
LESSER_WIZARD_OIL = 47903,
|
||||||
WIZARD_OIL = 20750,
|
BRILLIANT_WIZARD_OIL = 47901,
|
||||||
BRILLIANT_WIZARD_OIL = 20749,
|
WIZARD_OIL = 47905,
|
||||||
SUPERIOR_WIZARD_OIL = 22522
|
SUPERIOR_WIZARD_OIL = 47904,
|
||||||
|
/// Blessed Wizard Oil = 26865 //scourge inv
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ManaOilId
|
enum ManaOilDisplayId
|
||||||
{
|
{
|
||||||
MINOR_MANA_OIL = 20745,
|
MINOR_MANA_OIL = 34492,
|
||||||
LESSER_MANA_OIL = 20747,
|
LESSER_MANA_OIL = 47902,
|
||||||
BRILLIANT_MANA_OIL = 20748,
|
BRILLIANT_MANA_OIL = 41488,
|
||||||
SUPERIOR_MANA_OIL = 22521
|
SUPERIOR_MANA_OIL = 36862
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ShieldWardDisplayId
|
||||||
|
{
|
||||||
|
LESSER_WARD_OFSHIELDING = 38759,
|
||||||
|
GREATER_WARD_OFSHIELDING = 38760
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class BotTypeNumber : uint8
|
enum class BotTypeNumber : uint8
|
||||||
@@ -408,7 +401,6 @@ public:
|
|||||||
void ClearStrategies(BotState type);
|
void ClearStrategies(BotState type);
|
||||||
std::vector<std::string> GetStrategies(BotState type);
|
std::vector<std::string> GetStrategies(BotState type);
|
||||||
void ApplyInstanceStrategies(uint32 mapId, bool tellMaster = false);
|
void ApplyInstanceStrategies(uint32 mapId, bool tellMaster = false);
|
||||||
void EvaluateHealerDpsStrategy();
|
|
||||||
bool ContainsStrategy(StrategyType type);
|
bool ContainsStrategy(StrategyType type);
|
||||||
bool HasStrategy(std::string const name, BotState type);
|
bool HasStrategy(std::string const name, BotState type);
|
||||||
BotState GetState() { return currentState; };
|
BotState GetState() { return currentState; };
|
||||||
@@ -423,15 +415,13 @@ public:
|
|||||||
static bool IsCaster(Player* player, bool bySpec = false);
|
static bool IsCaster(Player* player, bool bySpec = false);
|
||||||
static bool IsRangedDps(Player* player, bool bySpec = false);
|
static bool IsRangedDps(Player* player, bool bySpec = false);
|
||||||
static bool IsCombo(Player* player);
|
static bool IsCombo(Player* player);
|
||||||
static bool IsBotMainTank(Player* player);
|
|
||||||
static bool IsMainTank(Player* player);
|
static bool IsMainTank(Player* player);
|
||||||
static uint32 GetGroupTankNum(Player* player);
|
static uint32 GetGroupTankNum(Player* player);
|
||||||
static bool IsAssistTank(Player* player);
|
bool IsAssistTank(Player* player);
|
||||||
static bool IsAssistTankOfIndex(Player* player, int index);
|
bool IsAssistTankOfIndex(Player* player, int index);
|
||||||
static bool IsHealAssistantOfIndex(Player* player, int index);
|
bool IsHealAssistantOfIndex(Player* player, int index);
|
||||||
static bool IsRangedDpsAssistantOfIndex(Player* player, int index);
|
bool IsRangedDpsAssistantOfIndex(Player* player, int index);
|
||||||
bool HasAggro(Unit* unit);
|
bool HasAggro(Unit* unit);
|
||||||
static int32 GetAssistTankIndex(Player* player);
|
|
||||||
int32 GetGroupSlotIndex(Player* player);
|
int32 GetGroupSlotIndex(Player* player);
|
||||||
int32 GetRangedIndex(Player* player);
|
int32 GetRangedIndex(Player* player);
|
||||||
int32 GetClassIndex(Player* player, uint8 cls);
|
int32 GetClassIndex(Player* player, uint8 cls);
|
||||||
@@ -481,7 +471,7 @@ public:
|
|||||||
Item* FindBandage() const;
|
Item* FindBandage() const;
|
||||||
Item* FindOpenableItem() const;
|
Item* FindOpenableItem() const;
|
||||||
Item* FindLockedItem() const;
|
Item* FindLockedItem() const;
|
||||||
Item* FindConsumable(uint32 itemId) const;
|
Item* FindConsumable(uint32 displayId) const;
|
||||||
Item* FindStoneFor(Item* weapon) const;
|
Item* FindStoneFor(Item* weapon) const;
|
||||||
Item* FindOilFor(Item* weapon) const;
|
Item* FindOilFor(Item* weapon) const;
|
||||||
void ImbueItem(Item* item, uint32 targetFlag, ObjectGuid targetGUID);
|
void ImbueItem(Item* item, uint32 targetFlag, ObjectGuid targetGUID);
|
||||||
@@ -555,8 +545,6 @@ public:
|
|||||||
bool IsSafe(WorldObject* obj);
|
bool IsSafe(WorldObject* obj);
|
||||||
ChatChannelSource GetChatChannelSource(Player* bot, uint32 type, std::string channelName);
|
ChatChannelSource GetChatChannelSource(Player* bot, uint32 type, std::string channelName);
|
||||||
|
|
||||||
bool CheckLocationDistanceByLevel(Player* player, const WorldLocation &loc, bool fromStartUp = false);
|
|
||||||
|
|
||||||
bool HasCheat(BotCheatMask mask)
|
bool HasCheat(BotCheatMask mask)
|
||||||
{
|
{
|
||||||
return ((uint32)mask & (uint32)cheatMask) != 0 ||
|
return ((uint32)mask & (uint32)cheatMask) != 0 ||
|
||||||
@@ -602,9 +590,6 @@ public:
|
|||||||
NewRpgStatistic rpgStatistic;
|
NewRpgStatistic rpgStatistic;
|
||||||
std::unordered_set<uint32> lowPriorityQuest;
|
std::unordered_set<uint32> lowPriorityQuest;
|
||||||
|
|
||||||
// Schedules a callback to run once after <delayMs> milliseconds.
|
|
||||||
void AddTimedEvent(std::function<void()> callback, uint32 delayMs);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void _fillGearScoreData(Player* player, Item* item, std::vector<uint32>* gearScore, uint32& twoHandScore,
|
static void _fillGearScoreData(Player* player, Item* item, std::vector<uint32>* gearScore, uint32& twoHandScore,
|
||||||
bool mixed = false);
|
bool mixed = false);
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "PlayerbotAIConfig.h"
|
#include "PlayerbotAIConfig.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "NewRpgInfo.h"
|
|
||||||
#include "PlayerbotDungeonSuggestionMgr.h"
|
#include "PlayerbotDungeonSuggestionMgr.h"
|
||||||
#include "PlayerbotFactory.h"
|
#include "PlayerbotFactory.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
@@ -81,8 +82,6 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
sitDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.SitDelay", 30000);
|
sitDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.SitDelay", 30000);
|
||||||
returnDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ReturnDelay", 7000);
|
returnDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ReturnDelay", 7000);
|
||||||
lootDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.LootDelay", 1000);
|
lootDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.LootDelay", 1000);
|
||||||
disabledWithoutRealPlayerLoginDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.DisabledWithoutRealPlayerLoginDelay", 30);
|
|
||||||
disabledWithoutRealPlayerLogoutDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.DisabledWithoutRealPlayerLogoutDelay", 300);
|
|
||||||
|
|
||||||
farDistance = sConfigMgr->GetOption<float>("AiPlayerbot.FarDistance", 20.0f);
|
farDistance = sConfigMgr->GetOption<float>("AiPlayerbot.FarDistance", 20.0f);
|
||||||
sightDistance = sConfigMgr->GetOption<float>("AiPlayerbot.SightDistance", 75.0f);
|
sightDistance = sConfigMgr->GetOption<float>("AiPlayerbot.SightDistance", 75.0f);
|
||||||
@@ -118,7 +117,6 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
tellWhenAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.TellWhenAvoidAoe", false);
|
tellWhenAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.TellWhenAvoidAoe", false);
|
||||||
|
|
||||||
randomGearLoweringChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomGearLoweringChance", 0.0f);
|
randomGearLoweringChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomGearLoweringChance", 0.0f);
|
||||||
incrementalGearInit = sConfigMgr->GetOption<bool>("AiPlayerbot.IncrementalGearInit", true);
|
|
||||||
randomGearQualityLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomGearQualityLimit", 3);
|
randomGearQualityLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomGearQualityLimit", 3);
|
||||||
randomGearScoreLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomGearScoreLimit", 0);
|
randomGearScoreLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomGearScoreLimit", 0);
|
||||||
|
|
||||||
@@ -131,7 +129,6 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
allowAccountBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowAccountBots", true);
|
allowAccountBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowAccountBots", true);
|
||||||
allowGuildBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowGuildBots", true);
|
allowGuildBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowGuildBots", true);
|
||||||
allowTrustedAccountBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowTrustedAccountBots", true);
|
allowTrustedAccountBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowTrustedAccountBots", true);
|
||||||
disabledWithoutRealPlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.DisabledWithoutRealPlayer", false);
|
|
||||||
randomBotGuildNearby = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGuildNearby", false);
|
randomBotGuildNearby = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGuildNearby", false);
|
||||||
randomBotInvitePlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotInvitePlayer", false);
|
randomBotInvitePlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotInvitePlayer", false);
|
||||||
inviteChat = sConfigMgr->GetOption<bool>("AiPlayerbot.InviteChat", false);
|
inviteChat = sConfigMgr->GetOption<bool>("AiPlayerbot.InviteChat", false);
|
||||||
@@ -139,17 +136,6 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
randomBotMapsAsString = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotMaps", "0,1,530,571");
|
randomBotMapsAsString = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotMaps", "0,1,530,571");
|
||||||
LoadList<std::vector<uint32>>(randomBotMapsAsString, randomBotMaps);
|
LoadList<std::vector<uint32>>(randomBotMapsAsString, randomBotMaps);
|
||||||
probTeleToBankers = sConfigMgr->GetOption<float>("AiPlayerbot.ProbTeleToBankers", 0.25f);
|
probTeleToBankers = sConfigMgr->GetOption<float>("AiPlayerbot.ProbTeleToBankers", 0.25f);
|
||||||
enableWeightTeleToCityBankers = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableWeightTeleToCityBankers", false);
|
|
||||||
weightTeleToStormwind = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToStormwindWeight", 1);
|
|
||||||
weightTeleToIronforge = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToIronforgeWeight", 1);
|
|
||||||
weightTeleToDarnassus = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToDarnassusWeight", 1);
|
|
||||||
weightTeleToExodar = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToExodarWeight", 1);
|
|
||||||
weightTeleToOrgrimmar = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToOrgrimmarWeight", 1);
|
|
||||||
weightTeleToUndercity = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToUndercityWeight", 1);
|
|
||||||
weightTeleToThunderBluff = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToThunderBluffWeight", 1);
|
|
||||||
weightTeleToSilvermoonCity = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToSilvermoonCityWeight", 1);
|
|
||||||
weightTeleToShattrathCity = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToShattrathCityWeight", 1);
|
|
||||||
weightTeleToDalaran = sConfigMgr->GetOption<int>("AiPlayerbot.TeleToDalaranWeight", 1);
|
|
||||||
LoadList<std::vector<uint32>>(
|
LoadList<std::vector<uint32>>(
|
||||||
sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotQuestItems",
|
sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotQuestItems",
|
||||||
"6948,5175,5176,5177,5178,16309,12382,13704,11000"),
|
"6948,5175,5176,5177,5178,16309,12382,13704,11000"),
|
||||||
@@ -159,23 +145,15 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
LoadList<std::vector<uint32>>(
|
LoadList<std::vector<uint32>>(
|
||||||
sConfigMgr->GetOption<std::string>("AiPlayerbot.PvpProhibitedZoneIds",
|
sConfigMgr->GetOption<std::string>("AiPlayerbot.PvpProhibitedZoneIds",
|
||||||
"2255,656,2361,2362,2363,976,35,2268,3425,392,541,1446,3828,3712,3738,3565,"
|
"2255,656,2361,2362,2363,976,35,2268,3425,392,541,1446,3828,3712,3738,3565,"
|
||||||
"3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395,3703,4298,3951"),
|
"3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395"),
|
||||||
pvpProhibitedZoneIds);
|
pvpProhibitedZoneIds);
|
||||||
LoadList<std::vector<uint32>>(
|
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.PvpProhibitedAreaIds", "976,35"),
|
||||||
sConfigMgr->GetOption<std::string>("AiPlayerbot.PvpProhibitedAreaIds",
|
|
||||||
"976,35,392,2268,4161,4010,4317,4312,3649,3887,3958,3724,4080,3938,3754"),
|
|
||||||
pvpProhibitedAreaIds);
|
pvpProhibitedAreaIds);
|
||||||
fastReactInBG = sConfigMgr->GetOption<bool>("AiPlayerbot.FastReactInBG", true);
|
fastReactInBG = sConfigMgr->GetOption<bool>("AiPlayerbot.FastReactInBG", true);
|
||||||
LoadList<std::vector<uint32>>(
|
LoadList<std::vector<uint32>>(
|
||||||
sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotQuestIds", "7848,3802,5505,6502,7761"),
|
sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotQuestIds", "7848,3802,5505,6502,7761"),
|
||||||
randomBotQuestIds);
|
randomBotQuestIds);
|
||||||
|
|
||||||
LoadSet<std::set<uint32>>(
|
|
||||||
sConfigMgr->GetOption<std::string>("AiPlayerbot.DisallowedGameObjects",
|
|
||||||
"176213,17155,2656,74448,19020,3719,3658,3705,3706,105579,75293,2857,"
|
|
||||||
"179490,141596,160836,160845,179516,176224,181085,176112,128308,128403,"
|
|
||||||
"165739,165738,175245,175970,176325,176327,123329"),
|
|
||||||
disallowedGameObjects);
|
|
||||||
botAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.BotAutologin", false);
|
botAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.BotAutologin", false);
|
||||||
randomBotAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotAutologin", true);
|
randomBotAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotAutologin", true);
|
||||||
minRandomBots = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBots", 50);
|
minRandomBots = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBots", 50);
|
||||||
@@ -207,19 +185,6 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotsPriceChangeInterval", 48 * HOUR);
|
sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotsPriceChangeInterval", 48 * HOUR);
|
||||||
randomBotJoinLfg = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotJoinLfg", true);
|
randomBotJoinLfg = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotJoinLfg", true);
|
||||||
|
|
||||||
restrictHealerDPS = sConfigMgr->GetOption<bool>("AiPlayerbot.HealerDPSMapRestriction", false);
|
|
||||||
LoadList<std::vector<uint32>>(
|
|
||||||
sConfigMgr->GetOption<std::string>("AiPlayerbot.RestrictedHealerDPSMaps",
|
|
||||||
"33,34,36,43,47,48,70,90,109,129,209,229,230,329,349,389,429,1001,1004,"
|
|
||||||
"1007,269,540,542,543,545,546,547,552,553,554,555,556,557,558,560,585,574,"
|
|
||||||
"575,576,578,595,599,600,601,602,604,608,619,632,650,658,668,409,469,509,"
|
|
||||||
"531,532,534,544,548,550,564,565,580,249,533,603,615,616,624,631,649,724"),
|
|
||||||
restrictedHealerDPSMaps);
|
|
||||||
|
|
||||||
//////////////////////////// ICC
|
|
||||||
|
|
||||||
EnableICCBuffs = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableICCBuffs", true);
|
|
||||||
|
|
||||||
//////////////////////////// CHAT
|
//////////////////////////// CHAT
|
||||||
enableBroadcasts = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableBroadcasts", true);
|
enableBroadcasts = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableBroadcasts", true);
|
||||||
randomBotTalk = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotTalk", false);
|
randomBotTalk = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotTalk", false);
|
||||||
@@ -342,51 +307,14 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
summonAtInnkeepersEnabled = sConfigMgr->GetOption<bool>("AiPlayerbot.SummonAtInnkeepersEnabled", true);
|
summonAtInnkeepersEnabled = sConfigMgr->GetOption<bool>("AiPlayerbot.SummonAtInnkeepersEnabled", true);
|
||||||
randomBotMinLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotMinLevel", 1);
|
randomBotMinLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotMinLevel", 1);
|
||||||
randomBotMaxLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotMaxLevel", 80);
|
randomBotMaxLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotMaxLevel", 80);
|
||||||
if (randomBotMaxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
|
|
||||||
randomBotMaxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
|
|
||||||
randomBotLoginAtStartup = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotLoginAtStartup", true);
|
randomBotLoginAtStartup = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotLoginAtStartup", true);
|
||||||
randomBotTeleLowerLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleLowerLevel", 1);
|
randomBotTeleLowerLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleLowerLevel", 3);
|
||||||
randomBotTeleHigherLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleHigherLevel", 3);
|
randomBotTeleHigherLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleHigherLevel", 1);
|
||||||
openGoSpell = sConfigMgr->GetOption<int32>("AiPlayerbot.OpenGoSpell", 6477);
|
openGoSpell = sConfigMgr->GetOption<int32>("AiPlayerbot.OpenGoSpell", 6477);
|
||||||
|
|
||||||
// Zones for NewRpgStrategy teleportation brackets
|
|
||||||
std::vector<uint32> zoneIds = {
|
|
||||||
// Classic WoW - Low-level zones
|
|
||||||
1, 12, 14, 85, 141, 215, 3430, 3524,
|
|
||||||
// Classic WoW - Mid-level zones
|
|
||||||
17, 38, 40, 130, 148, 3433, 3525,
|
|
||||||
// Classic WoW - High-level zones
|
|
||||||
10, 11, 44, 267, 331, 400, 406,
|
|
||||||
// Classic WoW - Higher-level zones
|
|
||||||
3, 8, 15, 16, 33, 45, 47, 51, 357, 405, 440,
|
|
||||||
// Classic WoW - Top-level zones
|
|
||||||
4, 28, 46, 139, 361, 490, 618, 1377,
|
|
||||||
// The Burning Crusade - Zones
|
|
||||||
3483, 3518, 3519, 3520, 3521, 3522, 3523, 4080,
|
|
||||||
// Wrath of the Lich King - Zones
|
|
||||||
65, 66, 67, 210, 394, 495, 2817, 3537, 3711, 4197
|
|
||||||
};
|
|
||||||
|
|
||||||
for (uint32 zoneId : zoneIds)
|
|
||||||
{
|
|
||||||
std::string setting = "AiPlayerbot.ZoneBracket." + std::to_string(zoneId);
|
|
||||||
std::string value = sConfigMgr->GetOption<std::string>(setting, "");
|
|
||||||
|
|
||||||
if (!value.empty())
|
|
||||||
{
|
|
||||||
size_t commaPos = value.find(',');
|
|
||||||
if (commaPos != std::string::npos)
|
|
||||||
{
|
|
||||||
uint32 minLevel = atoi(value.substr(0, commaPos).c_str());
|
|
||||||
uint32 maxLevel = atoi(value.substr(commaPos + 1).c_str());
|
|
||||||
zoneBrackets[zoneId] = std::make_pair(minLevel, maxLevel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
randomChangeMultiplier = sConfigMgr->GetOption<float>("AiPlayerbot.RandomChangeMultiplier", 1.0);
|
randomChangeMultiplier = sConfigMgr->GetOption<float>("AiPlayerbot.RandomChangeMultiplier", 1.0);
|
||||||
|
|
||||||
randomBotCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotCombatStrategies", "");
|
randomBotCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotCombatStrategies", "-threat");
|
||||||
randomBotNonCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotNonCombatStrategies", "");
|
randomBotNonCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotNonCombatStrategies", "");
|
||||||
combatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.CombatStrategies", "+custom::say");
|
combatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.CombatStrategies", "+custom::say");
|
||||||
nonCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.NonCombatStrategies", "+custom::say,+return");
|
nonCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.NonCombatStrategies", "+custom::say,+return");
|
||||||
@@ -403,12 +331,6 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
useFlyMountAtMinLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.UseFlyMountAtMinLevel", 60);
|
useFlyMountAtMinLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.UseFlyMountAtMinLevel", 60);
|
||||||
useFastFlyMountAtMinLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.UseFastFlyMountAtMinLevel", 70);
|
useFastFlyMountAtMinLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.UseFastFlyMountAtMinLevel", 70);
|
||||||
|
|
||||||
// stagger bot flightpath takeoff
|
|
||||||
delayMin = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiDelayMinMs", 350u);
|
|
||||||
delayMax = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiDelayMaxMs", 5000u);
|
|
||||||
gapMs = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiGapMs", 200u);
|
|
||||||
gapJitterMs = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiGapJitterMs", 100u);
|
|
||||||
|
|
||||||
LOG_INFO("server.loading", "Loading TalentSpecs...");
|
LOG_INFO("server.loading", "Loading TalentSpecs...");
|
||||||
|
|
||||||
for (uint32 cls = 1; cls < MAX_CLASSES; ++cls)
|
for (uint32 cls = 1; cls < MAX_CLASSES; ++cls)
|
||||||
@@ -473,13 +395,11 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
}
|
}
|
||||||
|
|
||||||
botCheats.clear();
|
botCheats.clear();
|
||||||
LoadListString<std::vector<std::string>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.BotCheats", "food,taxi,raid"),
|
LoadListString<std::vector<std::string>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.BotCheats", "taxi"),
|
||||||
botCheats);
|
botCheats);
|
||||||
|
|
||||||
botCheatMask = 0;
|
botCheatMask = 0;
|
||||||
|
|
||||||
if (std::find(botCheats.begin(), botCheats.end(), "food") != botCheats.end())
|
|
||||||
botCheatMask |= (uint32)BotCheatMask::food;
|
|
||||||
if (std::find(botCheats.begin(), botCheats.end(), "taxi") != botCheats.end())
|
if (std::find(botCheats.begin(), botCheats.end(), "taxi") != botCheats.end())
|
||||||
botCheatMask |= (uint32)BotCheatMask::taxi;
|
botCheatMask |= (uint32)BotCheatMask::taxi;
|
||||||
if (std::find(botCheats.begin(), botCheats.end(), "gold") != botCheats.end())
|
if (std::find(botCheats.begin(), botCheats.end(), "gold") != botCheats.end())
|
||||||
@@ -490,17 +410,30 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
botCheatMask |= (uint32)BotCheatMask::mana;
|
botCheatMask |= (uint32)BotCheatMask::mana;
|
||||||
if (std::find(botCheats.begin(), botCheats.end(), "power") != botCheats.end())
|
if (std::find(botCheats.begin(), botCheats.end(), "power") != botCheats.end())
|
||||||
botCheatMask |= (uint32)BotCheatMask::power;
|
botCheatMask |= (uint32)BotCheatMask::power;
|
||||||
if (std::find(botCheats.begin(), botCheats.end(), "raid") != botCheats.end())
|
|
||||||
botCheatMask |= (uint32)BotCheatMask::raid;
|
|
||||||
|
|
||||||
LoadListString<std::vector<std::string>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.AllowedLogFiles", ""),
|
LoadListString<std::vector<std::string>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.AllowedLogFiles", ""),
|
||||||
allowedLogFiles);
|
allowedLogFiles);
|
||||||
LoadListString<std::vector<std::string>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.TradeActionExcludedPrefixes", ""),
|
|
||||||
tradeActionExcludedPrefixes);
|
|
||||||
|
|
||||||
worldBuffs.clear();
|
worldBuffs.clear();
|
||||||
loadWorldBuff();
|
|
||||||
LOG_INFO("playerbots", "Loading World Buff Feature...");
|
LOG_INFO("playerbots", "Loading Worldbuff...");
|
||||||
|
for (uint32 factionId = 0; factionId < 3; factionId++)
|
||||||
|
{
|
||||||
|
for (uint32 classId = 0; classId < MAX_CLASSES; classId++)
|
||||||
|
{
|
||||||
|
for (uint32 specId = 0; specId <= MAX_WORLDBUFF_SPECNO; specId++)
|
||||||
|
{
|
||||||
|
for (uint32 minLevel = 0; minLevel <= randomBotMaxLevel; minLevel++)
|
||||||
|
{
|
||||||
|
for (uint32 maxLevel = minLevel; maxLevel <= randomBotMaxLevel; maxLevel++)
|
||||||
|
{
|
||||||
|
loadWorldBuff(factionId, classId, specId, minLevel, maxLevel);
|
||||||
|
}
|
||||||
|
loadWorldBuff(factionId, classId, specId, minLevel, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
randomBotAccountPrefix = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAccountPrefix", "rndbot");
|
randomBotAccountPrefix = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAccountPrefix", "rndbot");
|
||||||
randomBotAccountCount = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAccountCount", 0);
|
randomBotAccountCount = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAccountCount", 0);
|
||||||
@@ -533,7 +466,6 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
equipmentPersistence = sConfigMgr->GetOption<bool>("AiPlayerbot.EquipmentPersistence", false);
|
equipmentPersistence = sConfigMgr->GetOption<bool>("AiPlayerbot.EquipmentPersistence", false);
|
||||||
equipmentPersistenceLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.EquipmentPersistenceLevel", 80);
|
equipmentPersistenceLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.EquipmentPersistenceLevel", 80);
|
||||||
groupInvitationPermission = sConfigMgr->GetOption<int32>("AiPlayerbot.GroupInvitationPermission", 1);
|
groupInvitationPermission = sConfigMgr->GetOption<int32>("AiPlayerbot.GroupInvitationPermission", 1);
|
||||||
keepAltsInGroup = sConfigMgr->GetOption<bool>("AiPlayerbot.KeepAltsInGroup", false);
|
|
||||||
allowSummonInCombat = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonInCombat", true);
|
allowSummonInCombat = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonInCombat", true);
|
||||||
allowSummonWhenMasterIsDead = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonWhenMasterIsDead", true);
|
allowSummonWhenMasterIsDead = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonWhenMasterIsDead", true);
|
||||||
allowSummonWhenBotIsDead = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonWhenBotIsDead", true);
|
allowSummonWhenBotIsDead = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonWhenBotIsDead", true);
|
||||||
@@ -551,7 +483,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
autoGearQualityLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.AutoGearQualityLimit", 3);
|
autoGearQualityLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.AutoGearQualityLimit", 3);
|
||||||
autoGearScoreLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.AutoGearScoreLimit", 0);
|
autoGearScoreLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.AutoGearScoreLimit", 0);
|
||||||
|
|
||||||
randomBotXPRate = sConfigMgr->GetOption<float>("AiPlayerbot.RandomBotXPRate", 1.0);
|
playerbotsXPrate = sConfigMgr->GetOption<float>("AiPlayerbot.PlayerbotsXPRate", 1.0);
|
||||||
randomBotAllianceRatio = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAllianceRatio", 50);
|
randomBotAllianceRatio = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAllianceRatio", 50);
|
||||||
randomBotHordeRatio = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotHordeRatio", 50);
|
randomBotHordeRatio = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotHordeRatio", 50);
|
||||||
disableDeathKnightLogin = sConfigMgr->GetOption<bool>("AiPlayerbot.DisableDeathKnightLogin", 0);
|
disableDeathKnightLogin = sConfigMgr->GetOption<bool>("AiPlayerbot.DisableDeathKnightLogin", 0);
|
||||||
@@ -594,23 +526,13 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
autoPickTalents = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoPickTalents", true);
|
autoPickTalents = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoPickTalents", true);
|
||||||
autoUpgradeEquip = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoUpgradeEquip", false);
|
autoUpgradeEquip = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoUpgradeEquip", false);
|
||||||
hunterWolfPet = sConfigMgr->GetOption<int32>("AiPlayerbot.HunterWolfPet", 0);
|
hunterWolfPet = sConfigMgr->GetOption<int32>("AiPlayerbot.HunterWolfPet", 0);
|
||||||
defaultPetStance = sConfigMgr->GetOption<int32>("AiPlayerbot.DefaultPetStance", 1);
|
|
||||||
petChatCommandDebug = sConfigMgr->GetOption<bool>("AiPlayerbot.PetChatCommandDebug", 0);
|
|
||||||
autoLearnTrainerSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoLearnTrainerSpells", true);
|
autoLearnTrainerSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoLearnTrainerSpells", true);
|
||||||
autoLearnQuestSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoLearnQuestSpells", false);
|
autoLearnQuestSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoLearnQuestSpells", false);
|
||||||
autoTeleportForLevel = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoTeleportForLevel", false);
|
autoTeleportForLevel = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoTeleportForLevel", false);
|
||||||
autoDoQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoDoQuests", true);
|
autoDoQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoDoQuests", true);
|
||||||
enableNewRpgStrategy = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableNewRpgStrategy", true);
|
enableNewRpgStrategy = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableNewRpgStrategy", false);
|
||||||
|
|
||||||
RpgStatusProbWeight[RPG_WANDER_RANDOM] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.WanderRandom", 15);
|
|
||||||
RpgStatusProbWeight[RPG_WANDER_NPC] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.WanderNpc", 20);
|
|
||||||
RpgStatusProbWeight[RPG_GO_GRIND] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.GoGrind", 15);
|
|
||||||
RpgStatusProbWeight[RPG_GO_CAMP] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.GoCamp", 10);
|
|
||||||
RpgStatusProbWeight[RPG_DO_QUEST] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.DoQuest", 60);
|
|
||||||
RpgStatusProbWeight[RPG_TRAVEL_FLIGHT] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.TravelFlight", 15);
|
|
||||||
RpgStatusProbWeight[RPG_REST] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.Rest", 5);
|
|
||||||
|
|
||||||
syncLevelWithPlayers = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncLevelWithPlayers", false);
|
syncLevelWithPlayers = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncLevelWithPlayers", false);
|
||||||
|
freeFood = sConfigMgr->GetOption<bool>("AiPlayerbot.FreeFood", true);
|
||||||
randomBotGroupNearby = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGroupNearby", true);
|
randomBotGroupNearby = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGroupNearby", true);
|
||||||
|
|
||||||
// arena
|
// arena
|
||||||
@@ -629,9 +551,6 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign account types after accounts are created
|
|
||||||
sRandomPlayerbotMgr->AssignAccountTypes();
|
|
||||||
|
|
||||||
if (sPlayerbotAIConfig->enabled)
|
if (sPlayerbotAIConfig->enabled)
|
||||||
{
|
{
|
||||||
sRandomPlayerbotMgr->Init();
|
sRandomPlayerbotMgr->Init();
|
||||||
@@ -643,16 +562,18 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
sPlayerbotTextMgr->LoadBotTextChance();
|
sPlayerbotTextMgr->LoadBotTextChance();
|
||||||
PlayerbotFactory::Init();
|
PlayerbotFactory::Init();
|
||||||
|
|
||||||
AiObjectContext::BuildAllSharedContexts();
|
if (!sPlayerbotAIConfig->autoDoQuests)
|
||||||
|
{
|
||||||
|
LOG_INFO("server.loading", "Loading Quest Detail Data...");
|
||||||
|
sTravelMgr->LoadQuestTravelTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (sPlayerbotAIConfig->randomBotSuggestDungeons)
|
if (sPlayerbotAIConfig->randomBotSuggestDungeons)
|
||||||
{
|
{
|
||||||
sPlayerbotDungeonSuggestionMgr->LoadDungeonSuggestions();
|
sPlayerbotDungeonSuggestionMgr->LoadDungeonSuggestions();
|
||||||
}
|
}
|
||||||
|
|
||||||
excludedHunterPetFamilies.clear();
|
|
||||||
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.ExcludedHunterPetFamilies", ""), excludedHunterPetFamilies);
|
|
||||||
|
|
||||||
LOG_INFO("server.loading", "---------------------------------------");
|
LOG_INFO("server.loading", "---------------------------------------");
|
||||||
LOG_INFO("server.loading", " AI Playerbots initialized ");
|
LOG_INFO("server.loading", " AI Playerbots initialized ");
|
||||||
LOG_INFO("server.loading", "---------------------------------------");
|
LOG_INFO("server.loading", "---------------------------------------");
|
||||||
@@ -685,12 +606,6 @@ bool PlayerbotAIConfig::IsInPvpProhibitedArea(uint32 id)
|
|||||||
return find(pvpProhibitedAreaIds.begin(), pvpProhibitedAreaIds.end(), id) != pvpProhibitedAreaIds.end();
|
return find(pvpProhibitedAreaIds.begin(), pvpProhibitedAreaIds.end(), id) != pvpProhibitedAreaIds.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayerbotAIConfig::IsRestrictedHealerDPSMap(uint32 mapId) const
|
|
||||||
{
|
|
||||||
return restrictHealerDPS &&
|
|
||||||
std::find(restrictedHealerDPSMaps.begin(), restrictedHealerDPSMaps.end(), mapId) != restrictedHealerDPSMaps.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string const PlayerbotAIConfig::GetTimestampStr()
|
std::string const PlayerbotAIConfig::GetTimestampStr()
|
||||||
{
|
{
|
||||||
time_t t = time(nullptr);
|
time_t t = time(nullptr);
|
||||||
@@ -763,62 +678,88 @@ void PlayerbotAIConfig::log(std::string const fileName, char const* str, ...)
|
|||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerbotAIConfig::loadWorldBuff()
|
void PlayerbotAIConfig::loadWorldBuff(uint32 factionId1, uint32 classId1, uint32 specId1, uint32 minLevel1, uint32 maxLevel1)
|
||||||
{
|
{
|
||||||
std::string matrix = sConfigMgr->GetOption<std::string>("AiPlayerbot.WorldBuffMatrix", "", true);
|
std::vector<uint32> buffs;
|
||||||
if (matrix.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::istringstream entryStream(matrix);
|
std::ostringstream os;
|
||||||
std::string entry;
|
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << classId1 << "." << specId1 << "." << minLevel1 << "." << maxLevel1;
|
||||||
|
|
||||||
while (std::getline(entryStream, entry, ';'))
|
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs);
|
||||||
|
|
||||||
|
for (auto buff : buffs)
|
||||||
{
|
{
|
||||||
|
worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
|
||||||
entry.erase(0, entry.find_first_not_of(" \t\r\n"));
|
|
||||||
entry.erase(entry.find_last_not_of(" \t\r\n") + 1);
|
|
||||||
|
|
||||||
size_t firstColon = entry.find(':');
|
|
||||||
size_t secondColon = entry.find(':', firstColon + 1);
|
|
||||||
|
|
||||||
if (firstColon == std::string::npos || secondColon == std::string::npos)
|
|
||||||
{
|
|
||||||
LOG_ERROR("playerbots", "Malformed entry: [{}]", entry);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string metaPart = entry.substr(firstColon + 1, secondColon - firstColon - 1);
|
|
||||||
std::string spellPart = entry.substr(secondColon + 1);
|
|
||||||
|
|
||||||
std::vector<uint32> ids;
|
|
||||||
std::istringstream metaStream(metaPart);
|
|
||||||
std::string token;
|
|
||||||
while (std::getline(metaStream, token, ','))
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
ids.push_back(static_cast<uint32>(std::stoi(token)));
|
|
||||||
} catch (...) {
|
|
||||||
LOG_ERROR("playerbots", "Invalid meta token in [{}]", entry);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ids.size() != 5)
|
|
||||||
{
|
|
||||||
LOG_ERROR("playerbots", "Entry [{}] has incomplete meta block", entry);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::istringstream spellStream(spellPart);
|
|
||||||
while (std::getline(spellStream, token, ','))
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
uint32 spellId = static_cast<uint32>(std::stoi(token));
|
|
||||||
worldBuff wb = { spellId, ids[0], ids[1], ids[2], ids[3], ids[4] };
|
|
||||||
worldBuffs.push_back(wb);
|
worldBuffs.push_back(wb);
|
||||||
} catch (...) {
|
|
||||||
LOG_ERROR("playerbots", "Invalid spell ID in [{}]", entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (maxLevel1 == 0)
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << classId1 << "." << specId1 << "." << minLevel1;
|
||||||
|
|
||||||
|
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs);
|
||||||
|
|
||||||
|
for (auto buff : buffs)
|
||||||
|
{
|
||||||
|
worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
|
||||||
|
worldBuffs.push_back(wb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxLevel1 == 0 && minLevel1 == 0)
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << factionId1 << "." << classId1 << "." << specId1;
|
||||||
|
|
||||||
|
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs);
|
||||||
|
|
||||||
|
for (auto buff : buffs)
|
||||||
|
{
|
||||||
|
worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
|
||||||
|
worldBuffs.push_back(wb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxLevel1 == 0 && minLevel1 == 0 && specId1 == 0)
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << factionId1 << "." << classId1;
|
||||||
|
|
||||||
|
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs);
|
||||||
|
|
||||||
|
for (auto buff : buffs)
|
||||||
|
{
|
||||||
|
worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
|
||||||
|
worldBuffs.push_back(wb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (classId1 == 0 && maxLevel1 == 0 && minLevel1 == 0 && specId1 == 0)
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os << "AiPlayerbot.WorldBuff." << factionId1;
|
||||||
|
|
||||||
|
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs);
|
||||||
|
|
||||||
|
for (auto buff : buffs)
|
||||||
|
{
|
||||||
|
worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
|
||||||
|
worldBuffs.push_back(wb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (factionId1 == 0 && classId1 == 0 && maxLevel1 == 0 && minLevel1 == 0 && specId1 == 0)
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os << "AiPlayerbot.WorldBuff";
|
||||||
|
|
||||||
|
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs);
|
||||||
|
|
||||||
|
for (auto buff : buffs)
|
||||||
|
{
|
||||||
|
worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
|
||||||
|
worldBuffs.push_back(wb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#define _PLAYERBOT_PLAYERbotAICONFIG_H
|
#define _PLAYERBOT_PLAYERbotAICONFIG_H
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "DBCEnums.h"
|
#include "DBCEnums.h"
|
||||||
@@ -22,9 +21,7 @@ enum class BotCheatMask : uint32
|
|||||||
health = 4,
|
health = 4,
|
||||||
mana = 8,
|
mana = 8,
|
||||||
power = 16,
|
power = 16,
|
||||||
raid = 32,
|
maxMask = 32
|
||||||
food = 64,
|
|
||||||
maxMask = 128
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class HealingManaEfficiency : uint8
|
enum class HealingManaEfficiency : uint8
|
||||||
@@ -37,27 +34,8 @@ enum class HealingManaEfficiency : uint8
|
|||||||
SUPERIOR = 32
|
SUPERIOR = 32
|
||||||
};
|
};
|
||||||
|
|
||||||
enum NewRpgStatus : int
|
|
||||||
{
|
|
||||||
RPG_STATUS_START = 0,
|
|
||||||
// Going to far away place
|
|
||||||
RPG_GO_GRIND = 0,
|
|
||||||
RPG_GO_CAMP = 1,
|
|
||||||
// Exploring nearby
|
|
||||||
RPG_WANDER_RANDOM = 2,
|
|
||||||
RPG_WANDER_NPC = 3,
|
|
||||||
// Do Quest (based on quest status)
|
|
||||||
RPG_DO_QUEST = 4,
|
|
||||||
// Travel
|
|
||||||
RPG_TRAVEL_FLIGHT = 5,
|
|
||||||
// Taking a break
|
|
||||||
RPG_REST = 6,
|
|
||||||
// Initial status
|
|
||||||
RPG_IDLE = 7,
|
|
||||||
RPG_STATUS_END = 8
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MAX_SPECNO 20
|
#define MAX_SPECNO 20
|
||||||
|
#define MAX_WORLDBUFF_SPECNO 3
|
||||||
|
|
||||||
class PlayerbotAIConfig
|
class PlayerbotAIConfig
|
||||||
{
|
{
|
||||||
@@ -77,8 +55,6 @@ public:
|
|||||||
bool IsInPvpProhibitedArea(uint32 id);
|
bool IsInPvpProhibitedArea(uint32 id);
|
||||||
|
|
||||||
bool enabled;
|
bool enabled;
|
||||||
bool disabledWithoutRealPlayer;
|
|
||||||
bool EnableICCBuffs;
|
|
||||||
bool allowAccountBots, allowGuildBots, allowTrustedAccountBots;
|
bool allowAccountBots, allowGuildBots, allowTrustedAccountBots;
|
||||||
bool randomBotGuildNearby, randomBotInvitePlayer, inviteChat;
|
bool randomBotGuildNearby, randomBotInvitePlayer, inviteChat;
|
||||||
uint32 globalCoolDown, reactDelay, maxWaitForMove, disableMoveSplinePath, maxMovementSearchTime, expireActionTime,
|
uint32 globalCoolDown, reactDelay, maxWaitForMove, disableMoveSplinePath, maxMovementSearchTime, expireActionTime,
|
||||||
@@ -95,24 +71,12 @@ public:
|
|||||||
float maxAoeAvoidRadius;
|
float maxAoeAvoidRadius;
|
||||||
std::set<uint32> aoeAvoidSpellWhitelist;
|
std::set<uint32> aoeAvoidSpellWhitelist;
|
||||||
bool tellWhenAvoidAoe;
|
bool tellWhenAvoidAoe;
|
||||||
std::set<uint32> disallowedGameObjects;
|
|
||||||
|
|
||||||
uint32 openGoSpell;
|
uint32 openGoSpell;
|
||||||
bool randomBotAutologin;
|
bool randomBotAutologin;
|
||||||
bool botAutologin;
|
bool botAutologin;
|
||||||
std::string randomBotMapsAsString;
|
std::string randomBotMapsAsString;
|
||||||
float probTeleToBankers;
|
float probTeleToBankers;
|
||||||
bool enableWeightTeleToCityBankers;
|
|
||||||
int weightTeleToStormwind;
|
|
||||||
int weightTeleToIronforge;
|
|
||||||
int weightTeleToDarnassus;
|
|
||||||
int weightTeleToExodar;
|
|
||||||
int weightTeleToOrgrimmar;
|
|
||||||
int weightTeleToUndercity;
|
|
||||||
int weightTeleToThunderBluff;
|
|
||||||
int weightTeleToSilvermoonCity;
|
|
||||||
int weightTeleToShattrathCity;
|
|
||||||
int weightTeleToDalaran;
|
|
||||||
std::vector<uint32> randomBotMaps;
|
std::vector<uint32> randomBotMaps;
|
||||||
std::vector<uint32> randomBotQuestItems;
|
std::vector<uint32> randomBotQuestItems;
|
||||||
std::vector<uint32> randomBotAccounts;
|
std::vector<uint32> randomBotAccounts;
|
||||||
@@ -120,7 +84,6 @@ public:
|
|||||||
std::vector<uint32> randomBotQuestIds;
|
std::vector<uint32> randomBotQuestIds;
|
||||||
uint32 randomBotTeleportDistance;
|
uint32 randomBotTeleportDistance;
|
||||||
float randomGearLoweringChance;
|
float randomGearLoweringChance;
|
||||||
bool incrementalGearInit;
|
|
||||||
int32 randomGearQualityLimit;
|
int32 randomGearQualityLimit;
|
||||||
int32 randomGearScoreLimit;
|
int32 randomGearScoreLimit;
|
||||||
float randomBotMinLevelChance, randomBotMaxLevelChance;
|
float randomBotMinLevelChance, randomBotMaxLevelChance;
|
||||||
@@ -136,7 +99,6 @@ public:
|
|||||||
uint32 minRandomBotPvpTime, maxRandomBotPvpTime;
|
uint32 minRandomBotPvpTime, maxRandomBotPvpTime;
|
||||||
uint32 randomBotsPerInterval;
|
uint32 randomBotsPerInterval;
|
||||||
uint32 minRandomBotsPriceChangeInterval, maxRandomBotsPriceChangeInterval;
|
uint32 minRandomBotsPriceChangeInterval, maxRandomBotsPriceChangeInterval;
|
||||||
uint32 disabledWithoutRealPlayerLoginDelay, disabledWithoutRealPlayerLogoutDelay;
|
|
||||||
bool randomBotJoinLfg;
|
bool randomBotJoinLfg;
|
||||||
|
|
||||||
// chat
|
// chat
|
||||||
@@ -233,7 +195,6 @@ public:
|
|||||||
|
|
||||||
bool randomBotLoginAtStartup;
|
bool randomBotLoginAtStartup;
|
||||||
uint32 randomBotTeleLowerLevel, randomBotTeleHigherLevel;
|
uint32 randomBotTeleLowerLevel, randomBotTeleHigherLevel;
|
||||||
std::map<uint32, std::pair<uint32, uint32>> zoneBrackets;
|
|
||||||
bool logInGroupOnly, logValuesPerTick;
|
bool logInGroupOnly, logValuesPerTick;
|
||||||
bool fleeingEnabled;
|
bool fleeingEnabled;
|
||||||
bool summonAtInnkeepersEnabled;
|
bool summonAtInnkeepersEnabled;
|
||||||
@@ -289,7 +250,6 @@ public:
|
|||||||
uint32 iterationsPerTick;
|
uint32 iterationsPerTick;
|
||||||
|
|
||||||
std::mutex m_logMtx;
|
std::mutex m_logMtx;
|
||||||
std::vector<std::string> tradeActionExcludedPrefixes;
|
|
||||||
std::vector<std::string> allowedLogFiles;
|
std::vector<std::string> allowedLogFiles;
|
||||||
std::unordered_map<std::string, std::pair<FILE*, bool>> logFiles;
|
std::unordered_map<std::string, std::pair<FILE*, bool>> logFiles;
|
||||||
|
|
||||||
@@ -299,11 +259,11 @@ public:
|
|||||||
struct worldBuff
|
struct worldBuff
|
||||||
{
|
{
|
||||||
uint32 spellId;
|
uint32 spellId;
|
||||||
uint32 factionId;
|
uint32 factionId = 0;
|
||||||
uint32 classId;
|
uint32 classId = 0;
|
||||||
uint32 specId;
|
uint32 specId = 0;
|
||||||
uint32 minLevel;
|
uint32 minLevel = 0;
|
||||||
uint32 maxLevel;
|
uint32 maxLevel = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<worldBuff> worldBuffs;
|
std::vector<worldBuff> worldBuffs;
|
||||||
@@ -315,7 +275,7 @@ public:
|
|||||||
bool randomBotShowCloak;
|
bool randomBotShowCloak;
|
||||||
bool randomBotFixedLevel;
|
bool randomBotFixedLevel;
|
||||||
bool disableRandomLevels;
|
bool disableRandomLevels;
|
||||||
float randomBotXPRate;
|
float playerbotsXPrate;
|
||||||
uint32 randomBotAllianceRatio;
|
uint32 randomBotAllianceRatio;
|
||||||
uint32 randomBotHordeRatio;
|
uint32 randomBotHordeRatio;
|
||||||
bool disableDeathKnightLogin;
|
bool disableDeathKnightLogin;
|
||||||
@@ -345,13 +305,11 @@ public:
|
|||||||
bool autoPickTalents;
|
bool autoPickTalents;
|
||||||
bool autoUpgradeEquip;
|
bool autoUpgradeEquip;
|
||||||
int32 hunterWolfPet;
|
int32 hunterWolfPet;
|
||||||
int32 defaultPetStance;
|
|
||||||
int32 petChatCommandDebug;
|
|
||||||
bool autoLearnTrainerSpells;
|
bool autoLearnTrainerSpells;
|
||||||
bool autoDoQuests;
|
bool autoDoQuests;
|
||||||
bool enableNewRpgStrategy;
|
bool enableNewRpgStrategy;
|
||||||
std::unordered_map<NewRpgStatus, uint32> RpgStatusProbWeight;
|
|
||||||
bool syncLevelWithPlayers;
|
bool syncLevelWithPlayers;
|
||||||
|
bool freeFood;
|
||||||
bool autoLearnQuestSpells;
|
bool autoLearnQuestSpells;
|
||||||
bool autoTeleportForLevel;
|
bool autoTeleportForLevel;
|
||||||
bool randomBotGroupNearby;
|
bool randomBotGroupNearby;
|
||||||
@@ -372,8 +330,6 @@ public:
|
|||||||
bool equipmentPersistence;
|
bool equipmentPersistence;
|
||||||
int32 equipmentPersistenceLevel;
|
int32 equipmentPersistenceLevel;
|
||||||
int32 groupInvitationPermission;
|
int32 groupInvitationPermission;
|
||||||
bool keepAltsInGroup = false;
|
|
||||||
bool KeepAltsInGroup() const { return keepAltsInGroup; }
|
|
||||||
bool allowSummonInCombat;
|
bool allowSummonInCombat;
|
||||||
bool allowSummonWhenMasterIsDead;
|
bool allowSummonWhenMasterIsDead;
|
||||||
bool allowSummonWhenBotIsDead;
|
bool allowSummonWhenBotIsDead;
|
||||||
@@ -392,12 +348,6 @@ public:
|
|||||||
uint32 useFlyMountAtMinLevel;
|
uint32 useFlyMountAtMinLevel;
|
||||||
uint32 useFastFlyMountAtMinLevel;
|
uint32 useFastFlyMountAtMinLevel;
|
||||||
|
|
||||||
// stagger flightpath takeoff
|
|
||||||
uint32 delayMin;
|
|
||||||
uint32 delayMax;
|
|
||||||
uint32 gapMs;
|
|
||||||
uint32 gapJitterMs;
|
|
||||||
|
|
||||||
std::string const GetTimestampStr();
|
std::string const GetTimestampStr();
|
||||||
bool hasLog(std::string const fileName)
|
bool hasLog(std::string const fileName)
|
||||||
{
|
{
|
||||||
@@ -411,16 +361,9 @@ public:
|
|||||||
}
|
}
|
||||||
void log(std::string const fileName, const char* str, ...);
|
void log(std::string const fileName, const char* str, ...);
|
||||||
|
|
||||||
void loadWorldBuff();
|
void loadWorldBuff(uint32 factionId, uint32 classId, uint32 specId, uint32 minLevel, uint32 maxLevel);
|
||||||
|
|
||||||
static std::vector<std::vector<uint32>> ParseTempTalentsOrder(uint32 cls, std::string temp_talents_order);
|
static std::vector<std::vector<uint32>> ParseTempTalentsOrder(uint32 cls, std::string temp_talents_order);
|
||||||
static std::vector<std::vector<uint32>> ParseTempPetTalentsOrder(uint32 spec, std::string temp_talents_order);
|
static std::vector<std::vector<uint32>> ParseTempPetTalentsOrder(uint32 spec, std::string temp_talents_order);
|
||||||
|
|
||||||
bool restrictHealerDPS = false;
|
|
||||||
std::vector<uint32> restrictedHealerDPSMaps;
|
|
||||||
bool IsRestrictedHealerDPSMap(uint32 mapId) const;
|
|
||||||
|
|
||||||
std::vector<uint32> excludedHunterPetFamilies;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define sPlayerbotAIConfig PlayerbotAIConfig::instance()
|
#define sPlayerbotAIConfig PlayerbotAIConfig::instance()
|
||||||
|
|||||||
@@ -36,8 +36,6 @@
|
|||||||
#include "BroadcastHelper.h"
|
#include "BroadcastHelper.h"
|
||||||
#include "PlayerbotDbStore.h"
|
#include "PlayerbotDbStore.h"
|
||||||
#include "WorldSessionMgr.h"
|
#include "WorldSessionMgr.h"
|
||||||
#include "DatabaseEnv.h" // Added for gender choice
|
|
||||||
#include <algorithm> // Added for gender choice
|
|
||||||
|
|
||||||
class BotInitGuard
|
class BotInitGuard
|
||||||
{
|
{
|
||||||
@@ -159,7 +157,7 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId
|
|||||||
bool PlayerbotHolder::IsAccountLinked(uint32 accountId, uint32 linkedAccountId)
|
bool PlayerbotHolder::IsAccountLinked(uint32 accountId, uint32 linkedAccountId)
|
||||||
{
|
{
|
||||||
QueryResult result = PlayerbotsDatabase.Query(
|
QueryResult result = PlayerbotsDatabase.Query(
|
||||||
"SELECT 1 FROM playerbots_account_links WHERE account_id = {} AND linked_account_id = {}", accountId, linkedAccountId);
|
"SELECT 1 FROM playerbot_account_links WHERE account_id = {} AND linked_account_id = {}", accountId, linkedAccountId);
|
||||||
return result != nullptr;
|
return result != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +166,7 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
|
|||||||
uint32 botAccountId = holder.GetAccountId();
|
uint32 botAccountId = holder.GetAccountId();
|
||||||
// At login DBC locale should be what the server is set to use by default (as spells etc are hardcoded to ENUS this
|
// At login DBC locale should be what the server is set to use by default (as spells etc are hardcoded to ENUS this
|
||||||
// allows channels to work as intended)
|
// allows channels to work as intended)
|
||||||
WorldSession* botSession = new WorldSession(botAccountId, "", 0x0, nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING,
|
WorldSession* botSession = new WorldSession(botAccountId, "", nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING,
|
||||||
time_t(0), sWorld->GetDefaultDbcLocale(), 0, false, false, 0, true);
|
time_t(0), sWorld->GetDefaultDbcLocale(), 0, false, false, 0, true);
|
||||||
|
|
||||||
botSession->HandlePlayerLoginFromDB(holder); // will delete lqh
|
botSession->HandlePlayerLoginFromDB(holder); // will delete lqh
|
||||||
@@ -475,11 +473,11 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Player* master = botAI->GetMaster();
|
Player* master = botAI->GetMaster();
|
||||||
if (master)
|
if (!master)
|
||||||
{
|
{
|
||||||
ObjectGuid masterGuid = master->GetGUID();
|
// Log a warning to indicate that the master is null
|
||||||
if (master->GetGroup() && !master->GetGroup()->IsLeader(masterGuid))
|
LOG_DEBUG("mod-playerbots", "Master is null for bot with GUID: {}", bot->GetGUID().GetRawValue());
|
||||||
master->GetGroup()->ChangeLeader(masterGuid);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
@@ -498,10 +496,7 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// Don't disband alt groups when master goes away
|
|
||||||
// Controlled by config
|
|
||||||
if (sPlayerbotAIConfig->KeepAltsInGroup())
|
|
||||||
{
|
{
|
||||||
uint32 account = sCharacterCache->GetCharacterAccountIdByGuid(member);
|
uint32 account = sCharacterCache->GetCharacterAccountIdByGuid(member);
|
||||||
if (!sPlayerbotAIConfig->IsInRandomAccountList(account))
|
if (!sPlayerbotAIConfig->IsInRandomAccountList(account))
|
||||||
@@ -586,8 +581,8 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bot->SaveToDB(false, false);
|
bot->SaveToDB(false, false);
|
||||||
bool addClassBot = sRandomPlayerbotMgr->IsAccountType(accountId, 2);
|
bool addClassBot = sRandomPlayerbotMgr->IsAddclassBot(bot->GetGUID().GetCounter());
|
||||||
if (addClassBot && master && abs((int)master->GetLevel() - (int)bot->GetLevel()) > 3)
|
if (addClassBot && master && isRandomAccount && abs((int)master->GetLevel() - (int)bot->GetLevel()) > 3)
|
||||||
{
|
{
|
||||||
// PlayerbotFactory factory(bot, master->GetLevel());
|
// PlayerbotFactory factory(bot, master->GetLevel());
|
||||||
// factory.Randomize(false);
|
// factory.Randomize(false);
|
||||||
@@ -839,18 +834,6 @@ std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, Obje
|
|||||||
return "unknown command";
|
return "unknown command";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Added for gender choice : Returns the gender of an offline character: 0 = male, 1 = female.
|
|
||||||
static uint8 GetOfflinePlayerGender(ObjectGuid guid)
|
|
||||||
{
|
|
||||||
QueryResult result = CharacterDatabase.Query(
|
|
||||||
"SELECT gender FROM characters WHERE guid = {}", guid.GetCounter());
|
|
||||||
|
|
||||||
if (result)
|
|
||||||
return (*result)[0].Get<uint8>(); // 0 = male, 1 = female
|
|
||||||
|
|
||||||
return GENDER_MALE; // fallback value
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PlayerbotMgr::HandlePlayerbotMgrCommand(ChatHandler* handler, char const* args)
|
bool PlayerbotMgr::HandlePlayerbotMgrCommand(ChatHandler* handler, char const* args)
|
||||||
{
|
{
|
||||||
if (!sPlayerbotAIConfig->enabled)
|
if (!sPlayerbotAIConfig->enabled)
|
||||||
@@ -893,17 +876,15 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
|
|||||||
if (!*args)
|
if (!*args)
|
||||||
{
|
{
|
||||||
messages.push_back("usage: list/reload/tweak/self or add/addaccount/init/remove PLAYERNAME\n");
|
messages.push_back("usage: list/reload/tweak/self or add/addaccount/init/remove PLAYERNAME\n");
|
||||||
messages.push_back("usage: addclass CLASSNAME [male|female|0|1]");
|
messages.push_back("usage: addclass CLASSNAME");
|
||||||
return messages;
|
return messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* cmd = strtok((char*)args, " ");
|
char* cmd = strtok((char*)args, " ");
|
||||||
char* charname = strtok(nullptr, " ");
|
char* charname = strtok(nullptr, " ");
|
||||||
char* genderArg = strtok(nullptr, " "); // Added for gender choice [male|female|0|1] optionnel
|
|
||||||
|
|
||||||
if (!cmd)
|
if (!cmd)
|
||||||
{
|
{
|
||||||
messages.push_back("usage: list/reload/tweak/self or add/init/remove PLAYERNAME or addclass CLASSNAME [male|female]");
|
messages.push_back("usage: list/reload/tweak/self or add/init/remove PLAYERNAME or addclass CLASSNAME");
|
||||||
return messages;
|
return messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1126,24 +1107,6 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
|
|||||||
messages.push_back("Error: Invalid Class. Try again.");
|
messages.push_back("Error: Invalid Class. Try again.");
|
||||||
return messages;
|
return messages;
|
||||||
}
|
}
|
||||||
// Added for gender choice : Parsing gender
|
|
||||||
int8 gender = -1; // -1 = gender will be random
|
|
||||||
if (genderArg)
|
|
||||||
{
|
|
||||||
std::string g = genderArg;
|
|
||||||
std::transform(g.begin(), g.end(), g.begin(), ::tolower);
|
|
||||||
|
|
||||||
if (g == "male" || g == "0")
|
|
||||||
gender = GENDER_MALE; // 0
|
|
||||||
else if (g == "female" || g == "1")
|
|
||||||
gender = GENDER_FEMALE; // 1
|
|
||||||
else
|
|
||||||
{
|
|
||||||
messages.push_back("Unknown gender : " + g + " (male/female/0/1)");
|
|
||||||
return messages;
|
|
||||||
}
|
|
||||||
} //end
|
|
||||||
|
|
||||||
if (claz == 6 && master->GetLevel() < sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL))
|
if (claz == 6 && master->GetLevel() < sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL))
|
||||||
{
|
{
|
||||||
messages.push_back("Your level is too low to summon Deathknight");
|
messages.push_back("Your level is too low to summon Deathknight");
|
||||||
@@ -1153,9 +1116,6 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
|
|||||||
const std::unordered_set<ObjectGuid> &guidCache = sRandomPlayerbotMgr->addclassCache[RandomPlayerbotMgr::GetTeamClassIdx(teamId == TEAM_ALLIANCE, claz)];
|
const std::unordered_set<ObjectGuid> &guidCache = sRandomPlayerbotMgr->addclassCache[RandomPlayerbotMgr::GetTeamClassIdx(teamId == TEAM_ALLIANCE, claz)];
|
||||||
for (const ObjectGuid &guid: guidCache)
|
for (const ObjectGuid &guid: guidCache)
|
||||||
{
|
{
|
||||||
// If the user requested a specific gender, skip any character that doesn't match.
|
|
||||||
if (gender != -1 && GetOfflinePlayerGender(guid) != gender)
|
|
||||||
continue;
|
|
||||||
if (botLoading.find(guid) != botLoading.end())
|
if (botLoading.find(guid) != botLoading.end())
|
||||||
continue;
|
continue;
|
||||||
if (ObjectAccessor::FindConnectedPlayer(guid))
|
if (ObjectAccessor::FindConnectedPlayer(guid))
|
||||||
@@ -1774,7 +1734,7 @@ void PlayerbotMgr::HandleSetSecurityKeyCommand(Player* player, const std::string
|
|||||||
|
|
||||||
// Store the hashed key in the database
|
// Store the hashed key in the database
|
||||||
PlayerbotsDatabase.Execute(
|
PlayerbotsDatabase.Execute(
|
||||||
"REPLACE INTO playerbots_account_keys (account_id, security_key) VALUES ({}, '{}')",
|
"REPLACE INTO playerbot_account_keys (account_id, security_key) VALUES ({}, '{}')",
|
||||||
accountId, hashedKey.str());
|
accountId, hashedKey.str());
|
||||||
|
|
||||||
ChatHandler(player->GetSession()).PSendSysMessage("Security key set successfully.");
|
ChatHandler(player->GetSession()).PSendSysMessage("Security key set successfully.");
|
||||||
@@ -1792,7 +1752,7 @@ void PlayerbotMgr::HandleLinkAccountCommand(Player* player, const std::string& a
|
|||||||
Field* fields = result->Fetch();
|
Field* fields = result->Fetch();
|
||||||
uint32 linkedAccountId = fields[0].Get<uint32>();
|
uint32 linkedAccountId = fields[0].Get<uint32>();
|
||||||
|
|
||||||
result = PlayerbotsDatabase.Query("SELECT security_key FROM playerbots_account_keys WHERE account_id = {}", linkedAccountId);
|
result = PlayerbotsDatabase.Query("SELECT security_key FROM playerbot_account_keys WHERE account_id = {}", linkedAccountId);
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
ChatHandler(player->GetSession()).PSendSysMessage("Invalid security key.");
|
ChatHandler(player->GetSession()).PSendSysMessage("Invalid security key.");
|
||||||
@@ -1818,10 +1778,10 @@ void PlayerbotMgr::HandleLinkAccountCommand(Player* player, const std::string& a
|
|||||||
|
|
||||||
uint32 accountId = player->GetSession()->GetAccountId();
|
uint32 accountId = player->GetSession()->GetAccountId();
|
||||||
PlayerbotsDatabase.Execute(
|
PlayerbotsDatabase.Execute(
|
||||||
"INSERT IGNORE INTO playerbots_account_links (account_id, linked_account_id) VALUES ({}, {})",
|
"INSERT IGNORE INTO playerbot_account_links (account_id, linked_account_id) VALUES ({}, {})",
|
||||||
accountId, linkedAccountId);
|
accountId, linkedAccountId);
|
||||||
PlayerbotsDatabase.Execute(
|
PlayerbotsDatabase.Execute(
|
||||||
"INSERT IGNORE INTO playerbots_account_links (account_id, linked_account_id) VALUES ({}, {})",
|
"INSERT IGNORE INTO playerbot_account_links (account_id, linked_account_id) VALUES ({}, {})",
|
||||||
linkedAccountId, accountId);
|
linkedAccountId, accountId);
|
||||||
|
|
||||||
ChatHandler(player->GetSession()).PSendSysMessage("Account linked successfully.");
|
ChatHandler(player->GetSession()).PSendSysMessage("Account linked successfully.");
|
||||||
@@ -1830,7 +1790,7 @@ void PlayerbotMgr::HandleLinkAccountCommand(Player* player, const std::string& a
|
|||||||
void PlayerbotMgr::HandleViewLinkedAccountsCommand(Player* player)
|
void PlayerbotMgr::HandleViewLinkedAccountsCommand(Player* player)
|
||||||
{
|
{
|
||||||
uint32 accountId = player->GetSession()->GetAccountId();
|
uint32 accountId = player->GetSession()->GetAccountId();
|
||||||
QueryResult result = PlayerbotsDatabase.Query("SELECT linked_account_id FROM playerbots_account_links WHERE account_id = {}", accountId);
|
QueryResult result = PlayerbotsDatabase.Query("SELECT linked_account_id FROM playerbot_account_links WHERE account_id = {}", accountId);
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
@@ -1871,7 +1831,7 @@ void PlayerbotMgr::HandleUnlinkAccountCommand(Player* player, const std::string&
|
|||||||
uint32 linkedAccountId = fields[0].Get<uint32>();
|
uint32 linkedAccountId = fields[0].Get<uint32>();
|
||||||
uint32 accountId = player->GetSession()->GetAccountId();
|
uint32 accountId = player->GetSession()->GetAccountId();
|
||||||
|
|
||||||
PlayerbotsDatabase.Execute("DELETE FROM playerbots_account_links WHERE (account_id = {} AND linked_account_id = {}) OR (account_id = {} AND linked_account_id = {})",
|
PlayerbotsDatabase.Execute("DELETE FROM playerbot_account_links WHERE (account_id = {} AND linked_account_id = {}) OR (account_id = {} AND linked_account_id = {})",
|
||||||
accountId, linkedAccountId, linkedAccountId, accountId);
|
accountId, linkedAccountId, linkedAccountId, accountId);
|
||||||
|
|
||||||
ChatHandler(player->GetSession()).PSendSysMessage("Account unlinked successfully.");
|
ChatHandler(player->GetSession()).PSendSysMessage("Account unlinked successfully.");
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
#include "ScriptMgr.h"
|
#include "ScriptMgr.h"
|
||||||
#include "cs_playerbots.h"
|
#include "cs_playerbots.h"
|
||||||
#include "cmath"
|
#include "cmath"
|
||||||
#include "BattleGroundTactics.h"
|
|
||||||
|
|
||||||
class PlayerbotsDatabaseScript : public DatabaseScript
|
class PlayerbotsDatabaseScript : public DatabaseScript
|
||||||
{
|
{
|
||||||
@@ -197,43 +196,34 @@ public:
|
|||||||
sRandomPlayerbotMgr->HandleCommand(type, msg, player);
|
sRandomPlayerbotMgr->HandleCommand(type, msg, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OnPlayerBeforeAchievementComplete(Player* player, AchievementEntry const* achievement) override
|
bool OnPlayerBeforeCriteriaProgress(Player* player, AchievementCriteriaEntry const* /*criteria*/) override
|
||||||
{
|
{
|
||||||
if (sRandomPlayerbotMgr->IsRandomBot(player) && (achievement->flags == 256 || achievement->flags == 768))
|
if (sRandomPlayerbotMgr->IsRandomBot(player))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OnPlayerBeforeAchievementComplete(Player* player, AchievementEntry const* /*achievement*/) override
|
||||||
|
{
|
||||||
|
if (sRandomPlayerbotMgr->IsRandomBot(player))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnPlayerGiveXP(Player* player, uint32& amount, Unit* /*victim*/, uint8 /*xpSource*/) override
|
void OnPlayerGiveXP(Player* player, uint32& amount, Unit* /*victim*/, uint8 /*xpSource*/) override
|
||||||
{
|
{
|
||||||
// early return
|
if (!player->GetSession()->IsBot())
|
||||||
if (sPlayerbotAIConfig->randomBotXPRate == 1.0 || !player)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// no XP multiplier, when player is no bot.
|
if (sPlayerbotAIConfig->playerbotsXPrate != 1.0)
|
||||||
if (!player->GetSession()->IsBot() || !sRandomPlayerbotMgr->IsRandomBot(player))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// no XP multiplier, when bot has group where leader is a real player.
|
|
||||||
if (Group* group = player->GetGroup())
|
|
||||||
{
|
{
|
||||||
Player* leader = group->GetLeader();
|
amount = static_cast<uint32>(std::round(static_cast<float>(amount) * sPlayerbotAIConfig->playerbotsXPrate));
|
||||||
if (leader && leader != player)
|
|
||||||
{
|
|
||||||
if (PlayerbotAI* leaderBotAI = GET_PLAYERBOT_AI(leader))
|
|
||||||
{
|
|
||||||
if (leaderBotAI->HasRealPlayerMaster())
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise apply bot XP multiplier.
|
|
||||||
amount = static_cast<uint32>(std::round(static_cast<float>(amount) * sPlayerbotAIConfig->randomBotXPRate));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PlayerbotsMiscScript : public MiscScript
|
class PlayerbotsMiscScript : public MiscScript
|
||||||
@@ -396,43 +386,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class PlayerBotsBGScript : public BGScript
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PlayerBotsBGScript() : BGScript("PlayerBotsBGScript") {}
|
|
||||||
|
|
||||||
void OnBattlegroundStart(Battleground* bg) override
|
|
||||||
{
|
|
||||||
BGStrategyData data;
|
|
||||||
|
|
||||||
switch (bg->GetBgTypeID())
|
|
||||||
{
|
|
||||||
case BATTLEGROUND_WS:
|
|
||||||
data.allianceStrategy = urand(0, WS_STRATEGY_MAX - 1);
|
|
||||||
data.hordeStrategy = urand(0, WS_STRATEGY_MAX - 1);
|
|
||||||
break;
|
|
||||||
case BATTLEGROUND_AB:
|
|
||||||
data.allianceStrategy = urand(0, AB_STRATEGY_MAX - 1);
|
|
||||||
data.hordeStrategy = urand(0, AB_STRATEGY_MAX - 1);
|
|
||||||
break;
|
|
||||||
case BATTLEGROUND_AV:
|
|
||||||
data.allianceStrategy = urand(0, AV_STRATEGY_MAX - 1);
|
|
||||||
data.hordeStrategy = urand(0, AV_STRATEGY_MAX - 1);
|
|
||||||
break;
|
|
||||||
case BATTLEGROUND_EY:
|
|
||||||
data.allianceStrategy = urand(0, EY_STRATEGY_MAX - 1);
|
|
||||||
data.hordeStrategy = urand(0, EY_STRATEGY_MAX - 1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
bgStrategies[bg->GetInstanceID()] = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnBattlegroundEnd(Battleground* bg, TeamId /*winnerTeam*/) override { bgStrategies.erase(bg->GetInstanceID()); }
|
|
||||||
};
|
|
||||||
|
|
||||||
void AddPlayerbotsScripts()
|
void AddPlayerbotsScripts()
|
||||||
{
|
{
|
||||||
new PlayerbotsDatabaseScript();
|
new PlayerbotsDatabaseScript();
|
||||||
@@ -441,7 +394,6 @@ void AddPlayerbotsScripts()
|
|||||||
new PlayerbotsServerScript();
|
new PlayerbotsServerScript();
|
||||||
new PlayerbotsWorldScript();
|
new PlayerbotsWorldScript();
|
||||||
new PlayerbotsScript();
|
new PlayerbotsScript();
|
||||||
new PlayerBotsBGScript();
|
|
||||||
|
|
||||||
AddSC_playerbots_commandscript();
|
AddSC_playerbots_commandscript();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -393,118 +393,37 @@ std::string const RandomPlayerbotFactory::CreateRandomBotName(NameRaceAndGender
|
|||||||
return std::move(botName);
|
return std::move(botName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculates the total number of required accounts, either using the specified randomBotAccountCount
|
|
||||||
// or determining it dynamically based on MaxRandomBots, EnablePeriodicOnlineOffline and its ratio,
|
|
||||||
// and AddClassAccountPoolSize. The system also factors in the types of existing account, as assigned by
|
|
||||||
// AssignAccountTypes()
|
|
||||||
uint32 RandomPlayerbotFactory::CalculateTotalAccountCount()
|
uint32 RandomPlayerbotFactory::CalculateTotalAccountCount()
|
||||||
{
|
{
|
||||||
// Reset account types if features are disabled
|
// Calculates the total number of required accounts, either using the specified randomBotAccountCount
|
||||||
// Reset is done here to precede needed accounts calculations
|
// or determining it dynamically based on the WOTLK condition, max random bots, rotation pool size,
|
||||||
if (sPlayerbotAIConfig->maxRandomBots == 0 || sPlayerbotAIConfig->addClassAccountPoolSize == 0)
|
// and additional class account pool size.
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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)");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for DB to reflect the change, up to 1 second max. This is needed to make sure other logs don't show wrong info
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (!res || res->Fetch()[0].Get<uint64>() == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Extra 50ms fixed delay for safety.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks if randomBotAccountCount is set, otherwise calculate it dynamically.
|
// Checks if randomBotAccountCount is set, otherwise calculate it dynamically.
|
||||||
if (sPlayerbotAIConfig->randomBotAccountCount > 0)
|
if (sPlayerbotAIConfig->randomBotAccountCount > 0)
|
||||||
return sPlayerbotAIConfig->randomBotAccountCount;
|
return sPlayerbotAIConfig->randomBotAccountCount;
|
||||||
|
|
||||||
// Check existing account types
|
// Avoid creating accounts if both maxRandom & ClassBots are set to zero.
|
||||||
uint32 existingRndBotAccounts = 0;
|
if (sPlayerbotAIConfig->maxRandomBots == 0 &&
|
||||||
uint32 existingAddClassAccounts = 0;
|
sPlayerbotAIConfig->addClassAccountPoolSize == 0)
|
||||||
uint32 existingUnassignedAccounts = 0;
|
return 0;
|
||||||
|
|
||||||
QueryResult typeCheck = PlayerbotsDatabase.Query("SELECT account_type, COUNT(*) FROM playerbots_account_type GROUP BY account_type");
|
//bool isWOTLK = sWorld->getIntConfig(CONFIG_EXPANSION) == EXPANSION_WRATH_OF_THE_LICH_KING; //not used, line marked for removal.
|
||||||
if (typeCheck)
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
Field* fields = typeCheck->Fetch();
|
|
||||||
uint8 accountType = fields[0].Get<uint8>();
|
|
||||||
uint32 count = fields[1].Get<uint32>();
|
|
||||||
|
|
||||||
if (accountType == 0) existingUnassignedAccounts = count;
|
// Determine divisor based on WOTLK condition
|
||||||
else if (accountType == 1) existingRndBotAccounts = count;
|
|
||||||
else if (accountType == 2) existingAddClassAccounts = count;
|
|
||||||
} while (typeCheck->NextRow());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine divisor based on Death Knight login eligibility and requested A&H faction ratio
|
|
||||||
int divisor = CalculateAvailableCharsPerAccount();
|
int divisor = CalculateAvailableCharsPerAccount();
|
||||||
|
|
||||||
// Calculate max bots
|
// Calculate max bots
|
||||||
int maxBots = sPlayerbotAIConfig->maxRandomBots;
|
int maxBots = sPlayerbotAIConfig->maxRandomBots;
|
||||||
// Take periodic online - offline into account
|
// Take perodic online - offline into account
|
||||||
if (sPlayerbotAIConfig->enablePeriodicOnlineOffline)
|
if (sPlayerbotAIConfig->enablePeriodicOnlineOffline)
|
||||||
{
|
{
|
||||||
maxBots *= sPlayerbotAIConfig->periodicOnlineOfflineRatio;
|
maxBots *= sPlayerbotAIConfig->periodicOnlineOfflineRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate number of accounts needed for RNDbots
|
// Calculate base accounts, add class account pool size, and add 1 as a fixed offset
|
||||||
// Result is rounded up for maxBots not cleanly divisible by the divisor
|
uint32 baseAccounts = maxBots / divisor;
|
||||||
uint32 neededRndBotAccounts = (maxBots + divisor - 1) / divisor;
|
return baseAccounts + sPlayerbotAIConfig->addClassAccountPoolSize + 1;
|
||||||
uint32 neededAddClassAccounts = sPlayerbotAIConfig->addClassAccountPoolSize;
|
|
||||||
|
|
||||||
// Start with existing total
|
|
||||||
uint32 existingTotal = existingRndBotAccounts + existingAddClassAccounts + existingUnassignedAccounts;
|
|
||||||
|
|
||||||
// Calculate shortfalls after using unassigned accounts
|
|
||||||
uint32 availableUnassigned = existingUnassignedAccounts;
|
|
||||||
uint32 additionalAccountsNeeded = 0;
|
|
||||||
|
|
||||||
// Check RNDbot needs
|
|
||||||
if (neededRndBotAccounts > existingRndBotAccounts)
|
|
||||||
{
|
|
||||||
uint32 rndBotShortfall = neededRndBotAccounts - existingRndBotAccounts;
|
|
||||||
if (rndBotShortfall <= availableUnassigned)
|
|
||||||
availableUnassigned -= rndBotShortfall;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
additionalAccountsNeeded += (rndBotShortfall - availableUnassigned);
|
|
||||||
availableUnassigned = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check AddClass needs
|
|
||||||
if (neededAddClassAccounts > existingAddClassAccounts)
|
|
||||||
{
|
|
||||||
uint32 addClassShortfall = neededAddClassAccounts - existingAddClassAccounts;
|
|
||||||
if (addClassShortfall <= availableUnassigned)
|
|
||||||
availableUnassigned -= addClassShortfall;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
additionalAccountsNeeded += (addClassShortfall - availableUnassigned);
|
|
||||||
availableUnassigned = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return existing total plus any additional accounts needed
|
|
||||||
return existingTotal + additionalAccountsNeeded;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 RandomPlayerbotFactory::CalculateAvailableCharsPerAccount()
|
uint32 RandomPlayerbotFactory::CalculateAvailableCharsPerAccount()
|
||||||
@@ -556,9 +475,8 @@ void RandomPlayerbotFactory::CreateRandomBots()
|
|||||||
LOG_INFO("playerbots", "Deleting all random bot characters and accounts...");
|
LOG_INFO("playerbots", "Deleting all random bot characters and accounts...");
|
||||||
|
|
||||||
// First execute all the cleanup SQL commands
|
// First execute all the cleanup SQL commands
|
||||||
// Clear playerbots_random_bots and playerbots_account_type
|
// Clear playerbots_random_bots table
|
||||||
PlayerbotsDatabase.Execute("DELETE FROM playerbots_random_bots");
|
PlayerbotsDatabase.Execute("DELETE FROM playerbots_random_bots");
|
||||||
PlayerbotsDatabase.Execute("DELETE FROM playerbots_account_type");
|
|
||||||
|
|
||||||
// Get the database names dynamically
|
// Get the database names dynamically
|
||||||
std::string loginDBName = LoginDatabase.GetConnectionInfo()->database;
|
std::string loginDBName = LoginDatabase.GetConnectionInfo()->database;
|
||||||
@@ -568,13 +486,6 @@ void RandomPlayerbotFactory::CreateRandomBots()
|
|||||||
CharacterDatabase.Execute("DELETE FROM characters WHERE account IN (SELECT id FROM " + loginDBName + ".account WHERE username LIKE '{}%%')",
|
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())
|
|
||||||
{
|
|
||||||
std::this_thread::sleep_for(1s);
|
|
||||||
}
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Extra 100ms fixed delay for safety.
|
|
||||||
|
|
||||||
// Clean up orphaned entries in playerbots_guild_tasks
|
// Clean up orphaned entries in playerbots_guild_tasks
|
||||||
PlayerbotsDatabase.Execute("DELETE FROM playerbots_guild_tasks WHERE owner NOT IN (SELECT guid FROM " + characterDBName + ".characters)");
|
PlayerbotsDatabase.Execute("DELETE FROM playerbots_guild_tasks WHERE owner NOT IN (SELECT guid FROM " + characterDBName + ".characters)");
|
||||||
|
|
||||||
@@ -589,13 +500,11 @@ void RandomPlayerbotFactory::CreateRandomBots()
|
|||||||
CharacterDatabase.Execute("DELETE FROM character_achievement WHERE guid NOT IN (SELECT guid FROM characters)");
|
CharacterDatabase.Execute("DELETE FROM character_achievement WHERE guid NOT IN (SELECT guid FROM characters)");
|
||||||
CharacterDatabase.Execute("DELETE FROM character_achievement_progress WHERE guid NOT IN (SELECT guid FROM characters)");
|
CharacterDatabase.Execute("DELETE FROM character_achievement_progress WHERE guid NOT IN (SELECT guid FROM characters)");
|
||||||
CharacterDatabase.Execute("DELETE FROM character_action WHERE guid NOT IN (SELECT guid FROM characters)");
|
CharacterDatabase.Execute("DELETE FROM character_action WHERE guid NOT IN (SELECT guid FROM characters)");
|
||||||
CharacterDatabase.Execute("DELETE FROM character_arena_stats WHERE guid NOT IN (SELECT guid FROM characters)");
|
|
||||||
CharacterDatabase.Execute("DELETE FROM character_aura WHERE guid NOT IN (SELECT guid FROM characters)");
|
CharacterDatabase.Execute("DELETE FROM character_aura WHERE guid NOT IN (SELECT guid FROM characters)");
|
||||||
CharacterDatabase.Execute("DELETE FROM character_entry_point WHERE guid NOT IN (SELECT guid FROM characters)");
|
|
||||||
CharacterDatabase.Execute("DELETE FROM character_glyphs WHERE guid NOT IN (SELECT guid FROM characters)");
|
CharacterDatabase.Execute("DELETE FROM character_glyphs WHERE guid NOT IN (SELECT guid FROM characters)");
|
||||||
CharacterDatabase.Execute("DELETE FROM character_homebind WHERE guid NOT IN (SELECT guid FROM characters)");
|
CharacterDatabase.Execute("DELETE FROM character_homebind WHERE guid NOT IN (SELECT guid FROM characters)");
|
||||||
CharacterDatabase.Execute("DELETE FROM character_inventory WHERE guid NOT IN (SELECT guid FROM characters)");
|
|
||||||
CharacterDatabase.Execute("DELETE FROM item_instance WHERE owner_guid NOT IN (SELECT guid FROM characters) AND owner_guid > 0");
|
CharacterDatabase.Execute("DELETE FROM item_instance WHERE owner_guid NOT IN (SELECT guid FROM characters) AND owner_guid > 0");
|
||||||
|
CharacterDatabase.Execute("DELETE FROM character_inventory WHERE guid NOT IN (SELECT guid FROM characters)");
|
||||||
|
|
||||||
// Clean up pet data
|
// Clean up pet data
|
||||||
CharacterDatabase.Execute("DELETE FROM character_pet WHERE owner NOT IN (SELECT guid FROM characters)");
|
CharacterDatabase.Execute("DELETE FROM character_pet WHERE owner NOT IN (SELECT guid FROM characters)");
|
||||||
@@ -650,23 +559,11 @@ void RandomPlayerbotFactory::CreateRandomBots()
|
|||||||
|
|
||||||
uint32 timer = getMSTime();
|
uint32 timer = getMSTime();
|
||||||
|
|
||||||
// After ALL deletions, make sure data is commited to DB
|
|
||||||
LoginDatabase.Execute("COMMIT");
|
|
||||||
CharacterDatabase.Execute("COMMIT");
|
|
||||||
PlayerbotsDatabase.Execute("COMMIT");
|
|
||||||
|
|
||||||
// Wait for all pending database operations to complete
|
// Wait for all pending database operations to complete
|
||||||
while (LoginDatabase.QueueSize() || CharacterDatabase.QueueSize() || PlayerbotsDatabase.QueueSize())
|
while (LoginDatabase.QueueSize() || CharacterDatabase.QueueSize() || PlayerbotsDatabase.QueueSize())
|
||||||
{
|
{
|
||||||
std::this_thread::sleep_for(1s);
|
std::this_thread::sleep_for(1s);
|
||||||
}
|
}
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Extra 100ms fixed delay for safety.
|
|
||||||
|
|
||||||
// Flush tables to ensure all data in memory are written to disk
|
|
||||||
LoginDatabase.Execute("FLUSH TABLES");
|
|
||||||
CharacterDatabase.Execute("FLUSH TABLES");
|
|
||||||
PlayerbotsDatabase.Execute("FLUSH TABLES");
|
|
||||||
|
|
||||||
LOG_INFO("playerbots", ">> Random bot accounts and data deleted in {} ms", GetMSTimeDiffToNow(timer));
|
LOG_INFO("playerbots", ">> Random bot accounts and data deleted in {} ms", GetMSTimeDiffToNow(timer));
|
||||||
LOG_INFO("playerbots", "Please reset the AiPlayerbot.DeleteRandomBotAccounts to 0 and restart the server...");
|
LOG_INFO("playerbots", "Please reset the AiPlayerbot.DeleteRandomBotAccounts to 0 and restart the server...");
|
||||||
World::StopNow(SHUTDOWN_EXIT_CODE);
|
World::StopNow(SHUTDOWN_EXIT_CODE);
|
||||||
@@ -785,7 +682,7 @@ void RandomPlayerbotFactory::CreateRandomBots()
|
|||||||
LOG_DEBUG("playerbots", "Creating random bot characters for account: [{}/{}]", accountNumber + 1, totalAccountCount);
|
LOG_DEBUG("playerbots", "Creating random bot characters for account: [{}/{}]", accountNumber + 1, totalAccountCount);
|
||||||
RandomPlayerbotFactory factory(accountId);
|
RandomPlayerbotFactory factory(accountId);
|
||||||
|
|
||||||
WorldSession* session = new WorldSession(accountId, "", 0x0, nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING,
|
WorldSession* session = new WorldSession(accountId, "", nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING,
|
||||||
time_t(0), LOCALE_enUS, 0, false, false, 0, true);
|
time_t(0), LOCALE_enUS, 0, false, false, 0, true);
|
||||||
sessionBots.push_back(session);
|
sessionBots.push_back(session);
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -60,6 +60,7 @@ public:
|
|||||||
|
|
||||||
bool IsEmpty() { return !lastChangeTime; }
|
bool IsEmpty() { return !lastChangeTime; }
|
||||||
|
|
||||||
|
public:
|
||||||
uint32 value;
|
uint32 value;
|
||||||
uint32 lastChangeTime;
|
uint32 lastChangeTime;
|
||||||
uint32 validIn;
|
uint32 validIn;
|
||||||
@@ -103,6 +104,10 @@ public:
|
|||||||
void LogPlayerLocation();
|
void LogPlayerLocation();
|
||||||
void UpdateAIInternal(uint32 elapsed, bool minimal = false) override;
|
void UpdateAIInternal(uint32 elapsed, bool minimal = false) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//void ScaleBotActivity();
|
||||||
|
|
||||||
|
public:
|
||||||
uint32 activeBots = 0;
|
uint32 activeBots = 0;
|
||||||
static bool HandlePlayerbotConsoleCommand(ChatHandler* handler, char const* args);
|
static bool HandlePlayerbotConsoleCommand(ChatHandler* handler, char const* args);
|
||||||
bool IsRandomBot(Player* bot);
|
bool IsRandomBot(Player* bot);
|
||||||
@@ -175,24 +180,13 @@ public:
|
|||||||
std::map<uint8, std::vector<WorldLocation>> locsPerLevelCache;
|
std::map<uint8, std::vector<WorldLocation>> locsPerLevelCache;
|
||||||
std::map<uint8, std::vector<WorldLocation>> allianceStarterPerLevelCache;
|
std::map<uint8, std::vector<WorldLocation>> allianceStarterPerLevelCache;
|
||||||
std::map<uint8, std::vector<WorldLocation>> hordeStarterPerLevelCache;
|
std::map<uint8, std::vector<WorldLocation>> hordeStarterPerLevelCache;
|
||||||
std::vector<uint32> allianceFlightMasterCache;
|
|
||||||
std::vector<uint32> hordeFlightMasterCache;
|
|
||||||
struct LevelBracket {
|
struct LevelBracket {
|
||||||
uint32 low;
|
uint32 low;
|
||||||
uint32 high;
|
uint32 high;
|
||||||
bool InsideBracket(uint32 val) { return val >= low && val <= high; }
|
bool InsideBracket(uint32 val) { return val >= low && val <= high; }
|
||||||
};
|
};
|
||||||
std::map<uint32, LevelBracket> zone2LevelBracket;
|
std::map<uint32, LevelBracket> zone2LevelBracket;
|
||||||
struct BankerLocation {
|
std::map<uint8, std::vector<WorldLocation>> bankerLocsPerLevelCache;
|
||||||
WorldLocation loc;
|
|
||||||
uint32 entry;
|
|
||||||
};
|
|
||||||
std::map<uint8, std::vector<BankerLocation>> bankerLocsPerLevelCache;
|
|
||||||
|
|
||||||
// Account type management
|
|
||||||
void AssignAccountTypes();
|
|
||||||
bool IsAccountType(uint32 accountId, uint8 accountType);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OnBotLoginInternal(Player* const bot) override;
|
void OnBotLoginInternal(Player* const bot) override;
|
||||||
|
|
||||||
@@ -212,8 +206,6 @@ private:
|
|||||||
time_t BgCheckTimer;
|
time_t BgCheckTimer;
|
||||||
time_t LfgCheckTimer;
|
time_t LfgCheckTimer;
|
||||||
time_t PlayersCheckTimer;
|
time_t PlayersCheckTimer;
|
||||||
time_t RealPlayerLastTimeSeen = 0;
|
|
||||||
time_t DelayLoginBotsTimer;
|
|
||||||
time_t printStatsTimer;
|
time_t printStatsTimer;
|
||||||
uint32 AddRandomBots();
|
uint32 AddRandomBots();
|
||||||
bool ProcessBot(uint32 bot);
|
bool ProcessBot(uint32 bot);
|
||||||
@@ -222,9 +214,11 @@ private:
|
|||||||
void RandomTeleport(Player* bot, std::vector<WorldLocation>& locs, bool hearth = false);
|
void RandomTeleport(Player* bot, std::vector<WorldLocation>& locs, bool hearth = false);
|
||||||
uint32 GetZoneLevel(uint16 mapId, float teleX, float teleY, float teleZ);
|
uint32 GetZoneLevel(uint16 mapId, float teleX, float teleY, float teleZ);
|
||||||
typedef void (RandomPlayerbotMgr::*ConsoleCommandHandler)(Player*);
|
typedef void (RandomPlayerbotMgr::*ConsoleCommandHandler)(Player*);
|
||||||
|
|
||||||
std::vector<Player*> players;
|
std::vector<Player*> players;
|
||||||
uint32 processTicks;
|
uint32 processTicks;
|
||||||
|
|
||||||
|
|
||||||
// std::map<uint32, std::vector<WorldLocation>> rpgLocsCache;
|
// std::map<uint32, std::vector<WorldLocation>> rpgLocsCache;
|
||||||
std::map<uint32, std::map<uint32, std::vector<WorldLocation>>> rpgLocsCacheLevel;
|
std::map<uint32, std::map<uint32, std::vector<WorldLocation>>> rpgLocsCacheLevel;
|
||||||
std::map<TeamId, std::map<BattlegroundTypeId, std::vector<uint32>>> BattleMastersCache;
|
std::map<TeamId, std::map<BattlegroundTypeId, std::vector<uint32>>> BattleMastersCache;
|
||||||
@@ -232,12 +226,6 @@ private:
|
|||||||
std::list<uint32> currentBots;
|
std::list<uint32> currentBots;
|
||||||
uint32 bgBotsCount;
|
uint32 bgBotsCount;
|
||||||
uint32 playersLevel;
|
uint32 playersLevel;
|
||||||
|
|
||||||
// Account lists
|
|
||||||
std::vector<uint32> rndBotTypeAccounts; // Accounts marked as RNDbot (type 1)
|
|
||||||
std::vector<uint32> addClassTypeAccounts; // Accounts marked as AddClass (type 2)
|
|
||||||
|
|
||||||
//void ScaleBotActivity(); // Deprecated function
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define sRandomPlayerbotMgr RandomPlayerbotMgr::instance()
|
#define sRandomPlayerbotMgr RandomPlayerbotMgr::instance()
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "Queue.h"
|
#include "Queue.h"
|
||||||
#include "Strategy.h"
|
#include "Strategy.h"
|
||||||
#include "Timer.h"
|
|
||||||
|
|
||||||
Engine::Engine(PlayerbotAI* botAI, AiObjectContext* factory) : PlayerbotAIAware(botAI), aiObjectContext(factory)
|
Engine::Engine(PlayerbotAI* botAI, AiObjectContext* factory) : PlayerbotAIAware(botAI), aiObjectContext(factory)
|
||||||
{
|
{
|
||||||
@@ -109,8 +108,6 @@ void Engine::Reset()
|
|||||||
}
|
}
|
||||||
|
|
||||||
multipliers.clear();
|
multipliers.clear();
|
||||||
|
|
||||||
actionNodeFactories.creators.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::Init()
|
void Engine::Init()
|
||||||
@@ -123,10 +120,9 @@ void Engine::Init()
|
|||||||
strategyTypeMask |= strategy->GetType();
|
strategyTypeMask |= strategy->GetType();
|
||||||
strategy->InitMultipliers(multipliers);
|
strategy->InitMultipliers(multipliers);
|
||||||
strategy->InitTriggers(triggers);
|
strategy->InitTriggers(triggers);
|
||||||
for (auto &iter : strategy->actionNodeFactories.creators)
|
|
||||||
{
|
Event emptyEvent;
|
||||||
actionNodeFactories.creators[iter.first] = iter.second;
|
MultiplyAndPush(strategy->getDefaultActions(), 0.0f, false, emptyEvent, "default");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (testMode)
|
if (testMode)
|
||||||
@@ -252,9 +248,11 @@ bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal)
|
|||||||
|
|
||||||
ActionNode* Engine::CreateActionNode(std::string const name)
|
ActionNode* Engine::CreateActionNode(std::string const name)
|
||||||
{
|
{
|
||||||
ActionNode* node = actionNodeFactories.GetContextObject(name, botAI);
|
for (std::map<std::string, Strategy*>::iterator i = strategies.begin(); i != strategies.end(); i++)
|
||||||
if (node)
|
{
|
||||||
|
if (ActionNode* node = i->second->GetAction(name))
|
||||||
return node;
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
return new ActionNode(name,
|
return new ActionNode(name,
|
||||||
/*P*/ nullptr,
|
/*P*/ nullptr,
|
||||||
@@ -434,7 +432,6 @@ bool Engine::HasStrategy(std::string const name) { return strategies.find(name)
|
|||||||
void Engine::ProcessTriggers(bool minimal)
|
void Engine::ProcessTriggers(bool minimal)
|
||||||
{
|
{
|
||||||
std::unordered_map<Trigger*, Event> fires;
|
std::unordered_map<Trigger*, Event> fires;
|
||||||
uint32 now = getMSTime();
|
|
||||||
for (std::vector<TriggerNode*>::iterator i = triggers.begin(); i != triggers.end(); i++)
|
for (std::vector<TriggerNode*>::iterator i = triggers.begin(); i != triggers.end(); i++)
|
||||||
{
|
{
|
||||||
TriggerNode* node = *i;
|
TriggerNode* node = *i;
|
||||||
@@ -454,7 +451,7 @@ void Engine::ProcessTriggers(bool minimal)
|
|||||||
if (fires.find(trigger) != fires.end())
|
if (fires.find(trigger) != fires.end())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (testMode || trigger->needCheck(now))
|
if (testMode || trigger->needCheck())
|
||||||
{
|
{
|
||||||
if (minimal && node->getFirstRelevance() < 100)
|
if (minimal && node->getFirstRelevance() < 100)
|
||||||
continue;
|
continue;
|
||||||
@@ -114,7 +114,6 @@ protected:
|
|||||||
float lastRelevance;
|
float lastRelevance;
|
||||||
std::string lastAction;
|
std::string lastAction;
|
||||||
uint32 strategyTypeMask;
|
uint32 strategyTypeMask;
|
||||||
NamedObjectFactoryList<ActionNode> actionNodeFactories;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -14,10 +14,10 @@ void Qualified::Qualify(int qual)
|
|||||||
qualifier = out.str();
|
qualifier = out.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const Qualified::MultiQualify(const std::vector<std::string>& qualifiers, const std::string& separator, const std::string_view brackets)
|
std::string const Qualified::MultiQualify(std::vector<std::string> qualifiers, const std::string& separator, const std::string_view brackets)
|
||||||
{
|
{
|
||||||
std::stringstream out;
|
std::stringstream out;
|
||||||
for (uint8 i = 0; i < qualifiers.size(); ++i)
|
for (uint8 i = 0; i < qualifiers.size(); i++)
|
||||||
{
|
{
|
||||||
const std::string& qualifier = qualifiers[i];
|
const std::string& qualifier = qualifiers[i];
|
||||||
if (i == qualifiers.size() - 1)
|
if (i == qualifiers.size() - 1)
|
||||||
@@ -40,13 +40,13 @@ std::string const Qualified::MultiQualify(const std::vector<std::string>& qualif
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> Qualified::getMultiQualifiers(const std::string& qualifier1)
|
std::vector<std::string> Qualified::getMultiQualifiers(std::string const qualifier1)
|
||||||
{
|
{
|
||||||
std::istringstream iss(qualifier1);
|
std::istringstream iss(qualifier1);
|
||||||
return {std::istream_iterator<std::string>{iss}, std::istream_iterator<std::string>{}};
|
return {std::istream_iterator<std::string>{iss}, std::istream_iterator<std::string>{}};
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 Qualified::getMultiQualifier(const std::string& qualifier1, uint32 pos)
|
int32 Qualified::getMultiQualifier(std::string const qualifier1, uint32 pos)
|
||||||
{
|
{
|
||||||
return std::stoi(getMultiQualifiers(qualifier1)[pos]);
|
return std::stoi(getMultiQualifiers(qualifier1)[pos]);
|
||||||
}
|
}
|
||||||
272
src/engine/NamedObjectContext.h
Normal file
272
src/engine/NamedObjectContext.h
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
|
||||||
|
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PLAYERBOT_NAMEDOBJECTCONEXT_H
|
||||||
|
#define _PLAYERBOT_NAMEDOBJECTCONEXT_H
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <set>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
class PlayerbotAI;
|
||||||
|
|
||||||
|
class Qualified
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Qualified(){};
|
||||||
|
Qualified(std::string const qualifier) : qualifier(qualifier) {}
|
||||||
|
Qualified(int32 qualifier1) { Qualify(qualifier1); }
|
||||||
|
|
||||||
|
virtual void Qualify(int qual);
|
||||||
|
|
||||||
|
virtual void Qualify(std::string const qual) { qualifier = qual; }
|
||||||
|
|
||||||
|
std::string const getQualifier() { return qualifier; }
|
||||||
|
|
||||||
|
static std::string const MultiQualify(std::vector<std::string> qualifiers, const std::string& separator, const std::string_view brackets = "{}");
|
||||||
|
static std::vector<std::string> getMultiQualifiers(std::string const qualifier1);
|
||||||
|
static int32 getMultiQualifier(std::string const qualifier1, uint32 pos);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string qualifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class NamedObjectFactory
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
typedef T* (*ActionCreator)(PlayerbotAI* botAI);
|
||||||
|
std::unordered_map<std::string, ActionCreator> creators;
|
||||||
|
|
||||||
|
public:
|
||||||
|
T* create(std::string name, PlayerbotAI* botAI)
|
||||||
|
{
|
||||||
|
size_t found = name.find("::");
|
||||||
|
std::string qualifier;
|
||||||
|
if (found != std::string::npos)
|
||||||
|
{
|
||||||
|
qualifier = name.substr(found + 2);
|
||||||
|
name = name.substr(0, found);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creators.find(name) == creators.end())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
ActionCreator creator = creators[name];
|
||||||
|
if (!creator)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
T* object = (*creator)(botAI);
|
||||||
|
Qualified* q = dynamic_cast<Qualified*>(object);
|
||||||
|
if (q && found != std::string::npos)
|
||||||
|
q->Qualify(qualifier);
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<std::string> supports()
|
||||||
|
{
|
||||||
|
std::set<std::string> keys;
|
||||||
|
for (typename std::unordered_map<std::string, ActionCreator>::iterator it = creators.begin();
|
||||||
|
it != creators.end(); it++)
|
||||||
|
keys.insert(it->first);
|
||||||
|
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class NamedObjectContext : public NamedObjectFactory<T>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NamedObjectContext(bool shared = false, bool supportsSiblings = false)
|
||||||
|
: NamedObjectFactory<T>(), shared(shared), supportsSiblings(supportsSiblings)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~NamedObjectContext() { Clear(); }
|
||||||
|
|
||||||
|
T* create(std::string const name, PlayerbotAI* botAI)
|
||||||
|
{
|
||||||
|
if (created.find(name) == created.end())
|
||||||
|
return created[name] = NamedObjectFactory<T>::create(name, botAI);
|
||||||
|
|
||||||
|
return created[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
for (typename std::unordered_map<std::string, T*>::iterator i = created.begin(); i != created.end(); i++)
|
||||||
|
{
|
||||||
|
if (i->second)
|
||||||
|
delete i->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
created.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update()
|
||||||
|
{
|
||||||
|
for (typename std::unordered_map<std::string, T*>::iterator i = created.begin(); i != created.end(); i++)
|
||||||
|
{
|
||||||
|
if (i->second)
|
||||||
|
i->second->Update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
for (typename std::unordered_map<std::string, T*>::iterator i = created.begin(); i != created.end(); i++)
|
||||||
|
{
|
||||||
|
if (i->second)
|
||||||
|
i->second->Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsShared() { return shared; }
|
||||||
|
bool IsSupportsSiblings() { return supportsSiblings; }
|
||||||
|
|
||||||
|
std::set<std::string> GetCreated()
|
||||||
|
{
|
||||||
|
std::set<std::string> keys;
|
||||||
|
for (typename std::unordered_map<std::string, T*>::iterator it = created.begin(); it != created.end(); it++)
|
||||||
|
keys.insert(it->first);
|
||||||
|
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::unordered_map<std::string, T*> created;
|
||||||
|
bool shared;
|
||||||
|
bool supportsSiblings;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class NamedObjectContextList
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~NamedObjectContextList()
|
||||||
|
{
|
||||||
|
for (typename std::vector<NamedObjectContext<T>*>::iterator i = contexts.begin(); i != contexts.end(); i++)
|
||||||
|
{
|
||||||
|
NamedObjectContext<T>* context = *i;
|
||||||
|
if (!context->IsShared())
|
||||||
|
delete context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Add(NamedObjectContext<T>* context) { contexts.push_back(context); }
|
||||||
|
|
||||||
|
T* GetContextObject(std::string const name, PlayerbotAI* botAI)
|
||||||
|
{
|
||||||
|
for (typename std::vector<NamedObjectContext<T>*>::iterator i = contexts.begin(); i != contexts.end(); i++)
|
||||||
|
{
|
||||||
|
if (T* object = (*i)->create(name, botAI))
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update()
|
||||||
|
{
|
||||||
|
for (typename std::vector<NamedObjectContext<T>*>::iterator i = contexts.begin(); i != contexts.end(); i++)
|
||||||
|
{
|
||||||
|
if (!(*i)->IsShared())
|
||||||
|
(*i)->Update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
for (typename std::vector<NamedObjectContext<T>*>::iterator i = contexts.begin(); i != contexts.end(); i++)
|
||||||
|
{
|
||||||
|
(*i)->Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<std::string> GetSiblings(std::string const name)
|
||||||
|
{
|
||||||
|
for (typename std::vector<NamedObjectContext<T>*>::iterator i = contexts.begin(); i != contexts.end(); i++)
|
||||||
|
{
|
||||||
|
if (!(*i)->IsSupportsSiblings())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::set<std::string> supported = (*i)->supports();
|
||||||
|
std::set<std::string>::iterator found = supported.find(name);
|
||||||
|
if (found == supported.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
supported.erase(found);
|
||||||
|
return supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::set<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<std::string> supports()
|
||||||
|
{
|
||||||
|
std::set<std::string> result;
|
||||||
|
for (typename std::vector<NamedObjectContext<T>*>::iterator i = contexts.begin(); i != contexts.end(); i++)
|
||||||
|
{
|
||||||
|
std::set<std::string> supported = (*i)->supports();
|
||||||
|
|
||||||
|
for (std::set<std::string>::iterator j = supported.begin(); j != supported.end(); j++)
|
||||||
|
result.insert(*j);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<std::string> GetCreated()
|
||||||
|
{
|
||||||
|
std::set<std::string> result;
|
||||||
|
for (typename std::vector<NamedObjectContext<T>*>::iterator i = contexts.begin(); i != contexts.end(); i++)
|
||||||
|
{
|
||||||
|
std::set<std::string> createdKeys = (*i)->GetCreated();
|
||||||
|
|
||||||
|
for (std::set<std::string>::iterator j = createdKeys.begin(); j != createdKeys.end(); j++)
|
||||||
|
result.insert(*j);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<NamedObjectContext<T>*> contexts;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class NamedObjectFactoryList
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~NamedObjectFactoryList()
|
||||||
|
{
|
||||||
|
for (typename std::list<NamedObjectFactory<T>*>::iterator i = factories.begin(); i != factories.end(); i++)
|
||||||
|
delete *i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Add(NamedObjectFactory<T>* context) { factories.push_front(context); }
|
||||||
|
|
||||||
|
T* GetContextObject(std::string const& name, PlayerbotAI* botAI)
|
||||||
|
{
|
||||||
|
for (typename std::list<NamedObjectFactory<T>*>::iterator i = factories.begin(); i != factories.end(); i++)
|
||||||
|
{
|
||||||
|
if (T* object = (*i)->create(name, botAI))
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::list<NamedObjectFactory<T>*> factories;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -41,7 +41,6 @@ enum StrategyType : uint32
|
|||||||
// };
|
// };
|
||||||
|
|
||||||
static float ACTION_IDLE = 0.0f;
|
static float ACTION_IDLE = 0.0f;
|
||||||
static float ACTION_BG = 1.0f;
|
|
||||||
static float ACTION_DEFAULT = 5.0f;
|
static float ACTION_DEFAULT = 5.0f;
|
||||||
static float ACTION_NORMAL = 10.0f;
|
static float ACTION_NORMAL = 10.0f;
|
||||||
static float ACTION_HIGH = 20.0f;
|
static float ACTION_HIGH = 20.0f;
|
||||||
@@ -69,7 +68,7 @@ public:
|
|||||||
void Update() {}
|
void Update() {}
|
||||||
void Reset() {}
|
void Reset() {}
|
||||||
|
|
||||||
public:
|
protected:
|
||||||
NamedObjectFactoryList<ActionNode> actionNodeFactories;
|
NamedObjectFactoryList<ActionNode> actionNodeFactories;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -32,11 +32,12 @@ Value<Unit*>* Trigger::GetTargetValue() { return context->GetValue<Unit*>(GetTar
|
|||||||
|
|
||||||
Unit* Trigger::GetTarget() { return GetTargetValue()->Get(); }
|
Unit* Trigger::GetTarget() { return GetTargetValue()->Get(); }
|
||||||
|
|
||||||
bool Trigger::needCheck(uint32 now)
|
bool Trigger::needCheck()
|
||||||
{
|
{
|
||||||
if (checkInterval < 2)
|
if (checkInterval < 2)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
uint32 now = getMSTime();
|
||||||
if (!lastCheckTime || now - lastCheckTime >= checkInterval)
|
if (!lastCheckTime || now - lastCheckTime >= checkInterval)
|
||||||
{
|
{
|
||||||
lastCheckTime = now;
|
lastCheckTime = now;
|
||||||
@@ -30,7 +30,7 @@ public:
|
|||||||
virtual Value<Unit*>* GetTargetValue();
|
virtual Value<Unit*>* GetTargetValue();
|
||||||
virtual std::string const GetTargetName() { return "self target"; }
|
virtual std::string const GetTargetName() { return "self target"; }
|
||||||
|
|
||||||
bool needCheck(uint32 now);
|
bool needCheck();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int32 checkInterval;
|
int32 checkInterval;
|
||||||
@@ -80,16 +80,13 @@ uint8 AiFactory::GetPlayerSpecTab(Player* bot)
|
|||||||
switch (bot->getClass())
|
switch (bot->getClass())
|
||||||
{
|
{
|
||||||
case CLASS_MAGE:
|
case CLASS_MAGE:
|
||||||
tab = MAGE_TAB_FROST;
|
tab = 1;
|
||||||
break;
|
break;
|
||||||
case CLASS_PALADIN:
|
case CLASS_PALADIN:
|
||||||
tab = PALADIN_TAB_RETRIBUTION;
|
tab = 2;
|
||||||
break;
|
break;
|
||||||
case CLASS_PRIEST:
|
case CLASS_PRIEST:
|
||||||
tab = PRIEST_TAB_HOLY;
|
tab = 1;
|
||||||
break;
|
|
||||||
case CLASS_WARLOCK:
|
|
||||||
tab = WARLOCK_TAB_DEMONOLOGY;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,22 +302,22 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
break;
|
break;
|
||||||
case CLASS_MAGE:
|
case CLASS_MAGE:
|
||||||
if (tab == 0)
|
if (tab == 0)
|
||||||
engine->addStrategiesNoInit("arcane", nullptr);
|
engine->addStrategiesNoInit("arcane", "arcane aoe", nullptr);
|
||||||
else if (tab == 1)
|
else if (tab == 1)
|
||||||
{
|
{
|
||||||
if (player->HasSpell(44614) /*Frostfire Bolt*/ && player->HasAura(15047) /*Ice Shards*/)
|
if (player->HasSpell(44614) /*Frostfire Bolt*/ && player->HasAura(15047) /*Ice Shards*/)
|
||||||
{
|
{
|
||||||
engine->addStrategiesNoInit("frostfire", nullptr);
|
engine->addStrategiesNoInit("frostfire", "frostfire aoe", nullptr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
engine->addStrategiesNoInit("fire", nullptr);
|
engine->addStrategiesNoInit("fire", "fire aoe", nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
engine->addStrategiesNoInit("frost", nullptr);
|
engine->addStrategiesNoInit("frost", "frost aoe", nullptr);
|
||||||
|
|
||||||
engine->addStrategiesNoInit("dps", "dps assist", "cure", "aoe", nullptr);
|
engine->addStrategiesNoInit("dps", "dps assist", "cure", nullptr);
|
||||||
break;
|
break;
|
||||||
case CLASS_WARRIOR:
|
case CLASS_WARRIOR:
|
||||||
if (tab == 2)
|
if (tab == 2)
|
||||||
@@ -370,14 +367,12 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CLASS_HUNTER:
|
case CLASS_HUNTER:
|
||||||
if (tab == 0) // Beast Mastery
|
engine->addStrategiesNoInit("dps", "aoe", "bdps", "dps assist", nullptr);
|
||||||
engine->addStrategiesNoInit("bm", nullptr);
|
engine->addStrategy("dps debuff", false);
|
||||||
else if (tab == 1) // Marksmanship
|
// if (tab == HUNTER_TAB_SURVIVAL)
|
||||||
engine->addStrategiesNoInit("mm", nullptr);
|
// {
|
||||||
else if (tab == 2) // Survival
|
// engine->addStrategy("trap weave", false);
|
||||||
engine->addStrategiesNoInit("surv", nullptr);
|
// }
|
||||||
|
|
||||||
engine->addStrategiesNoInit("cc", "dps assist", "aoe", nullptr);
|
|
||||||
break;
|
break;
|
||||||
case CLASS_ROGUE:
|
case CLASS_ROGUE:
|
||||||
if (tab == ROGUE_TAB_ASSASSINATION || tab == ROGUE_TAB_SUBTLETY)
|
if (tab == ROGUE_TAB_ASSASSINATION || tab == ROGUE_TAB_SUBTLETY)
|
||||||
@@ -390,16 +385,8 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CLASS_WARLOCK:
|
case CLASS_WARLOCK:
|
||||||
if (tab == 0) // Affliction
|
engine->addStrategiesNoInit("dps assist", "dps", "dps debuff", "aoe", nullptr);
|
||||||
engine->addStrategiesNoInit("affli", "curse of agony", nullptr);
|
|
||||||
else if (tab == 1) // Demonology
|
|
||||||
engine->addStrategiesNoInit("demo", "curse of agony", "meta melee", nullptr);
|
|
||||||
else if (tab == 2) // Destruction
|
|
||||||
engine->addStrategiesNoInit("destro", "curse of elements", nullptr);
|
|
||||||
|
|
||||||
engine->addStrategiesNoInit("cc", "dps assist", "aoe", nullptr);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CLASS_DEATH_KNIGHT:
|
case CLASS_DEATH_KNIGHT:
|
||||||
if (tab == 0)
|
if (tab == 0)
|
||||||
engine->addStrategiesNoInit("blood", "tank assist", nullptr);
|
engine->addStrategiesNoInit("blood", "tank assist", nullptr);
|
||||||
@@ -420,7 +407,6 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
{
|
{
|
||||||
if (sPlayerbotAIConfig->autoSaveMana)
|
if (sPlayerbotAIConfig->autoSaveMana)
|
||||||
engine->addStrategy("save mana", false);
|
engine->addStrategy("save mana", false);
|
||||||
if (!sPlayerbotAIConfig->IsRestrictedHealerDPSMap(player->GetMapId()))
|
|
||||||
engine->addStrategy("healer dps", false);
|
engine->addStrategy("healer dps", false);
|
||||||
}
|
}
|
||||||
if (facade->IsRealPlayer() || sRandomPlayerbotMgr->IsRandomBot(player))
|
if (facade->IsRealPlayer() || sRandomPlayerbotMgr->IsRandomBot(player))
|
||||||
@@ -472,10 +458,6 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sRandomPlayerbotMgr->IsRandomBot(player))
|
|
||||||
{
|
|
||||||
engine->ChangeStrategy(sPlayerbotAIConfig->randomBotCombatStrategies);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
engine->ChangeStrategy(sPlayerbotAIConfig->combatStrategies);
|
engine->ChangeStrategy(sPlayerbotAIConfig->combatStrategies);
|
||||||
@@ -549,7 +531,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
|||||||
nonCombatEngine->addStrategiesNoInit("bthreat", "tank assist", "barmor", nullptr);
|
nonCombatEngine->addStrategiesNoInit("bthreat", "tank assist", "barmor", nullptr);
|
||||||
if (player->GetLevel() >= 20)
|
if (player->GetLevel() >= 20)
|
||||||
{
|
{
|
||||||
nonCombatEngine->addStrategy("bhealth", false);
|
nonCombatEngine->addStrategy("bstats", false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -606,17 +588,17 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
|||||||
case CLASS_WARLOCK:
|
case CLASS_WARLOCK:
|
||||||
if (tab == WARLOCK_TAB_AFFLICATION)
|
if (tab == WARLOCK_TAB_AFFLICATION)
|
||||||
{
|
{
|
||||||
nonCombatEngine->addStrategiesNoInit("felhunter", "spellstone", nullptr);
|
nonCombatEngine->addStrategiesNoInit("bmana", nullptr);
|
||||||
}
|
}
|
||||||
else if (tab == WARLOCK_TAB_DEMONOLOGY)
|
else if (tab == WARLOCK_TAB_DEMONOLOGY)
|
||||||
{
|
{
|
||||||
nonCombatEngine->addStrategiesNoInit("felguard", "spellstone", nullptr);
|
nonCombatEngine->addStrategiesNoInit("bdps", nullptr);
|
||||||
}
|
}
|
||||||
else if (tab == WARLOCK_TAB_DESTRUCTION)
|
else if (tab == WARLOCK_TAB_DESTRUCTION)
|
||||||
{
|
{
|
||||||
nonCombatEngine->addStrategiesNoInit("imp", "firestone", nullptr);
|
nonCombatEngine->addStrategiesNoInit("bhealth", nullptr);
|
||||||
}
|
}
|
||||||
nonCombatEngine->addStrategiesNoInit("dps assist", "ss self", nullptr);
|
nonCombatEngine->addStrategiesNoInit("dps assist", nullptr);
|
||||||
break;
|
break;
|
||||||
case CLASS_DEATH_KNIGHT:
|
case CLASS_DEATH_KNIGHT:
|
||||||
if (tab == 0)
|
if (tab == 0)
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -45,6 +45,63 @@ enum spec : uint8
|
|||||||
ROLE_CDPS = 3
|
ROLE_CDPS = 3
|
||||||
};*/
|
};*/
|
||||||
|
|
||||||
|
enum PriorizedConsumables
|
||||||
|
{
|
||||||
|
CONSUM_ID_ROUGH_WEIGHTSTONE = 3239,
|
||||||
|
CONSUM_ID_COARSE_WEIGHTSTONE = 3239,
|
||||||
|
CONSUM_ID_HEAVY_WEIGHTSTONE = 3241,
|
||||||
|
CONSUM_ID_SOLID_WEIGHTSTONE = 7965,
|
||||||
|
CONSUM_ID_DENSE_WEIGHTSTONE = 12643,
|
||||||
|
CONSUM_ID_FEL_WEIGHTSTONE = 28420,
|
||||||
|
CONSUM_ID_ADAMANTITE_WEIGHTSTONE = 28421,
|
||||||
|
CONSUM_ID_ROUGH_SHARPENING_STONE = 2862,
|
||||||
|
CONSUM_ID_COARSE_SHARPENING_STONE = 2863,
|
||||||
|
CONSUM_ID_HEAVY_SHARPENING_STONE = 2871,
|
||||||
|
CONSUM_ID_SOL_SHARPENING_STONE = 7964,
|
||||||
|
CONSUM_ID_DENSE_SHARPENING_STONE = 12404,
|
||||||
|
CONSUM_ID_ELEMENTAL_SHARPENING_STONE = 18262,
|
||||||
|
CONSUM_ID_CONSECRATED_SHARPENING_STONE = 23122,
|
||||||
|
CONSUM_ID_FEL_SHARPENING_STONE = 23528,
|
||||||
|
CONSUM_ID_ADAMANTITE_SHARPENING_STONE = 23529,
|
||||||
|
CONSUM_ID_LINEN_BANDAGE = 1251,
|
||||||
|
CONSUM_ID_HEAVY_LINEN_BANDAGE = 2581,
|
||||||
|
CONSUM_ID_WOOL_BANDAGE = 3530,
|
||||||
|
CONSUM_ID_HEAVY_WOOL_BANDAGE = 3531,
|
||||||
|
CONSUM_ID_SILK_BANDAGE = 6450,
|
||||||
|
CONSUM_ID_HEAVY_SILK_BANDAGE = 6451,
|
||||||
|
CONSUM_ID_MAGEWEAVE_BANDAGE = 8544,
|
||||||
|
CONSUM_ID_HEAVY_MAGEWEAVE_BANDAGE = 8545,
|
||||||
|
CONSUM_ID_RUNECLOTH_BANDAGE = 14529,
|
||||||
|
CONSUM_ID_HEAVY_RUNECLOTH_BANDAGE = 14530,
|
||||||
|
CONSUM_ID_NETHERWEAVE_BANDAGE = 21990,
|
||||||
|
CONSUM_ID_HEAVY_NETHERWEAVE_BANDAGE = 21991,
|
||||||
|
CONSUM_ID_BRILLIANT_MANA_OIL = 20748,
|
||||||
|
CONSUM_ID_MINOR_MANA_OIL = 20745,
|
||||||
|
CONSUM_ID_SUPERIOR_MANA_OIL = 22521,
|
||||||
|
CONSUM_ID_LESSER_MANA_OIL = 20747,
|
||||||
|
CONSUM_ID_BRILLIANT_WIZARD_OIL = 20749,
|
||||||
|
CONSUM_ID_MINOR_WIZARD_OIL = 20744,
|
||||||
|
CONSUM_ID_SUPERIOR_WIZARD_OIL = 22522,
|
||||||
|
CONSUM_ID_WIZARD_OIL = 20750,
|
||||||
|
CONSUM_ID_LESSER_WIZARD_OIL = 20746,
|
||||||
|
CONSUM_ID_INSTANT_POISON = 6947,
|
||||||
|
CONSUM_ID_INSTANT_POISON_II = 6949,
|
||||||
|
CONSUM_ID_INSTANT_POISON_III = 6950,
|
||||||
|
CONSUM_ID_INSTANT_POISON_IV = 8926,
|
||||||
|
CONSUM_ID_INSTANT_POISON_V = 8927,
|
||||||
|
CONSUM_ID_INSTANT_POISON_VI = 8928,
|
||||||
|
CONSUM_ID_INSTANT_POISON_VII = 21927,
|
||||||
|
CONSUM_ID_DEADLY_POISON = 2892,
|
||||||
|
CONSUM_ID_DEADLY_POISON_II = 2893,
|
||||||
|
CONSUM_ID_DEADLY_POISON_III = 8984,
|
||||||
|
CONSUM_ID_DEADLY_POISON_IV = 8985,
|
||||||
|
CONSUM_ID_DEADLY_POISON_V = 20844,
|
||||||
|
CONSUM_ID_DEADLY_POISON_VI = 22053,
|
||||||
|
CONSUM_ID_DEADLY_POISON_VII = 22054
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAX_CONSUM_ID 28
|
||||||
|
|
||||||
class PlayerbotFactory
|
class PlayerbotFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -71,10 +128,8 @@ public:
|
|||||||
void InitAmmo();
|
void InitAmmo();
|
||||||
static uint32 CalcMixedGearScore(uint32 gs, uint32 quality);
|
static uint32 CalcMixedGearScore(uint32 gs, uint32 quality);
|
||||||
void InitPetTalents();
|
void InitPetTalents();
|
||||||
void CleanupConsumables();
|
|
||||||
void InitReagents();
|
void InitReagents();
|
||||||
void InitConsumables();
|
|
||||||
void InitPotions();
|
|
||||||
void InitGlyphs(bool increment = false);
|
void InitGlyphs(bool increment = false);
|
||||||
void InitFood();
|
void InitFood();
|
||||||
void InitMounts();
|
void InitMounts();
|
||||||
@@ -85,6 +140,7 @@ public:
|
|||||||
void InitKeyring();
|
void InitKeyring();
|
||||||
void InitReputation();
|
void InitReputation();
|
||||||
void InitAttunementQuests();
|
void InitAttunementQuests();
|
||||||
|
void InitPotions();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Prepare();
|
void Prepare();
|
||||||
@@ -121,6 +177,7 @@ private:
|
|||||||
void InitGuild();
|
void InitGuild();
|
||||||
void InitArenaTeam();
|
void InitArenaTeam();
|
||||||
void InitImmersive();
|
void InitImmersive();
|
||||||
|
void AddConsumables();
|
||||||
static void AddPrevQuests(uint32 questId, std::list<uint32>& questIds);
|
static void AddPrevQuests(uint32 questId, std::list<uint32>& questIds);
|
||||||
void LoadEnchantContainer();
|
void LoadEnchantContainer();
|
||||||
void ApplyEnchantTemplate();
|
void ApplyEnchantTemplate();
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "DBCStores.h"
|
#include "DBCStores.h"
|
||||||
#include "ItemEnchantmentMgr.h"
|
|
||||||
#include "ItemTemplate.h"
|
#include "ItemTemplate.h"
|
||||||
#include "ObjectMgr.h"
|
#include "ObjectMgr.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
@@ -29,12 +28,12 @@ void StatsCollector::CollectItemStats(ItemTemplate const* proto)
|
|||||||
{
|
{
|
||||||
if (proto->IsRangedWeapon())
|
if (proto->IsRangedWeapon())
|
||||||
{
|
{
|
||||||
float val = (proto->Damage[0].DamageMin + proto->Damage[0].DamageMax) * 1000 / 2 / proto->Delay;
|
uint32 val = (proto->Damage[0].DamageMin + proto->Damage[0].DamageMax) * 1000 / 2 / proto->Delay;
|
||||||
stats[STATS_TYPE_RANGED_DPS] += val;
|
stats[STATS_TYPE_RANGED_DPS] += val;
|
||||||
}
|
}
|
||||||
else if (proto->IsWeapon())
|
else if (proto->IsWeapon())
|
||||||
{
|
{
|
||||||
float val = (proto->Damage[0].DamageMin + proto->Damage[0].DamageMax) * 1000 / 2 / proto->Delay;
|
uint32 val = (proto->Damage[0].DamageMin + proto->Damage[0].DamageMax) * 1000 / 2 / proto->Delay;
|
||||||
stats[STATS_TYPE_MELEE_DPS] += val;
|
stats[STATS_TYPE_MELEE_DPS] += val;
|
||||||
}
|
}
|
||||||
stats[STATS_TYPE_ARMOR] += proto->Armor;
|
stats[STATS_TYPE_ARMOR] += proto->Armor;
|
||||||
@@ -206,7 +205,7 @@ void StatsCollector::CollectSpellStats(uint32 spellId, float multiplier, int32 s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatsCollector::CollectEnchantStats(SpellItemEnchantmentEntry const* enchant, uint32 default_enchant_amount)
|
void StatsCollector::CollectEnchantStats(SpellItemEnchantmentEntry const* enchant)
|
||||||
{
|
{
|
||||||
for (int s = 0; s < MAX_SPELL_ITEM_ENCHANTMENT_EFFECTS; ++s)
|
for (int s = 0; s < MAX_SPELL_ITEM_ENCHANTMENT_EFFECTS; ++s)
|
||||||
{
|
{
|
||||||
@@ -232,10 +231,6 @@ void StatsCollector::CollectEnchantStats(SpellItemEnchantmentEntry const* enchan
|
|||||||
}
|
}
|
||||||
case ITEM_ENCHANTMENT_TYPE_STAT:
|
case ITEM_ENCHANTMENT_TYPE_STAT:
|
||||||
{
|
{
|
||||||
// for item random suffix
|
|
||||||
if (!enchant_amount)
|
|
||||||
enchant_amount = default_enchant_amount;
|
|
||||||
|
|
||||||
if (!enchant_amount)
|
if (!enchant_amount)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@@ -436,10 +431,10 @@ void StatsCollector::CollectByItemStatType(uint32 itemStatType, int32 val)
|
|||||||
switch (itemStatType)
|
switch (itemStatType)
|
||||||
{
|
{
|
||||||
case ITEM_MOD_MANA:
|
case ITEM_MOD_MANA:
|
||||||
stats[STATS_TYPE_MANA_REGENERATION] += (float)val / 10;
|
stats[STATS_TYPE_MANA_REGENERATION] += val / 10;
|
||||||
break;
|
break;
|
||||||
case ITEM_MOD_HEALTH:
|
case ITEM_MOD_HEALTH:
|
||||||
stats[STATS_TYPE_STAMINA] += (float)val / 15;
|
stats[STATS_TYPE_STAMINA] += val / 15;
|
||||||
break;
|
break;
|
||||||
case ITEM_MOD_AGILITY:
|
case ITEM_MOD_AGILITY:
|
||||||
stats[STATS_TYPE_AGILITY] += val;
|
stats[STATS_TYPE_AGILITY] += val;
|
||||||
@@ -747,11 +742,11 @@ void StatsCollector::HandleApplyAura(const SpellEffectInfo& effectInfo, float mu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float StatsCollector::AverageValue(const SpellEffectInfo& effectInfo)
|
int32 StatsCollector::AverageValue(const SpellEffectInfo& effectInfo)
|
||||||
{
|
{
|
||||||
// float basePointsPerLevel = effectInfo.RealPointsPerLevel; //not used, line marked for removal.
|
//float basePointsPerLevel = effectInfo.RealPointsPerLevel; //not used, line marked for removal.
|
||||||
float basePoints = effectInfo.BasePoints;
|
int32 basePoints = effectInfo.BasePoints;
|
||||||
int32 randomPoints = effectInfo.DieSides;
|
int32 randomPoints = int32(effectInfo.DieSides);
|
||||||
|
|
||||||
switch (randomPoints)
|
switch (randomPoints)
|
||||||
{
|
{
|
||||||
@@ -761,7 +756,7 @@ float StatsCollector::AverageValue(const SpellEffectInfo& effectInfo)
|
|||||||
basePoints += 1;
|
basePoints += 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
float randvalue = (1 + randomPoints) / 2.0f;
|
int32 randvalue = (1 + randomPoints) / 2;
|
||||||
basePoints += randvalue;
|
basePoints += randvalue;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,12 +66,12 @@ public:
|
|||||||
void Reset();
|
void Reset();
|
||||||
void CollectItemStats(ItemTemplate const* proto);
|
void CollectItemStats(ItemTemplate const* proto);
|
||||||
void CollectSpellStats(uint32 spellId, float multiplier = 1.0f, int32 spellCooldown = -1);
|
void CollectSpellStats(uint32 spellId, float multiplier = 1.0f, int32 spellCooldown = -1);
|
||||||
void CollectEnchantStats(SpellItemEnchantmentEntry const* enchant, uint32 default_enchant_amount = 0);
|
void CollectEnchantStats(SpellItemEnchantmentEntry const* enchant);
|
||||||
bool CanBeTriggeredByType(SpellInfo const* spellInfo, uint32 procFlags, bool strict = true);
|
bool CanBeTriggeredByType(SpellInfo const* spellInfo, uint32 procFlags, bool strict = true);
|
||||||
bool CheckSpellValidation(uint32 spellFamilyName, flag96 spelFalimyFlags, bool strict = true);
|
bool CheckSpellValidation(uint32 spellFamilyName, flag96 spelFalimyFlags, bool strict = true);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
float stats[STATS_TYPE_MAX];
|
int32 stats[STATS_TYPE_MAX];
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void CollectByItemStatType(uint32 itemStatType, int32 val);
|
void CollectByItemStatType(uint32 itemStatType, int32 val);
|
||||||
@@ -80,7 +80,7 @@ private:
|
|||||||
|
|
||||||
void HandleApplyAura(const SpellEffectInfo& effectInfo, float multiplier, bool canNextTrigger,
|
void HandleApplyAura(const SpellEffectInfo& effectInfo, float multiplier, bool canNextTrigger,
|
||||||
uint32 triggerCooldown);
|
uint32 triggerCooldown);
|
||||||
float AverageValue(const SpellEffectInfo& effectInfo);
|
int32 AverageValue(const SpellEffectInfo& effectInfo);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CollectorType type_;
|
CollectorType type_;
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
#include "AiFactory.h"
|
#include "AiFactory.h"
|
||||||
#include "DBCStores.h"
|
#include "DBCStores.h"
|
||||||
#include "ItemEnchantmentMgr.h"
|
|
||||||
#include "ItemTemplate.h"
|
#include "ItemTemplate.h"
|
||||||
#include "ObjectMgr.h"
|
#include "ObjectMgr.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
@@ -33,7 +32,6 @@ StatsWeightCalculator::StatsWeightCalculator(Player* player) : player_(player)
|
|||||||
else
|
else
|
||||||
type_ = CollectorType::RANGED;
|
type_ = CollectorType::RANGED;
|
||||||
cls = player->getClass();
|
cls = player->getClass();
|
||||||
lvl = player->GetLevel();
|
|
||||||
tab = AiFactory::GetPlayerSpecTab(player);
|
tab = AiFactory::GetPlayerSpecTab(player);
|
||||||
collector_ = std::make_unique<StatsCollector>(type_, cls);
|
collector_ = std::make_unique<StatsCollector>(type_, cls);
|
||||||
|
|
||||||
@@ -61,7 +59,7 @@ void StatsWeightCalculator::Reset()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float StatsWeightCalculator::CalculateItem(uint32 itemId, int32 randomPropertyIds)
|
float StatsWeightCalculator::CalculateItem(uint32 itemId)
|
||||||
{
|
{
|
||||||
ItemTemplate const* proto = &sObjectMgr->GetItemTemplateStore()->at(itemId);
|
ItemTemplate const* proto = &sObjectMgr->GetItemTemplateStore()->at(itemId);
|
||||||
|
|
||||||
@@ -72,9 +70,6 @@ float StatsWeightCalculator::CalculateItem(uint32 itemId, int32 randomPropertyId
|
|||||||
|
|
||||||
collector_->CollectItemStats(proto);
|
collector_->CollectItemStats(proto);
|
||||||
|
|
||||||
if (randomPropertyIds != 0)
|
|
||||||
CalculateRandomProperty(randomPropertyIds, itemId);
|
|
||||||
|
|
||||||
if (enable_overflow_penalty_)
|
if (enable_overflow_penalty_)
|
||||||
ApplyOverflowPenalty(player_);
|
ApplyOverflowPenalty(player_);
|
||||||
|
|
||||||
@@ -121,53 +116,6 @@ float StatsWeightCalculator::CalculateEnchant(uint32 enchantId)
|
|||||||
return weight_;
|
return weight_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatsWeightCalculator::CalculateRandomProperty(int32 randomPropertyId, uint32 itemId)
|
|
||||||
{
|
|
||||||
if (randomPropertyId > 0)
|
|
||||||
{
|
|
||||||
ItemRandomPropertiesEntry const* item_rand = sItemRandomPropertiesStore.LookupEntry(randomPropertyId);
|
|
||||||
if (!item_rand)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32 i = PROP_ENCHANTMENT_SLOT_0; i < MAX_ENCHANTMENT_SLOT; ++i)
|
|
||||||
{
|
|
||||||
uint32 enchantId = item_rand->Enchantment[i - PROP_ENCHANTMENT_SLOT_0];
|
|
||||||
SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId);
|
|
||||||
if (enchant)
|
|
||||||
collector_->CollectEnchantStats(enchant);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ItemRandomSuffixEntry const* item_rand = sItemRandomSuffixStore.LookupEntry(-randomPropertyId);
|
|
||||||
if (!item_rand)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32 i = PROP_ENCHANTMENT_SLOT_0; i < MAX_ENCHANTMENT_SLOT; ++i)
|
|
||||||
{
|
|
||||||
uint32 enchantId = item_rand->Enchantment[i - PROP_ENCHANTMENT_SLOT_0];
|
|
||||||
SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId);
|
|
||||||
uint32 enchant_amount = 0;
|
|
||||||
|
|
||||||
for (int k = 0; k < MAX_ITEM_ENCHANTMENT_EFFECTS; ++k)
|
|
||||||
{
|
|
||||||
if (item_rand->Enchantment[k] == enchantId)
|
|
||||||
{
|
|
||||||
enchant_amount = uint32((item_rand->AllocationPct[k] * GenerateEnchSuffixFactor(itemId)) / 10000);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enchant)
|
|
||||||
collector_->CollectEnchantStats(enchant, enchant_amount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatsWeightCalculator::GenerateWeights(Player* player)
|
void StatsWeightCalculator::GenerateWeights(Player* player)
|
||||||
{
|
{
|
||||||
GenerateBasicWeights(player);
|
GenerateBasicWeights(player);
|
||||||
@@ -182,7 +130,6 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
|
|||||||
stats_weights_[STATS_TYPE_ARMOR] += 0.001f;
|
stats_weights_[STATS_TYPE_ARMOR] += 0.001f;
|
||||||
stats_weights_[STATS_TYPE_BONUS] += 1.0f;
|
stats_weights_[STATS_TYPE_BONUS] += 1.0f;
|
||||||
stats_weights_[STATS_TYPE_MELEE_DPS] += 0.01f;
|
stats_weights_[STATS_TYPE_MELEE_DPS] += 0.01f;
|
||||||
stats_weights_[STATS_TYPE_RANGED_DPS] += 0.01f;
|
|
||||||
|
|
||||||
if (cls == CLASS_HUNTER && (tab == HUNTER_TAB_BEASTMASTER || tab == HUNTER_TAB_SURVIVAL))
|
if (cls == CLASS_HUNTER && (tab == HUNTER_TAB_BEASTMASTER || tab == HUNTER_TAB_SURVIVAL))
|
||||||
{
|
{
|
||||||
@@ -517,9 +464,9 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto)
|
|||||||
// {
|
// {
|
||||||
// weight_ *= 1.0;
|
// weight_ *= 1.0;
|
||||||
// }
|
// }
|
||||||
|
// double hand
|
||||||
if (proto->Class == ITEM_CLASS_WEAPON)
|
if (proto->Class == ITEM_CLASS_WEAPON)
|
||||||
{
|
{
|
||||||
// double hand
|
|
||||||
bool isDoubleHand = proto->Class == ITEM_CLASS_WEAPON &&
|
bool isDoubleHand = proto->Class == ITEM_CLASS_WEAPON &&
|
||||||
!(ITEM_SUBCLASS_MASK_SINGLE_HAND & (1 << proto->SubClass)) &&
|
!(ITEM_SUBCLASS_MASK_SINGLE_HAND & (1 << proto->SubClass)) &&
|
||||||
!(ITEM_SUBCLASS_MASK_WEAPON_RANGED & (1 << proto->SubClass));
|
!(ITEM_SUBCLASS_MASK_WEAPON_RANGED & (1 << proto->SubClass));
|
||||||
@@ -527,38 +474,30 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto)
|
|||||||
if (isDoubleHand)
|
if (isDoubleHand)
|
||||||
{
|
{
|
||||||
weight_ *= 0.5;
|
weight_ *= 0.5;
|
||||||
|
}
|
||||||
// spec without double hand
|
// spec without double hand
|
||||||
// enhancement, rogue, ice dk, unholy dk, shield tank, fury warrior without titan's grip but with duel wield
|
// enhancement, rogue, ice dk, unholy dk, shield tank, fury warrior without titan's grip but with duel wield
|
||||||
if (((cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ENHANCEMENT && player_->CanDualWield()) ||
|
if (isDoubleHand &&
|
||||||
|
((cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ENHANCEMENT && player_->CanDualWield()) ||
|
||||||
(cls == CLASS_ROGUE) || (cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_FROST) ||
|
(cls == CLASS_ROGUE) || (cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_FROST) ||
|
||||||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !player_->CanTitanGrip() &&
|
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !player_->CanTitanGrip() && player_->CanDualWield()) ||
|
||||||
player_->CanDualWield()) ||
|
|
||||||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_PROTECTION) ||
|
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_PROTECTION) ||
|
||||||
(cls == CLASS_PALADIN && tab == PALADIN_TAB_PROTECTION)))
|
(cls == CLASS_PALADIN && tab == PALADIN_TAB_PROTECTION)))
|
||||||
{
|
{
|
||||||
weight_ *= 0.1;
|
weight_ *= 0.1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// spec with double hand
|
// spec with double hand
|
||||||
// fury without duel wield, arms, bear, retribution, blood dk
|
// fury without duel wield, arms, bear, retribution, blood dk
|
||||||
if (!isDoubleHand)
|
if (!isDoubleHand &&
|
||||||
{
|
((cls == CLASS_HUNTER && !player_->CanDualWield()) ||
|
||||||
if ((cls == CLASS_HUNTER && !player_->CanDualWield()) ||
|
|
||||||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !player_->CanDualWield()) ||
|
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !player_->CanDualWield()) ||
|
||||||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_ARMS) || (cls == CLASS_DRUID && tab == DRUID_TAB_FERAL) ||
|
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_ARMS) || (cls == CLASS_DRUID && tab == DRUID_TAB_FERAL) ||
|
||||||
(cls == CLASS_PALADIN && tab == PALADIN_TAB_RETRIBUTION) ||
|
(cls == CLASS_PALADIN && tab == PALADIN_TAB_RETRIBUTION) ||
|
||||||
(cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_BLOOD) ||
|
(cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_BLOOD) ||
|
||||||
(cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ENHANCEMENT && !player_->CanDualWield()))
|
(cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ENHANCEMENT && !player_->CanDualWield())))
|
||||||
{
|
{
|
||||||
weight_ *= 0.1;
|
weight_ *= 0.1;
|
||||||
}
|
}
|
||||||
// caster's main hand (cannot duel weapon but can equip two-hands stuff)
|
|
||||||
if (cls == CLASS_MAGE || cls == CLASS_PRIEST || cls == CLASS_WARLOCK || cls == CLASS_DRUID ||
|
|
||||||
(cls == CLASS_SHAMAN && !player_->CanDualWield()))
|
|
||||||
{
|
|
||||||
weight_ *= 0.65;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// fury with titan's grip
|
// fury with titan's grip
|
||||||
if ((!isDoubleHand || proto->SubClass == ITEM_SUBCLASS_WEAPON_POLEARM ||
|
if ((!isDoubleHand || proto->SubClass == ITEM_SUBCLASS_WEAPON_POLEARM ||
|
||||||
proto->SubClass == ITEM_SUBCLASS_WEAPON_STAFF) &&
|
proto->SubClass == ITEM_SUBCLASS_WEAPON_STAFF) &&
|
||||||
@@ -566,18 +505,15 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto)
|
|||||||
{
|
{
|
||||||
weight_ *= 0.1;
|
weight_ *= 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cls == CLASS_HUNTER && proto->SubClass == ITEM_SUBCLASS_WEAPON_THROWN)
|
if (cls == CLASS_HUNTER && proto->SubClass == ITEM_SUBCLASS_WEAPON_THROWN)
|
||||||
{
|
{
|
||||||
weight_ *= 0.1;
|
weight_ *= 0.1;
|
||||||
}
|
}
|
||||||
|
if (cls == CLASS_ROGUE && (tab == ROGUE_TAB_ASSASSINATION || tab == ROGUE_TAB_SUBTLETY) &&
|
||||||
if (lvl >= 10 && cls == CLASS_ROGUE && (tab == ROGUE_TAB_ASSASSINATION || tab == ROGUE_TAB_SUBTLETY) &&
|
proto->SubClass != ITEM_SUBCLASS_WEAPON_DAGGER)
|
||||||
proto->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER)
|
|
||||||
{
|
{
|
||||||
weight_ *= 1.5;
|
weight_ *= 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cls == CLASS_ROGUE && player_->HasAura(13964) &&
|
if (cls == CLASS_ROGUE && player_->HasAura(13964) &&
|
||||||
(proto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD || proto->SubClass == ITEM_SUBCLASS_WEAPON_AXE))
|
(proto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD || proto->SubClass == ITEM_SUBCLASS_WEAPON_AXE))
|
||||||
{
|
{
|
||||||
@@ -623,8 +559,7 @@ void StatsWeightCalculator::ApplyOverflowPenalty(Player* player)
|
|||||||
if (hitOverflowType_ & CollectorType::SPELL)
|
if (hitOverflowType_ & CollectorType::SPELL)
|
||||||
{
|
{
|
||||||
hit_current = player->GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HIT_CHANCE);
|
hit_current = player->GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HIT_CHANCE);
|
||||||
hit_current +=
|
hit_current += player->GetTotalAuraModifier(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT); // suppression (18176)
|
||||||
player->GetTotalAuraModifier(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT); // suppression (18176)
|
|
||||||
hit_current += player->GetRatingBonusValue(CR_HIT_SPELL);
|
hit_current += player->GetRatingBonusValue(CR_HIT_SPELL);
|
||||||
|
|
||||||
if (cls == CLASS_PRIEST && tab == PRIEST_TAB_SHADOW && player->HasAura(15835)) // Shadow Focus
|
if (cls == CLASS_PRIEST && tab == PRIEST_TAB_SHADOW && player->HasAura(15835)) // Shadow Focus
|
||||||
@@ -658,7 +593,7 @@ void StatsWeightCalculator::ApplyOverflowPenalty(Player* player)
|
|||||||
else
|
else
|
||||||
validPoints = 0;
|
validPoints = 0;
|
||||||
}
|
}
|
||||||
collector_->stats[STATS_TYPE_HIT] = std::min(collector_->stats[STATS_TYPE_HIT], validPoints);
|
collector_->stats[STATS_TYPE_HIT] = std::min(collector_->stats[STATS_TYPE_HIT], (int)validPoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -675,7 +610,8 @@ void StatsWeightCalculator::ApplyOverflowPenalty(Player* player)
|
|||||||
else
|
else
|
||||||
validPoints = 0;
|
validPoints = 0;
|
||||||
|
|
||||||
collector_->stats[STATS_TYPE_EXPERTISE] = std::min(collector_->stats[STATS_TYPE_EXPERTISE], validPoints);
|
collector_->stats[STATS_TYPE_EXPERTISE] =
|
||||||
|
std::min(collector_->stats[STATS_TYPE_EXPERTISE], (int)validPoints);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -692,7 +628,7 @@ void StatsWeightCalculator::ApplyOverflowPenalty(Player* player)
|
|||||||
else
|
else
|
||||||
validPoints = 0;
|
validPoints = 0;
|
||||||
|
|
||||||
collector_->stats[STATS_TYPE_DEFENSE] = std::min(collector_->stats[STATS_TYPE_DEFENSE], validPoints);
|
collector_->stats[STATS_TYPE_DEFENSE] = std::min(collector_->stats[STATS_TYPE_DEFENSE], (int)validPoints);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -711,7 +647,7 @@ void StatsWeightCalculator::ApplyOverflowPenalty(Player* player)
|
|||||||
validPoints = 0;
|
validPoints = 0;
|
||||||
|
|
||||||
collector_->stats[STATS_TYPE_ARMOR_PENETRATION] =
|
collector_->stats[STATS_TYPE_ARMOR_PENETRATION] =
|
||||||
std::min(collector_->stats[STATS_TYPE_ARMOR_PENETRATION], validPoints);
|
std::min(collector_->stats[STATS_TYPE_ARMOR_PENETRATION], (int)validPoints);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -721,7 +657,7 @@ void StatsWeightCalculator::ApplyWeightFinetune(Player* player)
|
|||||||
{
|
{
|
||||||
if (type_ & (CollectorType::MELEE | CollectorType::RANGED))
|
if (type_ & (CollectorType::MELEE | CollectorType::RANGED))
|
||||||
{
|
{
|
||||||
float armor_penetration_current /*, armor_penetration_overflow*/; // not used, line marked for removal.
|
float armor_penetration_current/*, armor_penetration_overflow*/; //not used, line marked for removal.
|
||||||
armor_penetration_current = player->GetRatingBonusValue(CR_ARMOR_PENETRATION);
|
armor_penetration_current = player->GetRatingBonusValue(CR_ARMOR_PENETRATION);
|
||||||
if (armor_penetration_current > 50)
|
if (armor_penetration_current > 50)
|
||||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] *= 1.2f;
|
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] *= 1.2f;
|
||||||
|
|||||||
@@ -28,19 +28,18 @@ class StatsWeightCalculator
|
|||||||
public:
|
public:
|
||||||
StatsWeightCalculator(Player* player);
|
StatsWeightCalculator(Player* player);
|
||||||
void Reset();
|
void Reset();
|
||||||
float CalculateItem(uint32 itemId, int32 randomPropertyId = 0);
|
float CalculateItem(uint32 itemId);
|
||||||
float CalculateEnchant(uint32 enchantId);
|
float CalculateEnchant(uint32 enchantId);
|
||||||
|
|
||||||
void SetOverflowPenalty(bool apply) { enable_overflow_penalty_ = apply; }
|
void SetOverflowPenalty(bool apply) { enable_overflow_penalty_ = apply; }
|
||||||
void SetItemSetBonus(bool apply) { enable_item_set_bonus_ = apply; }
|
void SetItemSetBonus(bool apply) { enable_item_set_bonus_ = apply; }
|
||||||
void SetQualityBlend(bool apply) { enable_quality_blend_ = apply; }
|
void SetQualityBlend(bool apply) { enable_quality_blend_ = apply; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void GenerateWeights(Player* player);
|
void GenerateWeights(Player* player);
|
||||||
void GenerateBasicWeights(Player* player);
|
void GenerateBasicWeights(Player* player);
|
||||||
void GenerateAdditionalWeights(Player* player);
|
void GenerateAdditionalWeights(Player* player);
|
||||||
|
|
||||||
void CalculateRandomProperty(int32 randomPropertyId, uint32 itemId);
|
|
||||||
void CalculateItemSetMod(Player* player, ItemTemplate const* proto);
|
void CalculateItemSetMod(Player* player, ItemTemplate const* proto);
|
||||||
void CalculateSocketBonus(Player* player, ItemTemplate const* proto);
|
void CalculateSocketBonus(Player* player, ItemTemplate const* proto);
|
||||||
|
|
||||||
@@ -57,7 +56,6 @@ private:
|
|||||||
CollectorType hitOverflowType_;
|
CollectorType hitOverflowType_;
|
||||||
std::unique_ptr<StatsCollector> collector_;
|
std::unique_ptr<StatsCollector> collector_;
|
||||||
uint8 cls;
|
uint8 cls;
|
||||||
uint8 lvl;
|
|
||||||
int tab;
|
int tab;
|
||||||
bool enable_overflow_penalty_;
|
bool enable_overflow_penalty_;
|
||||||
bool enable_item_set_bonus_;
|
bool enable_item_set_bonus_;
|
||||||
|
|||||||
@@ -46,14 +46,6 @@ public:
|
|||||||
if (melee && botAI->IsRanged(bot))
|
if (melee && botAI->IsRanged(bot))
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
bool rangeddps = message.find("@rangeddps") == 0;
|
|
||||||
if (rangeddps && (!botAI->IsRanged(bot) || botAI->IsTank(bot) || botAI->IsHeal(bot)))
|
|
||||||
return "";
|
|
||||||
|
|
||||||
bool meleedps = message.find("@meleedps") == 0;
|
|
||||||
if (meleedps && (!botAI->IsMelee(bot) || botAI->IsTank(bot) || botAI->IsHeal(bot)))
|
|
||||||
return "";
|
|
||||||
|
|
||||||
if (tank || dps || heal || ranged || melee)
|
if (tank || dps || heal || ranged || melee)
|
||||||
return ChatFilter::Filter(message);
|
return ChatFilter::Filter(message);
|
||||||
|
|
||||||
@@ -254,41 +246,21 @@ public:
|
|||||||
|
|
||||||
if (message.find("@group") == 0)
|
if (message.find("@group") == 0)
|
||||||
{
|
{
|
||||||
size_t spacePos = message.find(" ");
|
std::string const pnum = message.substr(6, message.find(" "));
|
||||||
if (spacePos == std::string::npos)
|
uint32 from = atoi(pnum.c_str());
|
||||||
return message;
|
uint32 to = from;
|
||||||
|
if (pnum.find("-") != std::string::npos)
|
||||||
std::string pnum = message.substr(6, spacePos - 6);
|
|
||||||
std::string actualMessage = message.substr(spacePos + 1);
|
|
||||||
|
|
||||||
std::set<uint32> targets;
|
|
||||||
std::istringstream ss(pnum);
|
|
||||||
std::string token;
|
|
||||||
|
|
||||||
while (std::getline(ss, token, ','))
|
|
||||||
{
|
{
|
||||||
size_t dashPos = token.find("-");
|
from = atoi(pnum.substr(pnum.find("@") + 1, pnum.find("-")).c_str());
|
||||||
if (dashPos != std::string::npos)
|
to = atoi(pnum.substr(pnum.find("-") + 1, pnum.find(" ")).c_str());
|
||||||
{
|
|
||||||
uint32 from = atoi(token.substr(0, dashPos).c_str());
|
|
||||||
uint32 to = atoi(token.substr(dashPos + 1).c_str());
|
|
||||||
if (from > to) std::swap(from, to);
|
|
||||||
for (uint32 i = from; i <= to; ++i)
|
|
||||||
targets.insert(i);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uint32 index = atoi(token.c_str());
|
|
||||||
targets.insert(index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bot->GetGroup())
|
if (!bot->GetGroup())
|
||||||
return message;
|
return message;
|
||||||
|
|
||||||
uint32 sg = bot->GetSubGroup() + 1;
|
uint32 sg = bot->GetSubGroup() + 1;
|
||||||
if (targets.find(sg) != targets.end())
|
if (sg >= from && sg <= to)
|
||||||
return ChatFilter::Filter(actualMessage);
|
return ChatFilter::Filter(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
@@ -305,49 +305,6 @@ ItemIds ChatHelper::parseItems(std::string const text)
|
|||||||
return itemIds;
|
return itemIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemWithRandomProperty ChatHelper::parseItemWithRandomProperty(std::string const text)
|
|
||||||
{
|
|
||||||
ItemWithRandomProperty res;
|
|
||||||
|
|
||||||
size_t itemStart = text.find("Hitem:");
|
|
||||||
if (itemStart == std::string::npos)
|
|
||||||
return res;
|
|
||||||
|
|
||||||
itemStart += 6;
|
|
||||||
if (itemStart >= text.length())
|
|
||||||
return res;
|
|
||||||
|
|
||||||
size_t colonPos = text.find(':', itemStart);
|
|
||||||
if (colonPos == std::string::npos)
|
|
||||||
return res;
|
|
||||||
|
|
||||||
std::string itemIdStr = text.substr(itemStart, colonPos - itemStart);
|
|
||||||
res.itemId = atoi(itemIdStr.c_str());
|
|
||||||
|
|
||||||
std::vector<std::string> params;
|
|
||||||
size_t currentPos = colonPos + 1;
|
|
||||||
|
|
||||||
while (currentPos < text.length()) {
|
|
||||||
size_t nextColon = text.find(':', currentPos);
|
|
||||||
if (nextColon == std::string::npos) {
|
|
||||||
size_t hTag = text.find("|h", currentPos);
|
|
||||||
if (hTag != std::string::npos) {
|
|
||||||
params.push_back(text.substr(currentPos, hTag - currentPos));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
params.push_back(text.substr(currentPos, nextColon - currentPos));
|
|
||||||
currentPos = nextColon + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.size() >= 6) {
|
|
||||||
res.randomPropertyId = atoi(params[5].c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string const ChatHelper::FormatQuest(Quest const* quest)
|
std::string const ChatHelper::FormatQuest(Quest const* quest)
|
||||||
{
|
{
|
||||||
if (!quest)
|
if (!quest)
|
||||||
@@ -425,7 +382,7 @@ std::string const ChatHelper::FormatSpell(SpellInfo const* spellInfo)
|
|||||||
std::string const ChatHelper::FormatItem(ItemTemplate const* proto, uint32 count, uint32 total)
|
std::string const ChatHelper::FormatItem(ItemTemplate const* proto, uint32 count, uint32 total)
|
||||||
{
|
{
|
||||||
char color[32];
|
char color[32];
|
||||||
snprintf(color, sizeof(color), "%x", ItemQualityColors[proto->Quality]);
|
sprintf(color, "%x", ItemQualityColors[proto->Quality]);
|
||||||
|
|
||||||
std::string itemName;
|
std::string itemName;
|
||||||
const ItemLocale* locale = sObjectMgr->GetItemLocale(proto->ItemId);
|
const ItemLocale* locale = sObjectMgr->GetItemLocale(proto->ItemId);
|
||||||
@@ -452,7 +409,7 @@ std::string const ChatHelper::FormatItem(ItemTemplate const* proto, uint32 count
|
|||||||
std::string const ChatHelper::FormatQItem(uint32 itemId)
|
std::string const ChatHelper::FormatQItem(uint32 itemId)
|
||||||
{
|
{
|
||||||
char color[32];
|
char color[32];
|
||||||
snprintf(color, sizeof(color), "%x", ItemQualityColors[0]);
|
sprintf(color, "%x", ItemQualityColors[0]);
|
||||||
|
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << "|c" << color << "|Hitem:" << itemId << ":0:0:0:0:0:0:0"
|
out << "|c" << color << "|Hitem:" << itemId << ":0:0:0:0:0:0:0"
|
||||||
@@ -25,11 +25,6 @@ struct ItemTemplate;
|
|||||||
typedef std::set<uint32> ItemIds;
|
typedef std::set<uint32> ItemIds;
|
||||||
typedef std::set<uint32> SpellIds;
|
typedef std::set<uint32> SpellIds;
|
||||||
|
|
||||||
struct ItemWithRandomProperty {
|
|
||||||
uint32 itemId{0};
|
|
||||||
int32 randomPropertyId{0};
|
|
||||||
};
|
|
||||||
|
|
||||||
class ChatHelper : public PlayerbotAIAware
|
class ChatHelper : public PlayerbotAIAware
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -38,7 +33,6 @@ public:
|
|||||||
static std::string const formatMoney(uint32 copper);
|
static std::string const formatMoney(uint32 copper);
|
||||||
static uint32 parseMoney(std::string const text);
|
static uint32 parseMoney(std::string const text);
|
||||||
static ItemIds parseItems(std::string const text);
|
static ItemIds parseItems(std::string const text);
|
||||||
static ItemWithRandomProperty parseItemWithRandomProperty(std::string const text);
|
|
||||||
uint32 parseSpell(std::string const text);
|
uint32 parseSpell(std::string const text);
|
||||||
static std::string parseValue(const std::string& type, const std::string& text);
|
static std::string parseValue(const std::string& type, const std::string& text);
|
||||||
|
|
||||||
@@ -525,11 +525,6 @@ uint32 GuildTaskMgr::GetMaxItemTaskCount(uint32 itemId)
|
|||||||
|
|
||||||
bool GuildTaskMgr::IsGuildTaskItem(uint32 itemId, uint32 guildId)
|
bool GuildTaskMgr::IsGuildTaskItem(uint32 itemId, uint32 guildId)
|
||||||
{
|
{
|
||||||
if (!sPlayerbotAIConfig->guildTaskEnabled)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 value = 0;
|
uint32 value = 0;
|
||||||
|
|
||||||
PlayerbotsDatabasePreparedStatement* stmt =
|
PlayerbotsDatabasePreparedStatement* stmt =
|
||||||
@@ -553,11 +548,6 @@ bool GuildTaskMgr::IsGuildTaskItem(uint32 itemId, uint32 guildId)
|
|||||||
std::map<uint32, uint32> GuildTaskMgr::GetTaskValues(uint32 owner, std::string const type,
|
std::map<uint32, uint32> GuildTaskMgr::GetTaskValues(uint32 owner, std::string const type,
|
||||||
[[maybe_unused]] uint32* validIn /* = nullptr */)
|
[[maybe_unused]] uint32* validIn /* = nullptr */)
|
||||||
{
|
{
|
||||||
if (!sPlayerbotAIConfig->guildTaskEnabled)
|
|
||||||
{
|
|
||||||
return std::map<uint32, uint32>();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<uint32, uint32> results;
|
std::map<uint32, uint32> results;
|
||||||
|
|
||||||
PlayerbotsDatabasePreparedStatement* stmt =
|
PlayerbotsDatabasePreparedStatement* stmt =
|
||||||
@@ -586,11 +576,6 @@ std::map<uint32, uint32> GuildTaskMgr::GetTaskValues(uint32 owner, std::string c
|
|||||||
|
|
||||||
uint32 GuildTaskMgr::GetTaskValue(uint32 owner, uint32 guildId, std::string const type, [[maybe_unused]] uint32* validIn /* = nullptr */)
|
uint32 GuildTaskMgr::GetTaskValue(uint32 owner, uint32 guildId, std::string const type, [[maybe_unused]] uint32* validIn /* = nullptr */)
|
||||||
{
|
{
|
||||||
if (!sPlayerbotAIConfig->guildTaskEnabled)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 value = 0;
|
uint32 value = 0;
|
||||||
|
|
||||||
PlayerbotsDatabasePreparedStatement* stmt =
|
PlayerbotsDatabasePreparedStatement* stmt =
|
||||||
@@ -232,20 +232,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CollectItemsVisitor : public IterateItemsVisitor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CollectItemsVisitor() : IterateItemsVisitor() {}
|
|
||||||
|
|
||||||
std::vector<Item*> items;
|
|
||||||
|
|
||||||
bool Visit(Item* item) override
|
|
||||||
{
|
|
||||||
items.push_back(item);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ItemCountByQuality : public IterateItemsVisitor
|
class ItemCountByQuality : public IterateItemsVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -6,8 +6,6 @@
|
|||||||
#include "LootObjectStack.h"
|
#include "LootObjectStack.h"
|
||||||
|
|
||||||
#include "LootMgr.h"
|
#include "LootMgr.h"
|
||||||
#include "Object.h"
|
|
||||||
#include "ObjectAccessor.h"
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "Unit.h"
|
#include "Unit.h"
|
||||||
|
|
||||||
@@ -87,7 +85,7 @@ void LootObject::Refresh(Player* bot, ObjectGuid lootGUID)
|
|||||||
bool hasAnyQuestItems = false;
|
bool hasAnyQuestItems = false;
|
||||||
|
|
||||||
GameObjectQuestItemList const* items = sObjectMgr->GetGameObjectQuestItemList(go->GetEntry());
|
GameObjectQuestItemList const* items = sObjectMgr->GetGameObjectQuestItemList(go->GetEntry());
|
||||||
for (size_t i = 0; i < MAX_GAMEOBJECT_QUEST_ITEMS; i++)
|
for (int i = 0; i < MAX_GAMEOBJECT_QUEST_ITEMS; i++)
|
||||||
{
|
{
|
||||||
if (!items || i >= items->size())
|
if (!items || i >= items->size())
|
||||||
break;
|
break;
|
||||||
@@ -289,7 +287,7 @@ bool LootObject::IsLootPossible(Player* bot)
|
|||||||
if (reqItem && !bot->HasItemCount(reqItem, 1))
|
if (reqItem && !bot->HasItemCount(reqItem, 1))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (abs(worldObj->GetPositionZ() - bot->GetPositionZ()) > INTERACTION_DISTANCE - 2.0f)
|
if (abs(worldObj->GetPositionZ() - bot->GetPositionZ()) > INTERACTION_DISTANCE -2.0f)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Creature* creature = botAI->GetCreature(guid);
|
Creature* creature = botAI->GetCreature(guid);
|
||||||
@@ -299,12 +297,6 @@ bool LootObject::IsLootPossible(Player* bot)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent bot from running to chests that are unlootable (e.g. Gunship Armory before completing the event) or on
|
|
||||||
// respawn time
|
|
||||||
GameObject* go = botAI->GetGameObject(guid);
|
|
||||||
if (go && (go->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND | GO_FLAG_NOT_SELECTABLE) || !go->isSpawned()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (skillId == SKILL_NONE)
|
if (skillId == SKILL_NONE)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -321,16 +313,28 @@ bool LootObject::IsLootPossible(Player* bot)
|
|||||||
if (reqSkillValue > skillValue)
|
if (reqSkillValue > skillValue)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (skillId == SKILL_MINING && !bot->HasItemCount(756, 1) && !bot->HasItemCount(778, 1) &&
|
if (skillId == SKILL_MINING &&
|
||||||
!bot->HasItemCount(1819, 1) && !bot->HasItemCount(1893, 1) && !bot->HasItemCount(1959, 1) &&
|
!bot->HasItemCount(756, 1) &&
|
||||||
!bot->HasItemCount(2901, 1) && !bot->HasItemCount(9465, 1) && !bot->HasItemCount(20723, 1) &&
|
!bot->HasItemCount(778, 1) &&
|
||||||
!bot->HasItemCount(40772, 1) && !bot->HasItemCount(40892, 1) && !bot->HasItemCount(40893, 1))
|
!bot->HasItemCount(1819, 1) &&
|
||||||
|
!bot->HasItemCount(1893, 1) &&
|
||||||
|
!bot->HasItemCount(1959, 1) &&
|
||||||
|
!bot->HasItemCount(2901, 1) &&
|
||||||
|
!bot->HasItemCount(9465, 1) &&
|
||||||
|
!bot->HasItemCount(20723, 1) &&
|
||||||
|
!bot->HasItemCount(40772, 1) &&
|
||||||
|
!bot->HasItemCount(40892, 1) &&
|
||||||
|
!bot->HasItemCount(40893, 1))
|
||||||
{
|
{
|
||||||
return false; // Bot is missing a mining pick
|
return false; // Bot is missing a mining pick
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skillId == SKILL_SKINNING && !bot->HasItemCount(7005, 1) && !bot->HasItemCount(40772, 1) &&
|
if (skillId == SKILL_SKINNING &&
|
||||||
!bot->HasItemCount(40893, 1) && !bot->HasItemCount(12709, 1) && !bot->HasItemCount(19901, 1))
|
!bot->HasItemCount(7005, 1) &&
|
||||||
|
!bot->HasItemCount(40772, 1) &&
|
||||||
|
!bot->HasItemCount(40893, 1) &&
|
||||||
|
!bot->HasItemCount(12709, 1) &&
|
||||||
|
!bot->HasItemCount(19901, 1))
|
||||||
{
|
{
|
||||||
return false; // Bot is missing a skinning knife
|
return false; // Bot is missing a skinning knife
|
||||||
}
|
}
|
||||||
@@ -367,45 +371,42 @@ void LootObjectStack::Clear() { availableLoot.clear(); }
|
|||||||
|
|
||||||
bool LootObjectStack::CanLoot(float maxDistance)
|
bool LootObjectStack::CanLoot(float maxDistance)
|
||||||
{
|
{
|
||||||
LootObject nearest = GetNearest(maxDistance);
|
std::vector<LootObject> ordered = OrderByDistance(maxDistance);
|
||||||
return !nearest.IsEmpty();
|
return !ordered.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
LootObject LootObjectStack::GetLoot(float maxDistance)
|
LootObject LootObjectStack::GetLoot(float maxDistance)
|
||||||
{
|
{
|
||||||
LootObject nearest = GetNearest(maxDistance);
|
std::vector<LootObject> ordered = OrderByDistance(maxDistance);
|
||||||
return nearest.IsEmpty() ? LootObject() : nearest;
|
return ordered.empty() ? LootObject() : *ordered.begin();
|
||||||
}
|
}
|
||||||
|
std::vector<LootObject> LootObjectStack::OrderByDistance(float maxDistance)
|
||||||
LootObject LootObjectStack::GetNearest(float maxDistance)
|
|
||||||
{
|
{
|
||||||
availableLoot.shrink(time(nullptr) - 30);
|
availableLoot.shrink(time(nullptr) - 30);
|
||||||
|
|
||||||
LootObject nearest;
|
std::map<float, LootObject> sortedMap;
|
||||||
float nearestDistance = std::numeric_limits<float>::max();
|
|
||||||
|
|
||||||
LootTargetList safeCopy(availableLoot);
|
LootTargetList safeCopy(availableLoot);
|
||||||
for (LootTargetList::iterator i = safeCopy.begin(); i != safeCopy.end(); i++)
|
for (LootTargetList::iterator i = safeCopy.begin(); i != safeCopy.end(); i++)
|
||||||
{
|
{
|
||||||
ObjectGuid guid = i->guid;
|
ObjectGuid guid = i->guid;
|
||||||
|
|
||||||
WorldObject* worldObj = ObjectAccessor::GetWorldObject(*bot, guid);
|
|
||||||
if (!worldObj)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
float distance = bot->GetDistance(worldObj);
|
|
||||||
|
|
||||||
if (distance >= nearestDistance || (maxDistance && distance > maxDistance))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
LootObject lootObject(bot, guid);
|
LootObject lootObject(bot, guid);
|
||||||
|
if (!lootObject.IsLootPossible(bot)) // Ensure loot object is valid
|
||||||
if (!lootObject.IsLootPossible(bot))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
nearestDistance = distance;
|
WorldObject* worldObj = lootObject.GetWorldObject(bot);
|
||||||
nearest = lootObject;
|
if (!worldObj) // Prevent null pointer dereference
|
||||||
|
{
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nearest;
|
float distance = bot->GetDistance(worldObj);
|
||||||
|
if (!maxDistance || distance <= maxDistance)
|
||||||
|
sortedMap[distance] = lootObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<LootObject> result;
|
||||||
|
for (auto& [_, lootObject] : sortedMap)
|
||||||
|
result.push_back(lootObject);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,6 @@ public:
|
|||||||
LootObject() : skillId(0), reqSkillValue(0), reqItem(0) {}
|
LootObject() : skillId(0), reqSkillValue(0), reqItem(0) {}
|
||||||
LootObject(Player* bot, ObjectGuid guid);
|
LootObject(Player* bot, ObjectGuid guid);
|
||||||
LootObject(LootObject const& other);
|
LootObject(LootObject const& other);
|
||||||
LootObject& operator=(LootObject const& other) = default;
|
|
||||||
|
|
||||||
bool IsEmpty() { return !guid; }
|
bool IsEmpty() { return !guid; }
|
||||||
bool IsLootPossible(Player* bot);
|
bool IsLootPossible(Player* bot);
|
||||||
@@ -78,7 +77,7 @@ public:
|
|||||||
LootObject GetLoot(float maxDistance = 0);
|
LootObject GetLoot(float maxDistance = 0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LootObject GetNearest(float maxDistance = 0);
|
std::vector<LootObject> OrderByDistance(float maxDistance = 0);
|
||||||
|
|
||||||
Player* bot;
|
Player* bot;
|
||||||
LootTargetList availableLoot;
|
LootTargetList availableLoot;
|
||||||
@@ -3336,7 +3336,7 @@ void TravelMgr::LoadQuestTravelTable()
|
|||||||
uint32 accountId = fields[0].Get<uint32>();
|
uint32 accountId = fields[0].Get<uint32>();
|
||||||
|
|
||||||
WorldSession* session =
|
WorldSession* session =
|
||||||
new WorldSession(accountId, "", 0x0, nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING, time_t(0),
|
new WorldSession(accountId, "", nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING, time_t(0),
|
||||||
LOCALE_enUS, 0, false, false, 0, true);
|
LOCALE_enUS, 0, false, false, 0, true);
|
||||||
|
|
||||||
std::vector<std::pair<std::pair<uint32, uint32>, uint32>> classSpecLevel;
|
std::vector<std::pair<std::pair<uint32, uint32>, uint32>> classSpecLevel;
|
||||||
@@ -8,89 +8,39 @@
|
|||||||
#include "ActionContext.h"
|
#include "ActionContext.h"
|
||||||
#include "ChatActionContext.h"
|
#include "ChatActionContext.h"
|
||||||
#include "ChatTriggerContext.h"
|
#include "ChatTriggerContext.h"
|
||||||
#include "DKAiObjectContext.h"
|
|
||||||
#include "DruidAiObjectContext.h"
|
|
||||||
#include "HunterAiObjectContext.h"
|
|
||||||
#include "MageAiObjectContext.h"
|
|
||||||
#include "PaladinAiObjectContext.h"
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "PriestAiObjectContext.h"
|
|
||||||
#include "RaidUlduarActionContext.h"
|
|
||||||
#include "RaidUlduarTriggerContext.h"
|
#include "RaidUlduarTriggerContext.h"
|
||||||
#include "RogueAiObjectContext.h"
|
#include "RaidUlduarActionContext.h"
|
||||||
#include "ShamanAiObjectContext.h"
|
|
||||||
#include "SharedValueContext.h"
|
#include "SharedValueContext.h"
|
||||||
#include "StrategyContext.h"
|
#include "StrategyContext.h"
|
||||||
#include "TriggerContext.h"
|
#include "TriggerContext.h"
|
||||||
#include "ValueContext.h"
|
#include "ValueContext.h"
|
||||||
#include "WarlockAiObjectContext.h"
|
|
||||||
#include "WarriorAiObjectContext.h"
|
|
||||||
#include "WorldPacketActionContext.h"
|
#include "WorldPacketActionContext.h"
|
||||||
#include "WorldPacketTriggerContext.h"
|
#include "WorldPacketTriggerContext.h"
|
||||||
#include "dungeons/DungeonStrategyContext.h"
|
#include "RaidStrategyContext.h"
|
||||||
#include "dungeons/wotlk/WotlkDungeonActionContext.h"
|
#include "RaidBwlActionContext.h"
|
||||||
#include "dungeons/wotlk/WotlkDungeonTriggerContext.h"
|
#include "RaidBwlTriggerContext.h"
|
||||||
#include "raids/RaidStrategyContext.h"
|
#include "RaidNaxxActionContext.h"
|
||||||
#include "raids/aq20/RaidAq20ActionContext.h"
|
#include "RaidNaxxTriggerContext.h"
|
||||||
#include "raids/aq20/RaidAq20TriggerContext.h"
|
#include "RaidIccActionContext.h"
|
||||||
#include "raids/blackwinglair/RaidBwlActionContext.h"
|
#include "RaidIccTriggerContext.h"
|
||||||
#include "raids/blackwinglair/RaidBwlTriggerContext.h"
|
#include "RaidOsActionContext.h"
|
||||||
#include "raids/eyeofeternity/RaidEoEActionContext.h"
|
#include "RaidOsTriggerContext.h"
|
||||||
#include "raids/eyeofeternity/RaidEoETriggerContext.h"
|
#include "RaidEoEActionContext.h"
|
||||||
#include "raids/icecrown/RaidIccActionContext.h"
|
#include "RaidVoATriggerContext.h"
|
||||||
#include "raids/icecrown/RaidIccTriggerContext.h"
|
#include "RaidOnyxiaActionContext.h"
|
||||||
#include "raids/moltencore/RaidMcActionContext.h"
|
#include "RaidOnyxiaTriggerContext.h"
|
||||||
#include "raids/moltencore/RaidMcTriggerContext.h"
|
#include "RaidVoAActionContext.h"
|
||||||
#include "raids/naxxramas/RaidNaxxActionContext.h"
|
#include "RaidEoETriggerContext.h"
|
||||||
#include "raids/naxxramas/RaidNaxxTriggerContext.h"
|
#include "RaidMcActionContext.h"
|
||||||
#include "raids/obsidiansanctum/RaidOsActionContext.h"
|
#include "RaidMcTriggerContext.h"
|
||||||
#include "raids/obsidiansanctum/RaidOsTriggerContext.h"
|
#include "RaidAq20ActionContext.h"
|
||||||
#include "raids/onyxia/RaidOnyxiaActionContext.h"
|
#include "RaidAq20TriggerContext.h"
|
||||||
#include "raids/onyxia/RaidOnyxiaTriggerContext.h"
|
#include "DungeonStrategyContext.h"
|
||||||
#include "raids/vaultofarchavon/RaidVoAActionContext.h"
|
#include "WotlkDungeonActionContext.h"
|
||||||
#include "raids/vaultofarchavon/RaidVoATriggerContext.h"
|
#include "WotlkDungeonTriggerContext.h"
|
||||||
|
|
||||||
SharedNamedObjectContextList<Strategy> AiObjectContext::sharedStrategyContexts;
|
AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
|
||||||
SharedNamedObjectContextList<Action> AiObjectContext::sharedActionContexts;
|
|
||||||
SharedNamedObjectContextList<Trigger> AiObjectContext::sharedTriggerContexts;
|
|
||||||
SharedNamedObjectContextList<UntypedValue> AiObjectContext::sharedValueContexts;
|
|
||||||
|
|
||||||
AiObjectContext::AiObjectContext(PlayerbotAI* botAI, SharedNamedObjectContextList<Strategy>& sharedStrategyContext,
|
|
||||||
SharedNamedObjectContextList<Action>& sharedActionContext,
|
|
||||||
SharedNamedObjectContextList<Trigger>& sharedTriggerContext,
|
|
||||||
SharedNamedObjectContextList<UntypedValue>& sharedValueContext)
|
|
||||||
: PlayerbotAIAware(botAI),
|
|
||||||
strategyContexts(sharedStrategyContext),
|
|
||||||
actionContexts(sharedActionContext),
|
|
||||||
triggerContexts(sharedTriggerContext),
|
|
||||||
valueContexts(sharedValueContext)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void AiObjectContext::BuildAllSharedContexts()
|
|
||||||
{
|
|
||||||
AiObjectContext::BuildSharedContexts();
|
|
||||||
PriestAiObjectContext::BuildSharedContexts();
|
|
||||||
MageAiObjectContext::BuildSharedContexts();
|
|
||||||
WarlockAiObjectContext::BuildSharedContexts();
|
|
||||||
WarriorAiObjectContext::BuildSharedContexts();
|
|
||||||
ShamanAiObjectContext::BuildSharedContexts();
|
|
||||||
PaladinAiObjectContext::BuildSharedContexts();
|
|
||||||
DruidAiObjectContext::BuildSharedContexts();
|
|
||||||
HunterAiObjectContext::BuildSharedContexts();
|
|
||||||
RogueAiObjectContext::BuildSharedContexts();
|
|
||||||
DKAiObjectContext::BuildSharedContexts();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AiObjectContext::BuildSharedContexts()
|
|
||||||
{
|
|
||||||
BuildSharedStrategyContexts(sharedStrategyContexts);
|
|
||||||
BuildSharedActionContexts(sharedActionContexts);
|
|
||||||
BuildSharedTriggerContexts(sharedTriggerContexts);
|
|
||||||
BuildSharedValueContexts(sharedValueContexts);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AiObjectContext::BuildSharedStrategyContexts(SharedNamedObjectContextList<Strategy>& strategyContexts)
|
|
||||||
{
|
{
|
||||||
strategyContexts.Add(new StrategyContext());
|
strategyContexts.Add(new StrategyContext());
|
||||||
strategyContexts.Add(new MovementStrategyContext());
|
strategyContexts.Add(new MovementStrategyContext());
|
||||||
@@ -98,10 +48,7 @@ void AiObjectContext::BuildSharedStrategyContexts(SharedNamedObjectContextList<S
|
|||||||
strategyContexts.Add(new QuestStrategyContext());
|
strategyContexts.Add(new QuestStrategyContext());
|
||||||
strategyContexts.Add(new RaidStrategyContext());
|
strategyContexts.Add(new RaidStrategyContext());
|
||||||
strategyContexts.Add(new DungeonStrategyContext());
|
strategyContexts.Add(new DungeonStrategyContext());
|
||||||
}
|
|
||||||
|
|
||||||
void AiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList<Action>& actionContexts)
|
|
||||||
{
|
|
||||||
actionContexts.Add(new ActionContext());
|
actionContexts.Add(new ActionContext());
|
||||||
actionContexts.Add(new ChatActionContext());
|
actionContexts.Add(new ChatActionContext());
|
||||||
actionContexts.Add(new WorldPacketActionContext());
|
actionContexts.Add(new WorldPacketActionContext());
|
||||||
@@ -128,12 +75,8 @@ void AiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList<Act
|
|||||||
actionContexts.Add(new WotlkDungeonUPActionContext());
|
actionContexts.Add(new WotlkDungeonUPActionContext());
|
||||||
actionContexts.Add(new WotlkDungeonCoSActionContext());
|
actionContexts.Add(new WotlkDungeonCoSActionContext());
|
||||||
actionContexts.Add(new WotlkDungeonFoSActionContext());
|
actionContexts.Add(new WotlkDungeonFoSActionContext());
|
||||||
actionContexts.Add(new WotlkDungeonPoSActionContext());
|
|
||||||
actionContexts.Add(new WotlkDungeonToCActionContext());
|
actionContexts.Add(new WotlkDungeonToCActionContext());
|
||||||
}
|
|
||||||
|
|
||||||
void AiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextList<Trigger>& triggerContexts)
|
|
||||||
{
|
|
||||||
triggerContexts.Add(new TriggerContext());
|
triggerContexts.Add(new TriggerContext());
|
||||||
triggerContexts.Add(new ChatTriggerContext());
|
triggerContexts.Add(new ChatTriggerContext());
|
||||||
triggerContexts.Add(new WorldPacketTriggerContext());
|
triggerContexts.Add(new WorldPacketTriggerContext());
|
||||||
@@ -159,14 +102,28 @@ void AiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextList<Tr
|
|||||||
triggerContexts.Add(new WotlkDungeonOccTriggerContext());
|
triggerContexts.Add(new WotlkDungeonOccTriggerContext());
|
||||||
triggerContexts.Add(new WotlkDungeonUPTriggerContext());
|
triggerContexts.Add(new WotlkDungeonUPTriggerContext());
|
||||||
triggerContexts.Add(new WotlkDungeonCoSTriggerContext());
|
triggerContexts.Add(new WotlkDungeonCoSTriggerContext());
|
||||||
triggerContexts.Add(new WotlkDungeonFoSTriggerContext());
|
triggerContexts.Add(new WotlkDungeonFosTriggerContext());
|
||||||
triggerContexts.Add(new WotlkDungeonPoSTriggerContext());
|
|
||||||
triggerContexts.Add(new WotlkDungeonToCTriggerContext());
|
triggerContexts.Add(new WotlkDungeonToCTriggerContext());
|
||||||
|
|
||||||
|
valueContexts.Add(new ValueContext());
|
||||||
|
|
||||||
|
valueContexts.Add(sSharedValueContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList<UntypedValue>& valueContexts)
|
void AiObjectContext::Update()
|
||||||
{
|
{
|
||||||
valueContexts.Add(new ValueContext());
|
strategyContexts.Update();
|
||||||
|
triggerContexts.Update();
|
||||||
|
actionContexts.Update();
|
||||||
|
valueContexts.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiObjectContext::Reset()
|
||||||
|
{
|
||||||
|
strategyContexts.Reset();
|
||||||
|
triggerContexts.Reset();
|
||||||
|
actionContexts.Reset();
|
||||||
|
valueContexts.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> AiObjectContext::Save()
|
std::vector<std::string> AiObjectContext::Save()
|
||||||
@@ -259,3 +216,5 @@ std::string const AiObjectContext::FormatValues()
|
|||||||
|
|
||||||
return out.str();
|
return out.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AiObjectContext::AddShared(NamedObjectContext<UntypedValue>* sharedValues) { valueContexts.Add(sharedValues); }
|
||||||
|
|||||||
@@ -19,20 +19,10 @@
|
|||||||
|
|
||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
|
|
||||||
typedef Strategy* (*StrategyCreator)(PlayerbotAI* botAI);
|
|
||||||
typedef Action* (*ActionCreator)(PlayerbotAI* botAI);
|
|
||||||
typedef Trigger* (*TriggerCreator)(PlayerbotAI* botAI);
|
|
||||||
typedef UntypedValue* (*ValueCreator)(PlayerbotAI* botAI);
|
|
||||||
|
|
||||||
class AiObjectContext : public PlayerbotAIAware
|
class AiObjectContext : public PlayerbotAIAware
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static BoolCalculatedValue* custom_glyphs(PlayerbotAI* ai); // Added for cutom glyphs
|
AiObjectContext(PlayerbotAI* botAI);
|
||||||
AiObjectContext(PlayerbotAI* botAI,
|
|
||||||
SharedNamedObjectContextList<Strategy>& sharedStrategyContext = sharedStrategyContexts,
|
|
||||||
SharedNamedObjectContextList<Action>& sharedActionContext = sharedActionContexts,
|
|
||||||
SharedNamedObjectContextList<Trigger>& sharedTriggerContext = sharedTriggerContexts,
|
|
||||||
SharedNamedObjectContextList<UntypedValue>& sharedValueContext = sharedValueContexts);
|
|
||||||
virtual ~AiObjectContext() {}
|
virtual ~AiObjectContext() {}
|
||||||
|
|
||||||
virtual Strategy* GetStrategy(std::string const name);
|
virtual Strategy* GetStrategy(std::string const name);
|
||||||
@@ -66,30 +56,20 @@ public:
|
|||||||
std::set<std::string> GetSupportedActions();
|
std::set<std::string> GetSupportedActions();
|
||||||
std::string const FormatValues();
|
std::string const FormatValues();
|
||||||
|
|
||||||
|
virtual void Update();
|
||||||
|
virtual void Reset();
|
||||||
|
virtual void AddShared(NamedObjectContext<UntypedValue>* sharedValues);
|
||||||
|
|
||||||
std::vector<std::string> Save();
|
std::vector<std::string> Save();
|
||||||
void Load(std::vector<std::string> data);
|
void Load(std::vector<std::string> data);
|
||||||
|
|
||||||
std::vector<std::string> performanceStack;
|
std::vector<std::string> performanceStack;
|
||||||
|
|
||||||
static void BuildAllSharedContexts();
|
|
||||||
|
|
||||||
static void BuildSharedContexts();
|
|
||||||
static void BuildSharedStrategyContexts(SharedNamedObjectContextList<Strategy>& strategyContexts);
|
|
||||||
static void BuildSharedActionContexts(SharedNamedObjectContextList<Action>& actionContexts);
|
|
||||||
static void BuildSharedTriggerContexts(SharedNamedObjectContextList<Trigger>& triggerContexts);
|
|
||||||
static void BuildSharedValueContexts(SharedNamedObjectContextList<UntypedValue>& valueContexts);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NamedObjectContextList<Strategy> strategyContexts;
|
NamedObjectContextList<Strategy> strategyContexts;
|
||||||
NamedObjectContextList<Action> actionContexts;
|
NamedObjectContextList<Action> actionContexts;
|
||||||
NamedObjectContextList<Trigger> triggerContexts;
|
NamedObjectContextList<Trigger> triggerContexts;
|
||||||
NamedObjectContextList<UntypedValue> valueContexts;
|
NamedObjectContextList<UntypedValue> valueContexts;
|
||||||
|
|
||||||
private:
|
|
||||||
static SharedNamedObjectContextList<Strategy> sharedStrategyContexts;
|
|
||||||
static SharedNamedObjectContextList<Action> sharedActionContexts;
|
|
||||||
static SharedNamedObjectContextList<Trigger> sharedTriggerContexts;
|
|
||||||
static SharedNamedObjectContextList<UntypedValue> sharedValueContexts;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,313 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
|
|
||||||
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PLAYERBOT_NAMEDOBJECTCONEXT_H
|
|
||||||
#define _PLAYERBOT_NAMEDOBJECTCONEXT_H
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <set>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <unordered_set>
|
|
||||||
#include <vector>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include "Common.h"
|
|
||||||
|
|
||||||
class PlayerbotAI;
|
|
||||||
|
|
||||||
class Qualified
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Qualified(){};
|
|
||||||
Qualified(std::string const qualifier) : qualifier(qualifier) {}
|
|
||||||
Qualified(int32 qualifier1) { Qualify(qualifier1); }
|
|
||||||
|
|
||||||
virtual void Qualify(int qual);
|
|
||||||
|
|
||||||
virtual void Qualify(std::string const qual) { qualifier = qual; }
|
|
||||||
|
|
||||||
std::string const getQualifier() { return qualifier; }
|
|
||||||
|
|
||||||
static std::string const MultiQualify(const std::vector<std::string>& qualifiers, const std::string& separator,
|
|
||||||
const std::string_view brackets = "{}");
|
|
||||||
static std::vector<std::string> getMultiQualifiers(const std::string& qualifier1);
|
|
||||||
static int32 getMultiQualifier(const std::string& qualifier1, uint32 pos);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::string qualifier;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class NamedObjectFactory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using ObjectCreator = std::function<T*(PlayerbotAI* ai)>;
|
|
||||||
std::unordered_map<std::string, ObjectCreator> creators;
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual T* create(std::string name, PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
size_t found = name.find("::");
|
|
||||||
std::string qualifier;
|
|
||||||
if (found != std::string::npos)
|
|
||||||
{
|
|
||||||
qualifier = name.substr(found + 2);
|
|
||||||
name = name.substr(0, found);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (creators.find(name) == creators.end())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
ObjectCreator& creator = creators[name];
|
|
||||||
|
|
||||||
T* object = creator(botAI);
|
|
||||||
Qualified* q = dynamic_cast<Qualified*>(object);
|
|
||||||
if (q && found != std::string::npos)
|
|
||||||
q->Qualify(qualifier);
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::set<std::string> supports()
|
|
||||||
{
|
|
||||||
std::set<std::string> keys;
|
|
||||||
for (typename std::unordered_map<std::string, ObjectCreator>::const_iterator it = creators.begin();
|
|
||||||
it != creators.end(); it++)
|
|
||||||
keys.insert(it->first);
|
|
||||||
|
|
||||||
return keys;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class NamedObjectContext : public NamedObjectFactory<T>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NamedObjectContext(bool shared = false, bool supportsSiblings = false)
|
|
||||||
: NamedObjectFactory<T>(), shared(shared), supportsSiblings(supportsSiblings)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~NamedObjectContext() { Clear(); }
|
|
||||||
|
|
||||||
virtual T* create(std::string name, PlayerbotAI* botAI) override
|
|
||||||
{
|
|
||||||
if (created.find(name) == created.end())
|
|
||||||
return created[name] = NamedObjectFactory<T>::create(name, botAI);
|
|
||||||
|
|
||||||
return created[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clear()
|
|
||||||
{
|
|
||||||
for (typename std::unordered_map<std::string, T*>::const_iterator i = created.begin(); i != created.end(); i++)
|
|
||||||
{
|
|
||||||
if (i->second)
|
|
||||||
delete i->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
created.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsShared() { return shared; }
|
|
||||||
bool IsSupportsSiblings() { return supportsSiblings; }
|
|
||||||
|
|
||||||
std::set<std::string> GetCreated()
|
|
||||||
{
|
|
||||||
std::set<std::string> keys;
|
|
||||||
for (typename std::unordered_map<std::string, T*>::iterator it = created.begin(); it != created.end(); it++)
|
|
||||||
keys.insert(it->first);
|
|
||||||
|
|
||||||
return keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::unordered_map<std::string, T*> created;
|
|
||||||
bool shared;
|
|
||||||
bool supportsSiblings;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class SharedNamedObjectContextList
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using ObjectCreator = std::function<T*(PlayerbotAI* ai)>;
|
|
||||||
std::unordered_map<std::string, ObjectCreator> creators;
|
|
||||||
std::vector<NamedObjectContext<T>*> contexts;
|
|
||||||
|
|
||||||
~SharedNamedObjectContextList()
|
|
||||||
{
|
|
||||||
for (typename std::vector<NamedObjectContext<T>*>::const_iterator i = contexts.begin(); i != contexts.end(); i++)
|
|
||||||
delete *i;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Add(NamedObjectContext<T>* context)
|
|
||||||
{
|
|
||||||
contexts.push_back(context);
|
|
||||||
for (const auto& iter : context->creators)
|
|
||||||
{
|
|
||||||
creators[iter.first] = iter.second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class NamedObjectContextList
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using ObjectCreator = std::function<T*(PlayerbotAI* ai)>;
|
|
||||||
const std::unordered_map<std::string, ObjectCreator>& creators;
|
|
||||||
const std::vector<NamedObjectContext<T>*>& contexts;
|
|
||||||
std::unordered_map<std::string, T*> created;
|
|
||||||
|
|
||||||
NamedObjectContextList(const SharedNamedObjectContextList<T>& shared)
|
|
||||||
: creators(shared.creators), contexts(shared.contexts)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~NamedObjectContextList()
|
|
||||||
{
|
|
||||||
for (typename std::unordered_map<std::string, T*>::const_iterator i = created.begin(); i != created.end(); i++)
|
|
||||||
{
|
|
||||||
if (i->second)
|
|
||||||
delete i->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
created.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
T* create(std::string name, PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
size_t found = name.find("::");
|
|
||||||
std::string qualifier;
|
|
||||||
if (found != std::string::npos)
|
|
||||||
{
|
|
||||||
qualifier = name.substr(found + 2);
|
|
||||||
name = name.substr(0, found);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (creators.find(name) == creators.end())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
const ObjectCreator& creator = creators.at(name);
|
|
||||||
|
|
||||||
T* object = creator(botAI);
|
|
||||||
Qualified* q = dynamic_cast<Qualified*>(object);
|
|
||||||
if (q && found != std::string::npos)
|
|
||||||
q->Qualify(qualifier);
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
|
|
||||||
T* GetContextObject(const std::string& name, PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
if (created.find(name) == created.end())
|
|
||||||
{
|
|
||||||
if (T* object = create(name, botAI))
|
|
||||||
return created[name] = object;
|
|
||||||
}
|
|
||||||
return created[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
std::set<std::string> GetSiblings(const std::string& name)
|
|
||||||
{
|
|
||||||
for (auto i = contexts.begin(); i != contexts.end(); i++)
|
|
||||||
{
|
|
||||||
if (!(*i)->IsSupportsSiblings())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
std::set<std::string> supported = (*i)->supports();
|
|
||||||
std::set<std::string>::iterator found = supported.find(name);
|
|
||||||
if (found == supported.end())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
supported.erase(found);
|
|
||||||
return supported;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::set<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::set<std::string> supports()
|
|
||||||
{
|
|
||||||
std::set<std::string> result;
|
|
||||||
for (auto i = contexts.begin(); i != contexts.end(); i++)
|
|
||||||
{
|
|
||||||
std::set<std::string> supported = (*i)->supports();
|
|
||||||
|
|
||||||
for (std::set<std::string>::const_iterator j = supported.begin(); j != supported.end(); ++j)
|
|
||||||
result.insert(*j);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::set<std::string> GetCreated()
|
|
||||||
{
|
|
||||||
std::set<std::string> result;
|
|
||||||
for (typename std::unordered_map<std::string, T*>::const_iterator i = created.begin(); i != created.end(); i++)
|
|
||||||
{
|
|
||||||
result.insert(i->first);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class NamedObjectFactoryList
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using ObjectCreator = std::function<T*(PlayerbotAI* ai)>;
|
|
||||||
std::vector<NamedObjectFactory<T>*> factories;
|
|
||||||
std::unordered_map<std::string, ObjectCreator> creators;
|
|
||||||
|
|
||||||
virtual ~NamedObjectFactoryList()
|
|
||||||
{
|
|
||||||
for (typename std::vector<NamedObjectFactory<T>*>::const_iterator i = factories.begin(); i != factories.end(); i++)
|
|
||||||
delete *i;
|
|
||||||
}
|
|
||||||
|
|
||||||
T* create(std::string name, PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
size_t found = name.find("::");
|
|
||||||
std::string qualifier;
|
|
||||||
if (found != std::string::npos)
|
|
||||||
{
|
|
||||||
qualifier = name.substr(found + 2);
|
|
||||||
name = name.substr(0, found);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (creators.find(name) == creators.end())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
const ObjectCreator& creator = creators[name];
|
|
||||||
|
|
||||||
T* object = creator(botAI);
|
|
||||||
Qualified* q = dynamic_cast<Qualified*>(object);
|
|
||||||
if (q && found != std::string::npos)
|
|
||||||
q->Qualify(qualifier);
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Add(NamedObjectFactory<T>* context)
|
|
||||||
{
|
|
||||||
factories.push_back(context);
|
|
||||||
for (const auto& iter : context->creators)
|
|
||||||
{
|
|
||||||
creators[iter.first] = iter.second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
T* GetContextObject(const std::string& name, PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
if (T* object = create(name, botAI))
|
|
||||||
return object;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
|
|
||||||
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PLAYERBOT_BATTLEGROUNDTACTICSACTION_H
|
|
||||||
#define _PLAYERBOT_BATTLEGROUNDTACTICSACTION_H
|
|
||||||
|
|
||||||
#include "BattlegroundAV.h"
|
|
||||||
#include "MovementActions.h"
|
|
||||||
|
|
||||||
class ChatHandler;
|
|
||||||
class Battleground;
|
|
||||||
class PlayerbotAI;
|
|
||||||
struct Position;
|
|
||||||
|
|
||||||
#define SPELL_CAPTURE_BANNER 21651
|
|
||||||
|
|
||||||
enum WSBotStrategy : uint8
|
|
||||||
{
|
|
||||||
WS_STRATEGY_BALANCED = 0,
|
|
||||||
WS_STRATEGY_OFFENSIVE = 1,
|
|
||||||
WS_STRATEGY_DEFENSIVE = 2,
|
|
||||||
WS_STRATEGY_MAX = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ABBotStrategy : uint8
|
|
||||||
{
|
|
||||||
AB_STRATEGY_BALANCED = 0,
|
|
||||||
AB_STRATEGY_OFFENSIVE = 1,
|
|
||||||
AB_STRATEGY_DEFENSIVE = 2,
|
|
||||||
AB_STRATEGY_MAX = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum AVBotStrategy : uint8
|
|
||||||
{
|
|
||||||
AV_STRATEGY_BALANCED = 0,
|
|
||||||
AV_STRATEGY_OFFENSIVE = 1,
|
|
||||||
AV_STRATEGY_DEFENSIVE = 2,
|
|
||||||
AV_STRATEGY_MAX = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum EYBotStrategy : uint8
|
|
||||||
{
|
|
||||||
EY_STRATEGY_BALANCED = 0,
|
|
||||||
EY_STRATEGY_FRONT_FOCUS = 1,
|
|
||||||
EY_STRATEGY_BACK_FOCUS = 2,
|
|
||||||
EY_STRATEGY_FLAG_FOCUS = 3,
|
|
||||||
EY_STRATEGY_MAX = 4
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef void (*BattleBotWaypointFunc)();
|
|
||||||
|
|
||||||
struct BGStrategyData
|
|
||||||
{
|
|
||||||
uint8 allianceStrategy = 0;
|
|
||||||
uint8 hordeStrategy = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern std::unordered_map<uint32, BGStrategyData> bgStrategies;
|
|
||||||
|
|
||||||
struct BattleBotWaypoint
|
|
||||||
{
|
|
||||||
BattleBotWaypoint(float x_, float y_, float z_, BattleBotWaypointFunc func) : x(x_), y(y_), z(z_), pFunc(func){};
|
|
||||||
|
|
||||||
float x = 0.0f;
|
|
||||||
float y = 0.0f;
|
|
||||||
float z = 0.0f;
|
|
||||||
BattleBotWaypointFunc pFunc = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AVNodePositionData
|
|
||||||
{
|
|
||||||
Position pos;
|
|
||||||
float maxRadius;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Added to fix bot stuck at objectives
|
|
||||||
static std::unordered_map<uint8, AVNodePositionData> AVNodeMovementTargets = {
|
|
||||||
{BG_AV_NODES_FIRSTAID_STATION, {Position(640.364f, -36.535f, 45.625f), 15.0f}},
|
|
||||||
{BG_AV_NODES_STORMPIKE_GRAVE, {Position(665.598f, -292.976f, 30.291f), 15.0f}},
|
|
||||||
{BG_AV_NODES_STONEHEART_GRAVE, {Position(76.108f, -399.602f, 45.730f), 15.0f}},
|
|
||||||
{BG_AV_NODES_SNOWFALL_GRAVE, {Position(-201.298f, -119.661f, 78.291f), 15.0f}},
|
|
||||||
{BG_AV_NODES_ICEBLOOD_GRAVE, {Position(-617.858f, -400.654f, 59.692f), 15.0f}},
|
|
||||||
{BG_AV_NODES_FROSTWOLF_GRAVE, {Position(-1083.803f, -341.520f, 55.304f), 15.0f}},
|
|
||||||
{BG_AV_NODES_FROSTWOLF_HUT, {Position(-1405.678f, -309.108f, 89.377f, 0.392f), 10.0f}},
|
|
||||||
{BG_AV_NODES_DUNBALDAR_SOUTH, {Position(556.551f, -77.240f, 51.931f), 0.0f}},
|
|
||||||
{BG_AV_NODES_DUNBALDAR_NORTH, {Position(670.664f, -142.031f, 63.666f), 0.0f}},
|
|
||||||
{BG_AV_NODES_ICEWING_BUNKER, {Position(200.310f, -361.232f, 56.387f), 0.0f}},
|
|
||||||
{BG_AV_NODES_STONEHEART_BUNKER, {Position(-156.302f, -440.032f, 40.403f), 0.0f}},
|
|
||||||
{BG_AV_NODES_ICEBLOOD_TOWER, {Position(-569.702f, -265.362f, 75.009f), 0.0f}},
|
|
||||||
{BG_AV_NODES_TOWER_POINT, {Position(-767.439f, -360.200f, 90.895f), 0.0f}},
|
|
||||||
{BG_AV_NODES_FROSTWOLF_ETOWER, {Position(-1303.737f, -314.070f, 113.868f), 0.0f}},
|
|
||||||
{BG_AV_NODES_FROSTWOLF_WTOWER, {Position(-1300.648f, -267.356f, 114.151f), 0.0f}},
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::vector<BattleBotWaypoint> BattleBotPath;
|
|
||||||
|
|
||||||
extern std::vector<BattleBotPath*> const vPaths_WS;
|
|
||||||
extern std::vector<BattleBotPath*> const vPaths_AB;
|
|
||||||
extern std::vector<BattleBotPath*> const vPaths_AV;
|
|
||||||
extern std::vector<BattleBotPath*> const vPaths_EY;
|
|
||||||
extern std::vector<BattleBotPath*> const vPaths_IC;
|
|
||||||
|
|
||||||
class BGTactics : public MovementAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static bool HandleConsoleCommand(ChatHandler* handler, char const* args);
|
|
||||||
uint8 static GetBotStrategyForTeam(Battleground* bg, TeamId teamId);
|
|
||||||
|
|
||||||
BGTactics(PlayerbotAI* botAI, std::string const name = "bg tactics") : MovementAction(botAI, name) {}
|
|
||||||
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static std::string const HandleConsoleCommandPrivate(WorldSession* session, char const* args);
|
|
||||||
bool moveToStart(bool force = false);
|
|
||||||
bool selectObjective(bool reset = false);
|
|
||||||
bool moveToObjective(bool ignoreDist);
|
|
||||||
bool selectObjectiveWp(std::vector<BattleBotPath*> const& vPaths);
|
|
||||||
bool moveToObjectiveWp(BattleBotPath* const& currentPath, uint32 currentPoint, bool reverse = false);
|
|
||||||
bool startNewPathBegin(std::vector<BattleBotPath*> const& vPaths);
|
|
||||||
bool startNewPathFree(std::vector<BattleBotPath*> const& vPaths);
|
|
||||||
bool resetObjective();
|
|
||||||
bool wsJumpDown();
|
|
||||||
bool eyJumpDown();
|
|
||||||
bool atFlag(std::vector<BattleBotPath*> const& vPaths, std::vector<uint32> const& vFlagIds);
|
|
||||||
bool flagTaken();
|
|
||||||
bool teamFlagTaken();
|
|
||||||
bool protectFC();
|
|
||||||
bool useBuff();
|
|
||||||
uint32 getPlayersInArea(TeamId teamId, Position point, float range, bool combat = true);
|
|
||||||
bool IsLockedInsideKeep();
|
|
||||||
};
|
|
||||||
|
|
||||||
class ArenaTactics : public MovementAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ArenaTactics(PlayerbotAI* botAI, std::string const name = "arena tactics") : MovementAction(botAI, name) {}
|
|
||||||
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool moveToCenter(Battleground* bg);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
|
|
||||||
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "CancelChannelAction.h"
|
|
||||||
#include "Player.h"
|
|
||||||
#include "PlayerbotAI.h"
|
|
||||||
|
|
||||||
bool CancelChannelAction::Execute(Event event)
|
|
||||||
{
|
|
||||||
if (bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
|
|
||||||
{
|
|
||||||
bot->InterruptSpell(CURRENT_CHANNELED_SPELL);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
|
|
||||||
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PLAYERBOT_CANCELCHANNELACTION_H
|
|
||||||
#define _PLAYERBOT_CANCELCHANNELACTION_H
|
|
||||||
|
|
||||||
#include "Action.h"
|
|
||||||
|
|
||||||
class PlayerbotAI;
|
|
||||||
|
|
||||||
class CancelChannelAction : public Action
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CancelChannelAction(PlayerbotAI* botAI) : Action(botAI, "cancel channel") {}
|
|
||||||
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
|
|
||||||
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "EquipGlyphsAction.h"
|
|
||||||
|
|
||||||
#include "Playerbots.h"
|
|
||||||
#include "ObjectMgr.h"
|
|
||||||
#include "SpellMgr.h"
|
|
||||||
#include "DBCStores.h"
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "Log.h"
|
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <sstream>
|
|
||||||
#include <unordered_set>
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
// itemId -> GlyphInfo
|
|
||||||
std::unordered_map<uint32, EquipGlyphsAction::GlyphInfo> s_GlyphCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EquipGlyphsAction::BuildGlyphCache()
|
|
||||||
{
|
|
||||||
if (!s_GlyphCache.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
ItemTemplateContainer const* store = sObjectMgr->GetItemTemplateStore();
|
|
||||||
|
|
||||||
for (auto const& kv : *store)
|
|
||||||
{
|
|
||||||
uint32 itemId = kv.first;
|
|
||||||
ItemTemplate const* proto = &kv.second;
|
|
||||||
if (!proto || proto->Class != ITEM_CLASS_GLYPH)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// inspect item spell
|
|
||||||
for (uint32 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
|
||||||
{
|
|
||||||
uint32 spellId = proto->Spells[i].SpellId;
|
|
||||||
if (!spellId) continue;
|
|
||||||
|
|
||||||
SpellInfo const* si = sSpellMgr->GetSpellInfo(spellId);
|
|
||||||
if (!si) continue;
|
|
||||||
|
|
||||||
for (uint8 eff = 0; eff <= EFFECT_2; ++eff)
|
|
||||||
{
|
|
||||||
if (si->Effects[eff].Effect != SPELL_EFFECT_APPLY_GLYPH)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
uint32 glyphId = si->Effects[eff].MiscValue;
|
|
||||||
if (!glyphId) continue;
|
|
||||||
|
|
||||||
if (auto const* gp = sGlyphPropertiesStore.LookupEntry(glyphId))
|
|
||||||
s_GlyphCache[itemId] = {gp, proto};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EquipGlyphsAction::GlyphInfo const* EquipGlyphsAction::GetGlyphInfo(uint32 itemId)
|
|
||||||
{
|
|
||||||
BuildGlyphCache();
|
|
||||||
auto it = s_GlyphCache.find(itemId);
|
|
||||||
return (it == s_GlyphCache.end()) ? nullptr : &it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// -----------------------------------------------------------------
|
|
||||||
/// Validation and collect
|
|
||||||
/// -----------------------------------------------------------------
|
|
||||||
bool EquipGlyphsAction::CollectGlyphs(std::vector<uint32> const& itemIds,
|
|
||||||
std::vector<GlyphInfo const*>& out) const
|
|
||||||
{
|
|
||||||
std::unordered_set<uint32> seen;
|
|
||||||
|
|
||||||
for (uint32 itemId : itemIds)
|
|
||||||
{
|
|
||||||
if (!seen.insert(itemId).second)
|
|
||||||
return false; // double
|
|
||||||
|
|
||||||
auto const* info = GetGlyphInfo(itemId);
|
|
||||||
if (!info) // no good glyph
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// check class by AllowableClass
|
|
||||||
if ((info->proto->AllowableClass & bot->getClassMask()) == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
out.push_back(info);
|
|
||||||
}
|
|
||||||
return out.size() <= 6 && !out.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// -----------------------------------------------------------------
|
|
||||||
/// Action
|
|
||||||
/// -----------------------------------------------------------------
|
|
||||||
bool EquipGlyphsAction::Execute(Event event)
|
|
||||||
{
|
|
||||||
// 1) parse IDs
|
|
||||||
std::vector<uint32> itemIds;
|
|
||||||
std::istringstream iss(event.getParam());
|
|
||||||
for (uint32 id; iss >> id; ) itemIds.push_back(id);
|
|
||||||
|
|
||||||
std::vector<GlyphInfo const*> glyphs;
|
|
||||||
if (!CollectGlyphs(itemIds, glyphs))
|
|
||||||
{
|
|
||||||
botAI->TellMaster("Usage: glyph equip <6 glyph item IDs> (3 major, 3 minor).");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2) prepare a empty slots table ?
|
|
||||||
bool used[6] = {false,false,false,false,false,false};
|
|
||||||
|
|
||||||
// 3) for each glyph, find the first available and compatible socket
|
|
||||||
for (auto const* g : glyphs)
|
|
||||||
{
|
|
||||||
bool placed = false;
|
|
||||||
|
|
||||||
for (uint8 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i)
|
|
||||||
{
|
|
||||||
if (used[i]) continue;
|
|
||||||
|
|
||||||
uint32 slotId = bot->GetGlyphSlot(i);
|
|
||||||
auto const* gs = sGlyphSlotStore.LookupEntry(slotId);
|
|
||||||
if (!gs || gs->TypeFlags != g->prop->TypeFlags)
|
|
||||||
continue; // major/minor don't match
|
|
||||||
|
|
||||||
// Remove aura if exist
|
|
||||||
uint32 cur = bot->GetGlyph(i);
|
|
||||||
if (cur)
|
|
||||||
if (auto* old = sGlyphPropertiesStore.LookupEntry(cur))
|
|
||||||
bot->RemoveAurasDueToSpell(old->SpellId);
|
|
||||||
|
|
||||||
// Apply new one
|
|
||||||
bot->CastSpell(bot, g->prop->SpellId, true);
|
|
||||||
bot->SetGlyph(i, g->prop->Id, true);
|
|
||||||
|
|
||||||
used[i] = true;
|
|
||||||
placed = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!placed)
|
|
||||||
{
|
|
||||||
botAI->TellMaster("Not enought empty sockets for all glyphs.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
botAI->TellMaster("Glyphs updated.");
|
|
||||||
|
|
||||||
// Flag for custom glyphs
|
|
||||||
botAI->GetAiObjectContext()->GetValue<bool>("custom_glyphs")->Set(true);
|
|
||||||
LOG_INFO("playerbots", "Custom Glyph Flag set to ON");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
|
|
||||||
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PLAYERBOT_EQUIPGLYPHSACTION_H
|
|
||||||
#define _PLAYERBOT_EQUIPGLYPHSACTION_H
|
|
||||||
|
|
||||||
#include "Action.h"
|
|
||||||
|
|
||||||
// 1 = major, 2 = minor dans GlyphProperties.dbc
|
|
||||||
enum class GlyphKind : uint32 { MAJOR = 1, MINOR = 2 };
|
|
||||||
|
|
||||||
class EquipGlyphsAction : public Action
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
EquipGlyphsAction(PlayerbotAI* ai) : Action(ai, "glyph equip") {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
|
|
||||||
/// ---- Rendu public pour être utilisable par le cache global ----
|
|
||||||
struct GlyphInfo
|
|
||||||
{
|
|
||||||
GlyphPropertiesEntry const* prop; ///< entrée GlyphProperties.dbc
|
|
||||||
ItemTemplate const* proto; ///< template de l’objet glyphe
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// Construit la cache {itemId -> GlyphInfo}
|
|
||||||
static void BuildGlyphCache();
|
|
||||||
static GlyphInfo const* GetGlyphInfo(uint32 itemId);
|
|
||||||
|
|
||||||
/// Parse & valide la liste d’items glyphes
|
|
||||||
bool CollectGlyphs(std::vector<uint32> const& itemIds,
|
|
||||||
std::vector<GlyphInfo const*>& out) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user