Compare commits

..

No commits in common. "92fa97c3aa3d9391b895f525956b0f07678adcaa" and "4a63ee37e29f44010a0c926d33c114816abc2946" have entirely different histories.

26 changed files with 369 additions and 663 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +0,0 @@
DELETE FROM ai_playerbot_texts WHERE name IN (
'send_mail_disabled'
);
DELETE FROM ai_playerbot_texts_chance WHERE name IN (
'send_mail_disabled'
);
INSERT INTO ai_playerbot_texts (id, name, text, say_type, reply_type, text_loc1, text_loc2, text_loc3, text_loc4, text_loc5, text_loc6, text_loc7, text_loc8) VALUES
(1899, 'send_mail_disabled', 'I cannot send mail', 0, 0, '우편을 보낼 수 없습니다', 'Je ne peux pas envoyer de courrier', 'Ich kann keine Post senden', '我不能寄送邮件', '我不能寄送郵件', 'No puedo enviar correo', 'No puedo enviar correo', 'Я не могу отправить почту');
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES
('send_mail_disabled', 100);

View File

@ -12,8 +12,8 @@ bool AutoMaintenanceOnLevelupAction::Execute(Event /*event*/)
{
AutoPickTalents();
AutoLearnSpell();
AutoTeleportForLevel();
AutoUpgradeEquip();
AutoTeleportForLevel();
return true;
}
@ -21,11 +21,13 @@ bool AutoMaintenanceOnLevelupAction::Execute(Event /*event*/)
void AutoMaintenanceOnLevelupAction::AutoTeleportForLevel()
{
if (!sPlayerbotAIConfig.autoTeleportForLevel || !sRandomPlayerbotMgr.IsRandomBot(bot))
{
return;
}
if (botAI->HasRealPlayerMaster())
{
return;
}
sRandomPlayerbotMgr.RandomTeleportForLevel(bot);
return;
}
@ -87,17 +89,21 @@ void AutoMaintenanceOnLevelupAction::LearnQuestSpells(std::ostringstream* out)
{
Quest const* quest = i->second;
if (!quest->GetRequiredClasses() || quest->IsRepeatable() || quest->GetMinLevel() < 10 ||
quest->GetMinLevel() > bot->GetLevel())
{
// only process class-specific quests to learn class-related spells, cuz
// we don't want all these bunch of entries to be handled!
if (!quest->GetRequiredClasses())
continue;
}
// skip quests that are repeatable, too low level, or above bots' level
if (quest->IsRepeatable() || quest->GetMinLevel() < 10 || quest->GetMinLevel() > bot->GetLevel())
continue;
// skip if bot doesnt satisfy class, race, or skill requirements
if (!bot->SatisfyQuestClass(quest, false) || !bot->SatisfyQuestRace(quest, false) ||
!bot->SatisfyQuestSkill(quest, false))
{
continue;
}
// use the same logic and impl from Player::learnQuestRewardedSpells
int32 spellId = quest->GetRewSpellCast();
if (!spellId)
@ -107,26 +113,31 @@ void AutoMaintenanceOnLevelupAction::LearnQuestSpells(std::ostringstream* out)
if (!spellInfo)
continue;
// xinef: find effect with learn spell and check if we have this spell
bool found = false;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
if (spellInfo->Effects[i].Effect == SPELL_EFFECT_LEARN_SPELL && spellInfo->Effects[i].TriggerSpell &&
!bot->HasSpell(spellInfo->Effects[i].TriggerSpell))
{
// pusywizard: don't re-add profession specialties!
if (SpellInfo const* triggeredInfo = sSpellMgr->GetSpellInfo(spellInfo->Effects[i].TriggerSpell))
if (triggeredInfo->Effects[0].Effect == SPELL_EFFECT_TRADE_SKILL)
break;
break; // pussywizard: break and not cast the spell (found is false)
found = true;
break;
}
}
// xinef: we know the spell, continue
if (!found)
continue;
bot->CastSpell(bot, spellId, true);
// Check if RewardDisplaySpell is set to output the proper spell learned
// after processing quests. Output the original RewardSpell otherwise.
uint32 rewSpellId = quest->GetRewSpell();
if (rewSpellId)
{
@ -156,11 +167,12 @@ std::string const AutoMaintenanceOnLevelupAction::FormatSpell(SpellInfo const* s
void AutoMaintenanceOnLevelupAction::AutoUpgradeEquip()
{
if (!sRandomPlayerbotMgr.IsRandomBot(bot))
if (!sPlayerbotAIConfig.autoUpgradeEquip || !sRandomPlayerbotMgr.IsRandomBot(bot))
return;
PlayerbotFactory factory(bot, bot->GetLevel());
// Clean up old consumables before adding new ones
factory.CleanupConsumables();
factory.InitAmmo();
@ -169,6 +181,9 @@ void AutoMaintenanceOnLevelupAction::AutoUpgradeEquip()
factory.InitConsumables();
factory.InitPotions();
if (sPlayerbotAIConfig.autoUpgradeEquip)
if (!sPlayerbotAIConfig.equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel)
{
if (sPlayerbotAIConfig.incrementalGearInit)
factory.InitEquipment(true);
}
}

View File

@ -154,11 +154,9 @@ void EquipAction::EquipItem(Item* item)
calculator.SetOverflowPenalty(false);
// Calculate item scores once and store them
float newItemScore = calculator.CalculateItem(itemId, item->GetItemRandomPropertyId());
float mainHandScore = mainHandItem
? calculator.CalculateItem(mainHandItem->GetTemplate()->ItemId, mainHandItem->GetItemRandomPropertyId()) : 0.0f;
float offHandScore = offHandItem
? calculator.CalculateItem(offHandItem->GetTemplate()->ItemId, offHandItem->GetItemRandomPropertyId()) : 0.0f;
float newItemScore = calculator.CalculateItem(itemId);
float mainHandScore = mainHandItem ? calculator.CalculateItem(mainHandItem->GetTemplate()->ItemId) : 0.0f;
float offHandScore = offHandItem ? calculator.CalculateItem(offHandItem->GetTemplate()->ItemId) : 0.0f;
// Determine where this weapon can go
bool canGoMain = (invType == INVTYPE_WEAPON ||

View File

@ -6,7 +6,6 @@
#include "GenericSpellActions.h"
#include <ctime>
#include <unordered_set>
#include "Event.h"
#include "ItemTemplate.h"
@ -24,116 +23,6 @@
using ai::buff::MakeAuraQualifierForBuff;
using ai::spell::HasSpellOrCategoryCooldown;
namespace
{
std::unordered_set<uint32> const& GetMixedTriggerTrinketSpellIds()
{
static std::unordered_set<uint32> const mixedTriggerSpellIds = []()
{
std::unordered_set<uint32> onUseSpellIds;
std::unordered_set<uint32> onEquipSpellIds;
std::unordered_set<uint32> mixedSpellIds;
auto const* itemTemplates = sObjectMgr->GetItemTemplateStore();
if (!itemTemplates)
return mixedSpellIds;
auto const markSpellId = [&](int32 spellId, uint8 spellTrigger)
{
if (spellId <= 0)
return;
if (spellTrigger == ITEM_SPELLTRIGGER_ON_USE)
{
if (onEquipSpellIds.find(spellId) != onEquipSpellIds.end())
mixedSpellIds.insert(spellId);
onUseSpellIds.insert(spellId);
}
else if (spellTrigger == ITEM_SPELLTRIGGER_ON_EQUIP)
{
if (onUseSpellIds.find(spellId) != onUseSpellIds.end())
mixedSpellIds.insert(spellId);
onEquipSpellIds.insert(spellId);
}
};
for (auto const& itr : *itemTemplates)
{
ItemTemplate const& proto = itr.second;
if (proto.InventoryType != INVTYPE_TRINKET)
continue;
for (uint8 spellIndex = 0; spellIndex < MAX_ITEM_PROTO_SPELLS; ++spellIndex)
{
auto const& spellData = proto.Spells[spellIndex];
markSpellId(spellData.SpellId, spellData.SpellTrigger);
}
}
return mixedSpellIds;
}();
return mixedTriggerSpellIds;
}
bool IsManaRestoreEffect(SpellEffectInfo const& effectInfo)
{
return (effectInfo.Effect == SPELL_EFFECT_ENERGIZE &&
effectInfo.MiscValue == POWER_MANA) ||
(effectInfo.Effect == SPELL_EFFECT_APPLY_AURA &&
effectInfo.ApplyAuraName == SPELL_AURA_PERIODIC_ENERGIZE &&
effectInfo.MiscValue == POWER_MANA);
}
bool IsManaEfficiencyEffect(SpellEffectInfo const& effectInfo)
{
return effectInfo.Effect == SPELL_EFFECT_APPLY_AURA &&
(((effectInfo.ApplyAuraName == SPELL_AURA_MOD_POWER_REGEN ||
effectInfo.ApplyAuraName == SPELL_AURA_MOD_POWER_REGEN_PERCENT) &&
effectInfo.MiscValue == POWER_MANA) ||
effectInfo.ApplyAuraName == SPELL_AURA_MOD_POWER_COST_SCHOOL ||
effectInfo.ApplyAuraName == SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT ||
effectInfo.ApplyAuraName == SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
}
bool IsDefensiveTankEffect(SpellEffectInfo const& effectInfo)
{
if (effectInfo.Effect != SPELL_EFFECT_APPLY_AURA)
return false;
uint32 const tankRatingsMask =
(1u << CR_DEFENSE_SKILL) |
(1u << CR_DODGE) |
(1u << CR_PARRY) |
(1u << CR_BLOCK) |
(1u << CR_HIT_TAKEN_MELEE) |
(1u << CR_HIT_TAKEN_RANGED) |
(1u << CR_HIT_TAKEN_SPELL) |
(1u << CR_CRIT_TAKEN_MELEE) |
(1u << CR_CRIT_TAKEN_RANGED) |
(1u << CR_CRIT_TAKEN_SPELL);
switch (effectInfo.ApplyAuraName)
{
case SPELL_AURA_MOD_RESISTANCE:
return (effectInfo.MiscValue & SPELL_SCHOOL_MASK_NORMAL) != 0;
case SPELL_AURA_MOD_RATING:
return (effectInfo.MiscValue & tankRatingsMask) != 0;
case SPELL_AURA_MOD_INCREASE_HEALTH:
case SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT:
case SPELL_AURA_MOD_PARRY_PERCENT:
case SPELL_AURA_MOD_DODGE_PERCENT:
case SPELL_AURA_MOD_BLOCK_PERCENT:
case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN:
return true;
default:
return false;
}
}
}
CastSpellAction::CastSpellAction(PlayerbotAI* botAI, std::string const spell)
: Action(botAI, spell), range(botAI->GetRange("spell")), spell(spell) {}
@ -540,109 +429,52 @@ bool UseTrinketAction::UseTrinket(Item* item)
uint8 bagIndex = item->GetBagSlot();
uint8 slot = item->GetSlot();
// uint8 spell_index = 0; //not used, line marked for removal.
uint8 cast_count = 1;
ObjectGuid item_guid = item->GetGUID();
uint32 glyphIndex = 0;
uint8 castFlags = 0;
uint32 targetFlag = TARGET_FLAG_NONE;
uint32 spellId = 0;
int32 itemSpellCooldown = 0;
uint32 itemSpellCategory = 0;
int32 itemSpellCategoryCooldown = 0;
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
if (item->GetTemplate()->Spells[i].SpellId > 0 &&
item->GetTemplate()->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE)
{
spellId = item->GetTemplate()->Spells[i].SpellId;
itemSpellCooldown = item->GetTemplate()->Spells[i].SpellCooldown;
itemSpellCategory = item->GetTemplate()->Spells[i].SpellCategory;
itemSpellCategoryCooldown = item->GetTemplate()->Spells[i].SpellCategoryCooldown;
uint64 const itemCooldownKey = (static_cast<uint64>(item->GetEntry()) << 32) | spellId;
uint32 const now = getMSTime();
if (itemSpellCooldown > 0)
{
auto const itemCooldownItr = trinketItemCooldownExpiries.find(itemCooldownKey);
if (itemCooldownItr != trinketItemCooldownExpiries.end())
{
if (itemCooldownItr->second > now)
return false;
trinketItemCooldownExpiries.erase(itemCooldownItr);
}
}
if (itemSpellCategory && itemSpellCategoryCooldown > 0)
{
auto const categoryCooldownItr = trinketCategoryCooldownExpiries.find(itemSpellCategory);
if (categoryCooldownItr != trinketCategoryCooldownExpiries.end())
{
if (categoryCooldownItr->second > now)
return false;
trinketCategoryCooldownExpiries.erase(categoryCooldownItr);
}
}
const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo || !spellInfo->IsPositive())
return false;
bool applyAura = false;
bool restoresMana = false;
bool improvesManaEfficiency = false;
bool defensiveTankEffect = false;
for (int i = 0; i < MAX_SPELL_EFFECTS; i++)
{
const SpellEffectInfo& effectInfo = spellInfo->Effects[i];
if (effectInfo.Effect == SPELL_EFFECT_APPLY_AURA)
{
applyAura = true;
restoresMana = restoresMana || IsManaRestoreEffect(effectInfo);
improvesManaEfficiency = improvesManaEfficiency || IsManaEfficiencyEffect(effectInfo);
defensiveTankEffect = defensiveTankEffect || IsDefensiveTankEffect(effectInfo);
}
if (!applyAura && !restoresMana)
return false;
if (restoresMana || improvesManaEfficiency)
{
if (!AI_VALUE2(bool, "has mana", "self target"))
return false;
uint8 const manaPct = AI_VALUE2(uint8, "mana", "self target");
if ((restoresMana && manaPct >= sPlayerbotAIConfig.mediumMana) ||
manaPct >= sPlayerbotAIConfig.highMana)
{
return false;
}
}
if (defensiveTankEffect)
{
uint8 const healthPct = AI_VALUE2(uint8, "health", "self target");
if (healthPct > sPlayerbotAIConfig.lowHealth)
return false;
}
auto const& mixedTriggerTrinketSpellIds = GetMixedTriggerTrinketSpellIds();
// Exclude trinkets that expose the same spell as both ON_EQUIP and ON_USE across
// item templates. Those are equip/proc effects leaking into the active-use path,
// as seen with the error versions of Oracle Talisman of Ablution (44870) and
// Frenzyheart Insignia of Fury (44869).
if (mixedTriggerTrinketSpellIds.find(spellId) != mixedTriggerTrinketSpellIds.end())
return false;
if (!botAI->CanCastSpell(spellId, bot, false, nullptr, item))
return false;
break;
}
}
if (!applyAura)
return false;
uint32 spellProcFlag = spellInfo->ProcFlags;
// Handle items with procflag "if you kill a target that grants honor or experience"
// Bots will "learn" the trinket proc, so CanCastSpell() will be true
// e.g. on Item https://www.wowhead.com/wotlk/item=44074/oracle-talisman-of-ablution leading to
// constant casting of the proc spell onto themselfes https://www.wowhead.com/wotlk/spell=59787/oracle-ablutions
// This will lead to multiple hundreds of entries in m_appliedAuras -> Once killing an enemy -> Big diff time spikes
if (spellProcFlag != 0) return false;
if (!botAI->CanCastSpell(spellId, bot, false))
return false;
break;
}
}
if (!spellId)
return false;
@ -651,25 +483,7 @@ bool UseTrinketAction::UseTrinket(Item* item)
targetFlag = TARGET_FLAG_NONE;
packet << targetFlag << bot->GetPackGUID();
bot->GetSession()->HandleUseItemOpcode(packet);
uint32 const now = getMSTime();
uint32 const cooldownDelay = bot->GetSpellCooldownDelay(spellId);
if (cooldownDelay > 0)
{
if (itemSpellCooldown > 0)
{
uint64 const itemCooldownKey = (static_cast<uint64>(item->GetEntry()) << 32) | spellId;
trinketItemCooldownExpiries[itemCooldownKey] = now + static_cast<uint32>(itemSpellCooldown);
}
if (itemSpellCategory && itemSpellCategoryCooldown > 0)
{
trinketCategoryCooldownExpiries[itemSpellCategory] = now + static_cast<uint32>(itemSpellCategoryCooldown);
}
}
return true;
}

View File

@ -334,10 +334,6 @@ public:
protected:
bool UseTrinket(Item* trinket);
private:
std::unordered_map<uint64, uint32> trinketItemCooldownExpiries;
std::unordered_map<uint32, uint32> trinketCategoryCooldownExpiries;
};
class CastSpellOnEnemyHealerAction : public CastSpellAction

View File

@ -44,21 +44,6 @@ bool ResetAiAction::Execute(Event event)
}
}
}
if (Player* master = botAI->GetMaster())
{
Group* botGroup = bot->GetGroup();
Group* masterGroup = master->GetGroup();
if (botGroup && (!masterGroup || masterGroup != botGroup))
botAI->SetMaster(nullptr);
}
if (sRandomPlayerbotMgr.IsRandomBot(bot) && !bot->InBattleground())
{
if (bot->GetGroup() && (!botAI->GetMaster() || GET_PLAYERBOT_AI(botAI->GetMaster())))
{
if (Player* newMaster = botAI->FindNewMaster())
botAI->SetMaster(newMaster);
}
}
PlayerbotRepository::instance().Reset(botAI);
botAI->ResetStrategies(false);
botAI->TellMaster("AI was reset to defaults");

View File

@ -34,23 +34,24 @@ bool SendMailAction::Execute(Event event)
Player* receiver = GetMaster();
Player* tellTo = receiver;
std::vector<std::string> ss = split(text, ' ');
if (ss.size() > 1)
{
if (Player* p = ObjectAccessor::FindPlayer(ObjectGuid(uint64(ss[ss.size() - 1].c_str()))))
receiver = p;
}
if (!receiver)
receiver = event.getOwner();
if (!receiver || receiver == bot)
{
return false;
}
if (!tellTo)
tellTo = receiver;
if (!sPlayerbotAIConfig.botSendMailEnabled)
{
bot->Whisper(PlayerbotTextMgr::instance().GetBotTextOrDefault(
"send_mail_disabled", "I cannot send mail", {}),
LANG_UNIVERSAL, tellTo);
return false;
}
if (!mailboxFound && !randomBot)
{
bot->Whisper(PlayerbotTextMgr::instance().GetBotTextOrDefault(

View File

@ -16,7 +16,7 @@ void WorldPacketHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
triggers.push_back(
new TriggerNode("uninvite guid", { NextAction("uninvite", relevance) }));
triggers.push_back(
new TriggerNode("group set leader", { NextAction("reset botAI", relevance) }));
new TriggerNode("group set leader", { /*NextAction("leader", relevance),*/ }));
triggers.push_back(new TriggerNode(
"not enough money", { NextAction("tell not enough money", relevance) }));
triggers.push_back(

View File

@ -38,16 +38,3 @@ bool BwlUseHourglassSandAction::Execute(Event /*event*/)
{
return botAI->CastSpell(SPELL_HOURGLASS_SAND, bot);
}
bool BwlNefarianFearWardAction::Execute(Event /*event*/)
{
Unit* nefarian = AI_VALUE2(Unit*, "find target", "nefarian");
if (!nefarian)
return false;
Unit* victim = nefarian->GetVictim();
if (!victim)
return false;
return botAI->CastSpell("fear ward", victim);
}

View File

@ -29,11 +29,4 @@ public:
bool Execute(Event event) override;
};
class BwlNefarianFearWardAction : public Action
{
public:
BwlNefarianFearWardAction(PlayerbotAI* botAI) : Action(botAI, "bwl nefarian fear ward") {}
bool Execute(Event event) override;
};
#endif

View File

@ -13,14 +13,12 @@ public:
creators["bwl check onyxia scale cloak"] = &RaidBwlActionContext::bwl_check_onyxia_scale_cloak;
creators["bwl turn off suppression device"] = &RaidBwlActionContext::bwl_turn_off_suppression_device;
creators["bwl use hourglass sand"] = &RaidBwlActionContext::bwl_use_hourglass_sand;
creators["bwl nefarian fear ward"] = &RaidBwlActionContext::bwl_nefarian_fear_ward;
}
private:
static Action* bwl_check_onyxia_scale_cloak(PlayerbotAI* botAI) { return new BwlOnyxiaScaleCloakAuraCheckAction(botAI); }
static Action* bwl_turn_off_suppression_device(PlayerbotAI* botAI) { return new BwlTurnOffSuppressionDeviceAction(botAI); }
static Action* bwl_use_hourglass_sand(PlayerbotAI* botAI) { return new BwlUseHourglassSandAction(botAI); }
static Action* bwl_nefarian_fear_ward(PlayerbotAI* botAI) { return new BwlNefarianFearWardAction(botAI); }
};
#endif

View File

@ -11,15 +11,11 @@ public:
{
creators["bwl suppression device"] = &RaidBwlTriggerContext::bwl_suppression_device;
creators["bwl affliction bronze"] = &RaidBwlTriggerContext::bwl_affliction_bronze;
creators["bwl wild magic"] = &RaidBwlTriggerContext::bwl_wild_magic;
creators["bwl nefarian fear ward"] = &RaidBwlTriggerContext::bwl_nefarian_fear_ward;
}
private:
static Trigger* bwl_suppression_device(PlayerbotAI* ai) { return new BwlSuppressionDeviceTrigger(ai); }
static Trigger* bwl_affliction_bronze(PlayerbotAI* ai) { return new BwlAfflictionBronzeTrigger(ai); }
static Trigger* bwl_wild_magic(PlayerbotAI* ai) { return new BwlWildMagicTrigger(ai); }
static Trigger* bwl_nefarian_fear_ward(PlayerbotAI* ai) { return new BwlNefarianFearWardTrigger(ai); }
};
#endif

View File

@ -10,10 +10,4 @@ void RaidBwlStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(new TriggerNode("bwl affliction bronze", {
NextAction("bwl use hourglass sand", ACTION_RAID) }));
triggers.push_back(new TriggerNode("bwl wild magic", {
NextAction("ice block", ACTION_RAID) }));
triggers.push_back(new TriggerNode("bwl nefarian fear ward", {
NextAction("bwl nefarian fear ward", ACTION_RAID) }));
}

View File

@ -27,24 +27,3 @@ bool BwlAfflictionBronzeTrigger::IsActive()
{
return bot->HasAura(SPELL_BROOD_AFFLICTION_BRONZE);
}
bool BwlWildMagicTrigger::IsActive()
{
return bot->getClass() == CLASS_MAGE && bot->HasAura(SPELL_WILD_MAGIC);
}
bool BwlNefarianFearWardTrigger::IsActive()
{
if (bot->getClass() != CLASS_PRIEST)
return false;
Unit* nefarian = AI_VALUE2(Unit*, "find target", "nefarian");
if (!nefarian || !nefarian->IsInCombat())
return false;
Unit* victim = nefarian->GetVictim();
if (!victim)
return false;
return !botAI->HasAura("fear ward", victim);
}

View File

@ -21,20 +21,4 @@ public:
bool IsActive() override;
};
// Nefarian
class BwlWildMagicTrigger : public Trigger
{
public:
BwlWildMagicTrigger(PlayerbotAI* botAI) : Trigger(botAI, "bwl wild magic") {}
bool IsActive() override;
};
class BwlNefarianFearWardTrigger : public Trigger
{
public:
BwlNefarianFearWardTrigger(PlayerbotAI* botAI) : Trigger(botAI, "bwl nefarian fear ward") {}
bool IsActive() override;
};
#endif

View File

@ -12,10 +12,7 @@ namespace BlackwingLairHelpers
// Chromaggus
SPELL_BROOD_AFFLICTION_BRONZE = 23170,
SPELL_HOURGLASS_SAND = 23645,
// Nefarian
SPELL_WILD_MAGIC = 23410
SPELL_HOURGLASS_SAND = 23645
};
enum BlackwingLairGameObjects

View File

@ -552,8 +552,9 @@ void PlayerbotFactory::Prepare()
void PlayerbotFactory::Randomize(bool incremental)
{
// if (sPlayerbotAIConfig.disableRandomLevels)
// {
// return;
// }
LOG_DEBUG("playerbots", "{} randomizing {} (level {} class = {})...", (incremental ? "Incremental" : "Full"),
bot->GetName().c_str(), level, bot->getClass());
// LOG_DEBUG("playerbots", "Preparing to {} randomize...", (incremental ? "incremental" : "full"));
@ -561,23 +562,17 @@ void PlayerbotFactory::Randomize(bool incremental)
LOG_DEBUG("playerbots", "Resetting player...");
PerfMonitorOperation* pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Reset");
if (!sPlayerbotAIConfig.equipAndSpecPersistence ||
level < sPlayerbotAIConfig.equipAndSpecPersistenceLevel)
{
if (!PlayerbotAIConfig::instance().equipmentPersistence || level < PlayerbotAIConfig::instance().equipmentPersistenceLevel)
bot->resetTalents(true);
}
if (!incremental)
{
ClearSkills();
ClearSpells();
ResetQuests();
if (!sPlayerbotAIConfig.equipAndSpecPersistence ||
level < sPlayerbotAIConfig.equipAndSpecPersistenceLevel)
{
if (!PlayerbotAIConfig::instance().equipmentPersistence || level < PlayerbotAIConfig::instance().equipmentPersistenceLevel)
ClearAllItems();
}
}
ClearInventory();
bot->RemoveAllSpellCooldown();
UnbindInstance();
@ -627,8 +622,8 @@ void PlayerbotFactory::Randomize(bool incremental)
pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Talents");
LOG_DEBUG("playerbots", "Initializing talents...");
if (!incremental || !sPlayerbotAIConfig.equipAndSpecPersistence ||
bot->GetLevel() < sPlayerbotAIConfig.equipAndSpecPersistenceLevel)
if (!incremental || !sPlayerbotAIConfig.equipmentPersistence ||
bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel)
{
uint32 specIndex = InitTalentsTree();
sRandomPlayerbotMgr.SetValue(bot->GetGUID().GetCounter(), "specNo", specIndex + 1);
@ -675,9 +670,10 @@ void PlayerbotFactory::Randomize(bool incremental)
pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Equip");
LOG_DEBUG("playerbots", "Initializing equipmemt...");
if (!incremental || !sPlayerbotAIConfig.equipAndSpecPersistence ||
bot->GetLevel() < sPlayerbotAIConfig.equipAndSpecPersistenceLevel)
if (!incremental || !sPlayerbotAIConfig.equipmentPersistence ||
bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel)
{
if (sPlayerbotAIConfig.incrementalGearInit || !incremental)
InitEquipment(incremental, incremental ? false : sPlayerbotAIConfig.twoRoundsGearInit);
}
// bot->SaveToDB(false, false);
@ -815,8 +811,7 @@ void PlayerbotFactory::Randomize(bool incremental)
void PlayerbotFactory::Refresh()
{
// Prepare();
// if (!sPlayerbotAIConfig.equipAndSpecPersistence ||
// bot->GetLevel() < sPlayerbotAIConfig.equipAndSpecPersistenceLevel)
// if (!sPlayerbotAIConfig.equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel)
// {
// InitEquipment(true);
// }
@ -836,13 +831,14 @@ void PlayerbotFactory::Refresh()
InitSpecialSpells();
InitMounts();
InitKeyring();
if (!sPlayerbotAIConfig.equipAndSpecPersistence ||
bot->GetLevel() < sPlayerbotAIConfig.equipAndSpecPersistenceLevel)
if (!sPlayerbotAIConfig.equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel)
{
InitTalentsTree(true, true, true);
}
if (bot->GetLevel() >= sPlayerbotAIConfig.minEnchantingBotLevel)
{
ApplyEnchantAndGemsNew();
}
bot->DurabilityRepairAll(false, 1.0f, false);
if (bot->isDead())
bot->ResurrectPlayer(1.0f, false);
@ -2041,6 +2037,9 @@ void Shuffle(std::vector<uint32>& items)
void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
{
if (incremental && !sPlayerbotAIConfig.incrementalGearInit)
return;
if (level < 5)
{
// original items
@ -2082,7 +2081,7 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
return;
}
std::unordered_map<uint8, std::vector<std::pair<uint32, int32>>> items;
std::unordered_map<uint8, std::vector<uint32>> items;
// int tab = AiFactory::GetPlayerSpecTab(bot);
uint32 blevel = bot->GetLevel();
@ -2229,17 +2228,13 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
if (slot == EQUIPMENT_SLOT_OFFHAND && bot->getClass() == CLASS_ROGUE &&
proto->Class != ITEM_CLASS_WEAPON)
continue;
int32 bestRandomProp = 0;
if (proto->RandomProperty || proto->RandomSuffix)
bestRandomProp = calculator.PickBestRandomPropertyId(itemId);
items[slot].push_back({itemId, bestRandomProp});
items[slot].push_back(itemId);
}
}
}
} while (items[slot].size() < 25 && desiredQuality-- > ITEM_QUALITY_POOR);
std::vector<std::pair<uint32, int32>>& ids = items[slot];
std::vector<uint32>& ids = items[slot];
if (ids.empty())
{
continue;
@ -2247,15 +2242,13 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
float bestScoreForSlot = -1;
uint32 bestItemForSlot = 0;
int32 bestRandomPropForSlot = 0;
for (int index = 0; index < ids.size(); index++)
{
uint32 newItemId = ids[index].first;
int32 newItemProp = ids[index].second;
uint32 newItemId = ids[index];
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(newItemId);
float cur_score = calculator.CalculateItem(newItemId, newItemProp, slot);
float cur_score = calculator.CalculateItem(newItemId, 0, slot);
if (cur_score > 0.0f && proto && proto->Class == ITEM_CLASS_ARMOR && sPlayerbotAIConfig.preferClassArmorType)
{
@ -2274,7 +2267,6 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
continue;
bestScoreForSlot = cur_score;
bestItemForSlot = newItemId;
bestRandomPropForSlot = newItemProp;
}
}
@ -2312,16 +2304,7 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
if (oldItem)
continue;
if (Item* equipped = bot->EquipNewItem(dest, bestItemForSlot, true))
{
if (bestRandomPropForSlot != 0)
{
uint8 equipSlot = equipped->GetSlot();
bot->_ApplyItemMods(equipped, equipSlot, false);
equipped->SetItemRandomProperties(bestRandomPropForSlot);
bot->_ApplyItemMods(equipped, equipSlot, true);
}
}
bot->EquipNewItem(dest, bestItemForSlot, true);
bot->AutoUnequipOffhandIfNeed();
// if (newItem)
// {
@ -2362,21 +2345,19 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
if (Item* oldItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
bot->DestroyItem(INVENTORY_SLOT_BAG_0, slot, true);
std::vector<std::pair<uint32, int32>>& ids = items[slot];
std::vector<uint32>& ids = items[slot];
if (ids.empty())
continue;
float bestScoreForSlot = -1;
uint32 bestItemForSlot = 0;
int32 bestRandomPropForSlot = 0;
for (int index = 0; index < ids.size(); index++)
{
uint32 newItemId = ids[index].first;
int32 newItemProp = ids[index].second;
uint32 newItemId = ids[index];
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(newItemId);
float cur_score = calculator.CalculateItem(newItemId, newItemProp, slot);
float cur_score = calculator.CalculateItem(newItemId, 0, slot);
if (cur_score > 0.0f && proto && proto->Class == ITEM_CLASS_ARMOR && sPlayerbotAIConfig.preferClassArmorType)
{
@ -2395,7 +2376,6 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
continue;
bestScoreForSlot = cur_score;
bestItemForSlot = newItemId;
bestRandomPropForSlot = newItemProp;
}
}
@ -2406,16 +2386,7 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
if (!CanEquipUnseenItem(slot, dest, bestItemForSlot))
continue;
if (Item* equipped = bot->EquipNewItem(dest, bestItemForSlot, true))
{
if (bestRandomPropForSlot != 0)
{
uint8 equipSlot = equipped->GetSlot();
bot->_ApplyItemMods(equipped, equipSlot, false);
equipped->SetItemRandomProperties(bestRandomPropForSlot);
bot->_ApplyItemMods(equipped, equipSlot, true);
}
}
bot->EquipNewItem(dest, bestItemForSlot, true);
bot->AutoUnequipOffhandIfNeed();
}
}

View File

@ -22,7 +22,6 @@
#include "GuildMgr.h"
#include "ObjectAccessor.h"
#include "ObjectGuid.h"
#include "ObjectMgr.h"
#include "PlayerbotAIConfig.h"
#include "PlayerbotRepository.h"
#include "PlayerbotFactory.h"
@ -482,6 +481,12 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
}
Player* master = botAI->GetMaster();
if (master)
{
ObjectGuid masterGuid = master->GetGUID();
if (master->GetGroup() && !master->GetGroup()->IsLeader(masterGuid))
master->GetGroup()->ChangeLeader(masterGuid);
}
Group* group = bot->GetGroup();
if (group)
@ -732,10 +737,7 @@ std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, Obje
bool addClassBot = sRandomPlayerbotMgr.IsAddclassBot(guid.GetCounter());
if (!addClassBot)
{
if (!(cmd == "refresh=raid" && sPlayerbotAIConfig.resetInstanceIdForAltBots))
return "ERROR: You can only use this command on addclass bots.";
}
return "ERROR: You can not use this command on non-addclass bot.";
if (!admin)
{
@ -1244,7 +1246,7 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
std::vector<std::string> chars = split(charnameStr, ',');
for (std::vector<std::string>::iterator i = chars.begin(); i != chars.end(); i++)
{
std::string s = *i;
std::string const s = *i;
if (!strcmp(cmd, "addaccount"))
{
@ -1253,13 +1255,7 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
if (!accountId)
{
// If not found, try to get account ID from character name
std::string charName = s;
if (!normalizePlayerName(charName))
{
messages.push_back("Neither account nor character '" + s + "' found");
continue;
}
ObjectGuid charGuid = sCharacterCache->GetCharacterGuidByName(charName);
ObjectGuid charGuid = sCharacterCache->GetCharacterGuidByName(s);
if (!charGuid)
{
messages.push_back("Neither account nor character '" + s + "' found");
@ -1287,11 +1283,6 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
else
{
// For regular add command, only add the specific character
if (!normalizePlayerName(s))
{
messages.push_back("Character '" + *i + "' not found");
continue;
}
ObjectGuid charGuid = sCharacterCache->GetCharacterGuidByName(s);
if (!charGuid)
{

View File

@ -160,7 +160,6 @@ void RandomItemMgr::Init()
BuildPotionCache();
BuildFoodCache();
BuildTradeCache();
LoadEnchantmentPool();
}
void RandomItemMgr::InitAfterAhBot()
@ -453,39 +452,6 @@ std::vector<uint32> RandomItemMgr::GetCachedEquipments(uint32 requiredLevel, uin
return equipCacheNew[requiredLevel][inventoryType];
}
void RandomItemMgr::LoadEnchantmentPool()
{
enchPoolCache.clear();
QueryResult result = WorldDatabase.Query("SELECT entry, ench FROM item_enchantment_template");
if (!result)
{
LOG_WARN("playerbots", "item_enchantment_template empty; bot autogear cannot evaluate random suffixes");
return;
}
uint32 count = 0;
do
{
Field* fields = result->Fetch();
uint32 entry = fields[0].Get<uint32>();
uint32 ench = fields[1].Get<uint32>();
enchPoolCache[entry].push_back(ench);
++count;
} while (result->NextRow());
LOG_INFO("playerbots", "Loaded {} item enchantment pool rows for bot autogear", count);
}
std::vector<uint32> const& RandomItemMgr::GetEnchantmentPool(uint32 entry) const
{
static std::vector<uint32> const empty;
auto it = enchPoolCache.find(entry);
if (it == enchPoolCache.end())
return empty;
return it->second;
}
bool RandomItemMgr::ShouldEquipArmorForSpec(uint8 playerclass, uint8 spec, ItemTemplate const* proto)
{
if (proto->InventoryType == INVTYPE_TABARD)

View File

@ -8,7 +8,6 @@
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <vector>
@ -173,11 +172,9 @@ public:
static bool IsUsedBySkill(ItemTemplate const* proto, uint32 skillId);
bool IsTestItem(uint32 itemId) { return itemForTest.find(itemId) != itemForTest.end(); }
std::vector<uint32> GetCachedEquipments(uint32 requiredLevel, uint32 inventoryType);
std::vector<uint32> const& GetEnchantmentPool(uint32 entry) const;
private:
void BuildRandomItemCache();
void LoadEnchantmentPool();
void BuildEquipCache();
void BuildEquipCacheNew();
void BuildItemInfoCache();
@ -220,8 +217,6 @@ private:
static std::set<uint32> itemCache;
// equipCacheNew[RequiredLevel][InventoryType]
std::map<uint32, std::map<uint32, std::vector<uint32>>> equipCacheNew;
// enchPoolCache[item_enchantment_template.entry] -> list of enchantment ids
std::unordered_map<uint32, std::vector<uint32>> enchPoolCache;
};
#define sRandomItemMgr RandomItemMgr::instance()

View File

@ -14,7 +14,6 @@
#include "ObjectMgr.h"
#include "PlayerbotAI.h"
#include "PlayerbotFactory.h"
#include "RandomItemMgr.h"
#include "SharedDefines.h"
#include "SpellAuraDefines.h"
#include "SpellMgr.h"
@ -191,53 +190,6 @@ void StatsWeightCalculator::CalculateRandomProperty(int32 randomPropertyId, uint
}
}
int32 StatsWeightCalculator::PickBestRandomPropertyId(uint32 itemId)
{
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
if (!proto)
return 0;
bool isSuffix = false;
uint32 poolEntry = proto->RandomProperty;
if (!poolEntry)
{
poolEntry = proto->RandomSuffix;
isSuffix = true;
}
if (!poolEntry)
return 0;
std::vector<uint32> const& pool = sRandomItemMgr.GetEnchantmentPool(poolEntry);
if (pool.empty())
return 0;
Reset();
GenerateWeights(player_);
int32 bestId = 0;
float bestScore = 0.0f;
for (uint32 enchId : pool)
{
int32 candidate = isSuffix ? -static_cast<int32>(enchId) : static_cast<int32>(enchId);
collector_->Reset();
CalculateRandomProperty(candidate, itemId);
float score = 0.0f;
for (uint32 i = 0; i < STATS_TYPE_MAX; ++i)
score += stats_weights_[i] * collector_->stats[i];
if (bestId == 0 || score > bestScore)
{
bestId = candidate;
bestScore = score;
}
}
collector_->Reset();
return bestId;
}
void StatsWeightCalculator::GenerateWeights(Player* player)
{
GenerateBasicWeights(player);

View File

@ -30,7 +30,6 @@ public:
void Reset();
float CalculateItem(uint32 itemId, int32 randomPropertyId = 0, int32 slot = -1);
float CalculateEnchant(uint32 enchantId);
int32 PickBestRandomPropertyId(uint32 itemId);
void SetOverflowPenalty(bool apply) { enable_overflow_penalty_ = apply; }
void SetItemSetBonus(bool apply) { enable_item_set_bonus_ = apply; }

View File

@ -147,6 +147,7 @@ bool PlayerbotAIConfig::Initialize()
tellWhenAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.TellWhenAvoidAoe", false);
randomGearLoweringChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomGearLoweringChance", 0.0f);
incrementalGearInit = sConfigMgr->GetOption<bool>("AiPlayerbot.IncrementalGearInit", true);
randomGearQualityLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomGearQualityLimit", 3);
randomGearScoreLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomGearScoreLimit", 0);
preferClassArmorType = sConfigMgr->GetOption<bool>("AiPlayerbot.PreferClassArmorType", false);
@ -214,7 +215,7 @@ bool PlayerbotAIConfig::Initialize()
attunementQuests);
LoadSet<std::set<uint32>>(
sConfigMgr->GetOption<std::string>("AiPlayerbot.UnobtainableItems", "12468,44869,44870,46978"),
sConfigMgr->GetOption<std::string>("AiPlayerbot.UnobtainableItems", "12468,46978"),
unobtainableItems);
botAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.BotAutologin", false);
@ -351,27 +352,32 @@ bool PlayerbotAIConfig::Initialize()
// does not depend on global chance
broadcastChanceGuildManagement = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceGuildManagement", 30000);
////////////////////////////
toxicLinksRepliesChance = sConfigMgr->GetOption<int32>("AiPlayerbot.ToxicLinksRepliesChance", 30); // 0-100
thunderfuryRepliesChance = sConfigMgr->GetOption<int32>("AiPlayerbot.ThunderfuryRepliesChance", 40); // 0-100
guildRepliesRate = sConfigMgr->GetOption<int32>("AiPlayerbot.GuildRepliesRate", 100); // 0-100
suggestDungeonsInLowerCaseRandomly =
sConfigMgr->GetOption<bool>("AiPlayerbot.SuggestDungeonsInLowerCaseRandomly", false);
////////////////////////// !CHAT
randomBotJoinBG = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotJoinBG", true);
randomBotAutoJoinBG = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotAutoJoinBG", false);
randomBotAutoJoinArenaBracket = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAutoJoinArenaBracket", 14);
randomBotAutoJoinArenaBracket = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAutoJoinArenaBracket", 7);
randomBotAutoJoinWSBrackets = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAutoJoinWSBrackets", "7");
randomBotAutoJoinABBrackets = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAutoJoinABBrackets", "6");
randomBotAutoJoinAVBrackets = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAutoJoinAVBrackets", "3");
randomBotAutoJoinEYBrackets = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAutoJoinEYBrackets", "2");
randomBotAutoJoinICBrackets = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAutoJoinICBrackets", "1");
randomBotAutoJoinICBrackets = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAutoJoinICBrackets", "0,1");
randomBotAutoJoinEYBrackets = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAutoJoinEYBrackets", "0,1,2");
randomBotAutoJoinAVBrackets = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAutoJoinAVBrackets", "0,1,2,3");
randomBotAutoJoinABBrackets = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAutoJoinABBrackets", "0,1,2,3,4,5,6");
randomBotAutoJoinWSBrackets = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAutoJoinWSBrackets", "0,1,2,3,4,5,6,7");
randomBotAutoJoinBGWSCount = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAutoJoinBGWSCount", 1);
randomBotAutoJoinBGABCount = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAutoJoinBGABCount", 1);
randomBotAutoJoinBGAVCount = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAutoJoinBGAVCount", 0);
randomBotAutoJoinBGEYCount = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAutoJoinBGEYCount", 1);
randomBotAutoJoinBGICCount = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAutoJoinBGICCount", 0);
randomBotAutoJoinBGEYCount = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAutoJoinBGEYCount", 0);
randomBotAutoJoinBGAVCount = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAutoJoinBGAVCount", 0);
randomBotAutoJoinBGABCount = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAutoJoinBGABCount", 0);
randomBotAutoJoinBGWSCount = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAutoJoinBGWSCount", 0);
randomBotAutoJoinBGRatedArena2v2Count =
sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAutoJoinBGRatedArena2v2Count", 0);
@ -387,6 +393,7 @@ bool PlayerbotAIConfig::Initialize()
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);
randomBotTeleLowerLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleLowerLevel", 1);
randomBotTeleHigherLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleHigherLevel", 3);
openGoSpell = sConfigMgr->GetOption<int32>("AiPlayerbot.OpenGoSpell", 6477);
@ -552,8 +559,6 @@ bool PlayerbotAIConfig::Initialize()
randomBotGuildSizeMax = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotGuildSizeMax", 15);
deleteRandomBotGuilds = sConfigMgr->GetOption<bool>("AiPlayerbot.DeleteRandomBotGuilds", false);
botSendMailEnabled = sConfigMgr->GetOption<bool>("AiPlayerbot.BotSendMailEnabled", true);
guildTaskEnabled = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableGuildTasks", false);
minGuildTaskChangeTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MinGuildTaskChangeTime", 3 * 24 * 3600);
maxGuildTaskChangeTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxGuildTaskChangeTime", 4 * 24 * 3600);
@ -576,8 +581,8 @@ bool PlayerbotAIConfig::Initialize()
disableRandomLevels = sConfigMgr->GetOption<bool>("AiPlayerbot.DisableRandomLevels", false);
randomBotRandomPassword = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotRandomPassword", true);
downgradeMaxLevelBot = sConfigMgr->GetOption<bool>("AiPlayerbot.DowngradeMaxLevelBot", true);
equipAndSpecPersistence = sConfigMgr->GetOption<bool>("AiPlayerbot.EquipAndSpecPersistence", true);
equipAndSpecPersistenceLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.EquipAndSpecPersistenceLevel", 1);
equipmentPersistence = sConfigMgr->GetOption<bool>("AiPlayerbot.EquipmentPersistence", false);
equipmentPersistenceLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.EquipmentPersistenceLevel", 80);
groupInvitationPermission = sConfigMgr->GetOption<int32>("AiPlayerbot.GroupInvitationPermission", 1);
keepAltsInGroup = sConfigMgr->GetOption<bool>("AiPlayerbot.KeepAltsInGroup", false);
allowSummonInCombat = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonInCombat", true);
@ -586,7 +591,6 @@ bool PlayerbotAIConfig::Initialize()
reviveBotWhenSummoned = sConfigMgr->GetOption<int32>("AiPlayerbot.ReviveBotWhenSummoned", 1);
botRepairWhenSummon = sConfigMgr->GetOption<bool>("AiPlayerbot.BotRepairWhenSummon", true);
autoInitOnly = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoInitOnly", false);
resetInstanceIdForAltBots = sConfigMgr->GetOption<bool>("AiPlayerbot.ResetInstanceIdForAltBots", false);
autoInitEquipLevelLimitRatio = sConfigMgr->GetOption<float>("AiPlayerbot.AutoInitEquipLevelLimitRatio", 1.0);
maxAddedBots = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxAddedBots", 40);
@ -665,7 +669,7 @@ bool PlayerbotAIConfig::Initialize()
dropObsoleteQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.DropObsoleteQuests", true);
allowLearnTrainerSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowLearnTrainerSpells", true);
autoPickTalents = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoPickTalents", true);
autoUpgradeEquip = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoUpgradeEquip", true);
autoUpgradeEquip = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoUpgradeEquip", false);
hunterWolfPet = sConfigMgr->GetOption<int32>("AiPlayerbot.HunterWolfPet", 0);
defaultPetStance = sConfigMgr->GetOption<int32>("AiPlayerbot.DefaultPetStance", 1);
petChatCommandDebug = sConfigMgr->GetOption<bool>("AiPlayerbot.PetChatCommandDebug", 0);

View File

@ -3,8 +3,8 @@
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_PLAYERBOTAICONFIG_H
#define _PLAYERBOT_PLAYERBOTAICONFIG_H
#ifndef _PLAYERBOT_PLAYERbotAICONFIG_H
#define _PLAYERBOT_PLAYERbotAICONFIG_H
#include <mutex>
#include <unordered_map>
@ -134,6 +134,7 @@ public:
std::vector<uint32> randomBotQuestIds;
uint32 randomBotTeleportDistance;
float randomGearLoweringChance;
bool incrementalGearInit;
int32 randomGearQualityLimit;
int32 randomGearScoreLimit;
bool preferClassArmorType;
@ -226,6 +227,10 @@ public:
uint32 guildRepliesRate;
bool suggestDungeonsInLowerCaseRandomly;
// --
bool randomBotJoinBG;
bool randomBotAutoJoinBG;
@ -247,6 +252,7 @@ public:
uint32 randomBotAutoJoinBGRatedArena3v3Count;
uint32 randomBotAutoJoinBGRatedArena5v5Count;
bool randomBotLoginAtStartup;
uint32 randomBotTeleLowerLevel, randomBotTeleHigherLevel;
std::map<uint32, std::pair<uint32, uint32>> zoneBrackets;
bool logInGroupOnly, logValuesPerTick;
@ -292,7 +298,6 @@ public:
float periodicOnlineOfflineRatio;
bool gearscorecheck;
bool randomBotPreQuests;
bool botSendMailEnabled;
bool guildTaskEnabled;
uint32 minGuildTaskChangeTime, maxGuildTaskChangeTime;
@ -389,8 +394,8 @@ public:
uint32 selfBotLevel;
bool downgradeMaxLevelBot;
bool equipAndSpecPersistence;
int32 equipAndSpecPersistenceLevel;
bool equipmentPersistence;
int32 equipmentPersistenceLevel;
int32 groupInvitationPermission;
bool keepAltsInGroup = false;
bool KeepAltsInGroup() const { return keepAltsInGroup; }
@ -400,7 +405,6 @@ public:
int reviveBotWhenSummoned;
bool botRepairWhenSummon;
bool autoInitOnly;
bool resetInstanceIdForAltBots;
float autoInitEquipLevelLimitRatio;
int32 maxAddedBots;
int32 addClassCommand;

View File

@ -242,7 +242,6 @@ public:
}
group->ChangeLeader(newLeader->GetGUID());
group->SendUpdate();
LOG_DEBUG("playerbots", "GroupSetLeaderOperation: Changed leader to {}", newLeader->GetName());
return true;
}