mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-21 16:09:26 +02:00
Compare commits
No commits in common. "92fa97c3aa3d9391b895f525956b0f07678adcaa" and "4a63ee37e29f44010a0c926d33c114816abc2946" have entirely different histories.
92fa97c3aa
...
4a63ee37e2
File diff suppressed because it is too large
Load Diff
@ -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);
|
|
||||||
@ -12,8 +12,8 @@ bool AutoMaintenanceOnLevelupAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
AutoPickTalents();
|
AutoPickTalents();
|
||||||
AutoLearnSpell();
|
AutoLearnSpell();
|
||||||
AutoTeleportForLevel();
|
|
||||||
AutoUpgradeEquip();
|
AutoUpgradeEquip();
|
||||||
|
AutoTeleportForLevel();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -21,11 +21,13 @@ bool AutoMaintenanceOnLevelupAction::Execute(Event /*event*/)
|
|||||||
void AutoMaintenanceOnLevelupAction::AutoTeleportForLevel()
|
void AutoMaintenanceOnLevelupAction::AutoTeleportForLevel()
|
||||||
{
|
{
|
||||||
if (!sPlayerbotAIConfig.autoTeleportForLevel || !sRandomPlayerbotMgr.IsRandomBot(bot))
|
if (!sPlayerbotAIConfig.autoTeleportForLevel || !sRandomPlayerbotMgr.IsRandomBot(bot))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if (botAI->HasRealPlayerMaster())
|
if (botAI->HasRealPlayerMaster())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
sRandomPlayerbotMgr.RandomTeleportForLevel(bot);
|
sRandomPlayerbotMgr.RandomTeleportForLevel(bot);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -87,17 +89,21 @@ void AutoMaintenanceOnLevelupAction::LearnQuestSpells(std::ostringstream* out)
|
|||||||
{
|
{
|
||||||
Quest const* quest = i->second;
|
Quest const* quest = i->second;
|
||||||
|
|
||||||
if (!quest->GetRequiredClasses() || quest->IsRepeatable() || quest->GetMinLevel() < 10 ||
|
// only process class-specific quests to learn class-related spells, cuz
|
||||||
quest->GetMinLevel() > bot->GetLevel())
|
// we don't want all these bunch of entries to be handled!
|
||||||
{
|
if (!quest->GetRequiredClasses())
|
||||||
continue;
|
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) ||
|
if (!bot->SatisfyQuestClass(quest, false) || !bot->SatisfyQuestRace(quest, false) ||
|
||||||
!bot->SatisfyQuestSkill(quest, false))
|
!bot->SatisfyQuestSkill(quest, false))
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
// use the same logic and impl from Player::learnQuestRewardedSpells
|
||||||
|
|
||||||
int32 spellId = quest->GetRewSpellCast();
|
int32 spellId = quest->GetRewSpellCast();
|
||||||
if (!spellId)
|
if (!spellId)
|
||||||
@ -107,26 +113,31 @@ void AutoMaintenanceOnLevelupAction::LearnQuestSpells(std::ostringstream* out)
|
|||||||
if (!spellInfo)
|
if (!spellInfo)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// xinef: find effect with learn spell and check if we have this spell
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||||
{
|
{
|
||||||
if (spellInfo->Effects[i].Effect == SPELL_EFFECT_LEARN_SPELL && spellInfo->Effects[i].TriggerSpell &&
|
if (spellInfo->Effects[i].Effect == SPELL_EFFECT_LEARN_SPELL && spellInfo->Effects[i].TriggerSpell &&
|
||||||
!bot->HasSpell(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 (SpellInfo const* triggeredInfo = sSpellMgr->GetSpellInfo(spellInfo->Effects[i].TriggerSpell))
|
||||||
if (triggeredInfo->Effects[0].Effect == SPELL_EFFECT_TRADE_SKILL)
|
if (triggeredInfo->Effects[0].Effect == SPELL_EFFECT_TRADE_SKILL)
|
||||||
break;
|
break; // pussywizard: break and not cast the spell (found is false)
|
||||||
|
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// xinef: we know the spell, continue
|
||||||
if (!found)
|
if (!found)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
bot->CastSpell(bot, spellId, true);
|
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();
|
uint32 rewSpellId = quest->GetRewSpell();
|
||||||
if (rewSpellId)
|
if (rewSpellId)
|
||||||
{
|
{
|
||||||
@ -156,11 +167,12 @@ std::string const AutoMaintenanceOnLevelupAction::FormatSpell(SpellInfo const* s
|
|||||||
|
|
||||||
void AutoMaintenanceOnLevelupAction::AutoUpgradeEquip()
|
void AutoMaintenanceOnLevelupAction::AutoUpgradeEquip()
|
||||||
{
|
{
|
||||||
if (!sRandomPlayerbotMgr.IsRandomBot(bot))
|
if (!sPlayerbotAIConfig.autoUpgradeEquip || !sRandomPlayerbotMgr.IsRandomBot(bot))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PlayerbotFactory factory(bot, bot->GetLevel());
|
PlayerbotFactory factory(bot, bot->GetLevel());
|
||||||
|
|
||||||
|
// Clean up old consumables before adding new ones
|
||||||
factory.CleanupConsumables();
|
factory.CleanupConsumables();
|
||||||
|
|
||||||
factory.InitAmmo();
|
factory.InitAmmo();
|
||||||
@ -169,6 +181,9 @@ void AutoMaintenanceOnLevelupAction::AutoUpgradeEquip()
|
|||||||
factory.InitConsumables();
|
factory.InitConsumables();
|
||||||
factory.InitPotions();
|
factory.InitPotions();
|
||||||
|
|
||||||
if (sPlayerbotAIConfig.autoUpgradeEquip)
|
if (!sPlayerbotAIConfig.equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel)
|
||||||
|
{
|
||||||
|
if (sPlayerbotAIConfig.incrementalGearInit)
|
||||||
factory.InitEquipment(true);
|
factory.InitEquipment(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -154,11 +154,9 @@ void EquipAction::EquipItem(Item* item)
|
|||||||
calculator.SetOverflowPenalty(false);
|
calculator.SetOverflowPenalty(false);
|
||||||
|
|
||||||
// Calculate item scores once and store them
|
// Calculate item scores once and store them
|
||||||
float newItemScore = calculator.CalculateItem(itemId, item->GetItemRandomPropertyId());
|
float newItemScore = calculator.CalculateItem(itemId);
|
||||||
float mainHandScore = mainHandItem
|
float mainHandScore = mainHandItem ? calculator.CalculateItem(mainHandItem->GetTemplate()->ItemId) : 0.0f;
|
||||||
? calculator.CalculateItem(mainHandItem->GetTemplate()->ItemId, mainHandItem->GetItemRandomPropertyId()) : 0.0f;
|
float offHandScore = offHandItem ? calculator.CalculateItem(offHandItem->GetTemplate()->ItemId) : 0.0f;
|
||||||
float offHandScore = offHandItem
|
|
||||||
? calculator.CalculateItem(offHandItem->GetTemplate()->ItemId, offHandItem->GetItemRandomPropertyId()) : 0.0f;
|
|
||||||
|
|
||||||
// Determine where this weapon can go
|
// Determine where this weapon can go
|
||||||
bool canGoMain = (invType == INVTYPE_WEAPON ||
|
bool canGoMain = (invType == INVTYPE_WEAPON ||
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
#include "GenericSpellActions.h"
|
#include "GenericSpellActions.h"
|
||||||
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <unordered_set>
|
|
||||||
|
|
||||||
#include "Event.h"
|
#include "Event.h"
|
||||||
#include "ItemTemplate.h"
|
#include "ItemTemplate.h"
|
||||||
@ -24,116 +23,6 @@
|
|||||||
using ai::buff::MakeAuraQualifierForBuff;
|
using ai::buff::MakeAuraQualifierForBuff;
|
||||||
using ai::spell::HasSpellOrCategoryCooldown;
|
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)
|
CastSpellAction::CastSpellAction(PlayerbotAI* botAI, std::string const spell)
|
||||||
: Action(botAI, spell), range(botAI->GetRange("spell")), spell(spell) {}
|
: Action(botAI, spell), range(botAI->GetRange("spell")), spell(spell) {}
|
||||||
|
|
||||||
@ -540,109 +429,52 @@ bool UseTrinketAction::UseTrinket(Item* item)
|
|||||||
|
|
||||||
uint8 bagIndex = item->GetBagSlot();
|
uint8 bagIndex = item->GetBagSlot();
|
||||||
uint8 slot = item->GetSlot();
|
uint8 slot = item->GetSlot();
|
||||||
|
// uint8 spell_index = 0; //not used, line marked for removal.
|
||||||
uint8 cast_count = 1;
|
uint8 cast_count = 1;
|
||||||
ObjectGuid item_guid = item->GetGUID();
|
ObjectGuid item_guid = item->GetGUID();
|
||||||
uint32 glyphIndex = 0;
|
uint32 glyphIndex = 0;
|
||||||
uint8 castFlags = 0;
|
uint8 castFlags = 0;
|
||||||
uint32 targetFlag = TARGET_FLAG_NONE;
|
uint32 targetFlag = TARGET_FLAG_NONE;
|
||||||
uint32 spellId = 0;
|
uint32 spellId = 0;
|
||||||
int32 itemSpellCooldown = 0;
|
|
||||||
uint32 itemSpellCategory = 0;
|
|
||||||
int32 itemSpellCategoryCooldown = 0;
|
|
||||||
|
|
||||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
||||||
{
|
{
|
||||||
if (item->GetTemplate()->Spells[i].SpellId > 0 &&
|
if (item->GetTemplate()->Spells[i].SpellId > 0 &&
|
||||||
item->GetTemplate()->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE)
|
item->GetTemplate()->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE)
|
||||||
{
|
{
|
||||||
spellId = item->GetTemplate()->Spells[i].SpellId;
|
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);
|
const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||||
|
|
||||||
if (!spellInfo || !spellInfo->IsPositive())
|
if (!spellInfo || !spellInfo->IsPositive())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool applyAura = false;
|
bool applyAura = false;
|
||||||
bool restoresMana = false;
|
|
||||||
bool improvesManaEfficiency = false;
|
|
||||||
bool defensiveTankEffect = false;
|
|
||||||
for (int i = 0; i < MAX_SPELL_EFFECTS; i++)
|
for (int i = 0; i < MAX_SPELL_EFFECTS; i++)
|
||||||
{
|
{
|
||||||
const SpellEffectInfo& effectInfo = spellInfo->Effects[i];
|
const SpellEffectInfo& effectInfo = spellInfo->Effects[i];
|
||||||
if (effectInfo.Effect == SPELL_EFFECT_APPLY_AURA)
|
if (effectInfo.Effect == SPELL_EFFECT_APPLY_AURA)
|
||||||
|
{
|
||||||
applyAura = true;
|
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;
|
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)
|
if (!spellId)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -651,25 +483,7 @@ bool UseTrinketAction::UseTrinket(Item* item)
|
|||||||
|
|
||||||
targetFlag = TARGET_FLAG_NONE;
|
targetFlag = TARGET_FLAG_NONE;
|
||||||
packet << targetFlag << bot->GetPackGUID();
|
packet << targetFlag << bot->GetPackGUID();
|
||||||
|
|
||||||
bot->GetSession()->HandleUseItemOpcode(packet);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -334,10 +334,6 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool UseTrinket(Item* trinket);
|
bool UseTrinket(Item* trinket);
|
||||||
|
|
||||||
private:
|
|
||||||
std::unordered_map<uint64, uint32> trinketItemCooldownExpiries;
|
|
||||||
std::unordered_map<uint32, uint32> trinketCategoryCooldownExpiries;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastSpellOnEnemyHealerAction : public CastSpellAction
|
class CastSpellOnEnemyHealerAction : public CastSpellAction
|
||||||
|
|||||||
@ -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);
|
PlayerbotRepository::instance().Reset(botAI);
|
||||||
botAI->ResetStrategies(false);
|
botAI->ResetStrategies(false);
|
||||||
botAI->TellMaster("AI was reset to defaults");
|
botAI->TellMaster("AI was reset to defaults");
|
||||||
|
|||||||
@ -34,23 +34,24 @@ bool SendMailAction::Execute(Event event)
|
|||||||
Player* receiver = GetMaster();
|
Player* receiver = GetMaster();
|
||||||
Player* tellTo = receiver;
|
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)
|
if (!receiver)
|
||||||
receiver = event.getOwner();
|
receiver = event.getOwner();
|
||||||
|
|
||||||
if (!receiver || receiver == bot)
|
if (!receiver || receiver == bot)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!tellTo)
|
if (!tellTo)
|
||||||
tellTo = receiver;
|
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)
|
if (!mailboxFound && !randomBot)
|
||||||
{
|
{
|
||||||
bot->Whisper(PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
bot->Whisper(PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||||
|
|||||||
@ -16,7 +16,7 @@ void WorldPacketHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
|||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("uninvite guid", { NextAction("uninvite", relevance) }));
|
new TriggerNode("uninvite guid", { NextAction("uninvite", relevance) }));
|
||||||
triggers.push_back(
|
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(
|
triggers.push_back(new TriggerNode(
|
||||||
"not enough money", { NextAction("tell not enough money", relevance) }));
|
"not enough money", { NextAction("tell not enough money", relevance) }));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
|
|||||||
@ -38,16 +38,3 @@ bool BwlUseHourglassSandAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
return botAI->CastSpell(SPELL_HOURGLASS_SAND, bot);
|
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);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -29,11 +29,4 @@ public:
|
|||||||
bool Execute(Event event) override;
|
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
|
#endif
|
||||||
|
|||||||
@ -13,14 +13,12 @@ public:
|
|||||||
creators["bwl check onyxia scale cloak"] = &RaidBwlActionContext::bwl_check_onyxia_scale_cloak;
|
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 turn off suppression device"] = &RaidBwlActionContext::bwl_turn_off_suppression_device;
|
||||||
creators["bwl use hourglass sand"] = &RaidBwlActionContext::bwl_use_hourglass_sand;
|
creators["bwl use hourglass sand"] = &RaidBwlActionContext::bwl_use_hourglass_sand;
|
||||||
creators["bwl nefarian fear ward"] = &RaidBwlActionContext::bwl_nefarian_fear_ward;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Action* bwl_check_onyxia_scale_cloak(PlayerbotAI* botAI) { return new BwlOnyxiaScaleCloakAuraCheckAction(botAI); }
|
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_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_use_hourglass_sand(PlayerbotAI* botAI) { return new BwlUseHourglassSandAction(botAI); }
|
||||||
static Action* bwl_nefarian_fear_ward(PlayerbotAI* botAI) { return new BwlNefarianFearWardAction(botAI); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -11,15 +11,11 @@ public:
|
|||||||
{
|
{
|
||||||
creators["bwl suppression device"] = &RaidBwlTriggerContext::bwl_suppression_device;
|
creators["bwl suppression device"] = &RaidBwlTriggerContext::bwl_suppression_device;
|
||||||
creators["bwl affliction bronze"] = &RaidBwlTriggerContext::bwl_affliction_bronze;
|
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:
|
private:
|
||||||
static Trigger* bwl_suppression_device(PlayerbotAI* ai) { return new BwlSuppressionDeviceTrigger(ai); }
|
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_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
|
#endif
|
||||||
|
|||||||
@ -10,10 +10,4 @@ void RaidBwlStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
|
|
||||||
triggers.push_back(new TriggerNode("bwl affliction bronze", {
|
triggers.push_back(new TriggerNode("bwl affliction bronze", {
|
||||||
NextAction("bwl use hourglass sand", ACTION_RAID) }));
|
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) }));
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,24 +27,3 @@ bool BwlAfflictionBronzeTrigger::IsActive()
|
|||||||
{
|
{
|
||||||
return bot->HasAura(SPELL_BROOD_AFFLICTION_BRONZE);
|
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);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -21,20 +21,4 @@ public:
|
|||||||
bool IsActive() override;
|
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
|
#endif
|
||||||
|
|||||||
@ -12,10 +12,7 @@ namespace BlackwingLairHelpers
|
|||||||
|
|
||||||
// Chromaggus
|
// Chromaggus
|
||||||
SPELL_BROOD_AFFLICTION_BRONZE = 23170,
|
SPELL_BROOD_AFFLICTION_BRONZE = 23170,
|
||||||
SPELL_HOURGLASS_SAND = 23645,
|
SPELL_HOURGLASS_SAND = 23645
|
||||||
|
|
||||||
// Nefarian
|
|
||||||
SPELL_WILD_MAGIC = 23410
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BlackwingLairGameObjects
|
enum BlackwingLairGameObjects
|
||||||
|
|||||||
@ -552,8 +552,9 @@ void PlayerbotFactory::Prepare()
|
|||||||
void PlayerbotFactory::Randomize(bool incremental)
|
void PlayerbotFactory::Randomize(bool incremental)
|
||||||
{
|
{
|
||||||
// if (sPlayerbotAIConfig.disableRandomLevels)
|
// if (sPlayerbotAIConfig.disableRandomLevels)
|
||||||
|
// {
|
||||||
// return;
|
// return;
|
||||||
|
// }
|
||||||
LOG_DEBUG("playerbots", "{} randomizing {} (level {} class = {})...", (incremental ? "Incremental" : "Full"),
|
LOG_DEBUG("playerbots", "{} randomizing {} (level {} class = {})...", (incremental ? "Incremental" : "Full"),
|
||||||
bot->GetName().c_str(), level, bot->getClass());
|
bot->GetName().c_str(), level, bot->getClass());
|
||||||
// LOG_DEBUG("playerbots", "Preparing to {} randomize...", (incremental ? "incremental" : "full"));
|
// LOG_DEBUG("playerbots", "Preparing to {} randomize...", (incremental ? "incremental" : "full"));
|
||||||
@ -561,23 +562,17 @@ void PlayerbotFactory::Randomize(bool incremental)
|
|||||||
LOG_DEBUG("playerbots", "Resetting player...");
|
LOG_DEBUG("playerbots", "Resetting player...");
|
||||||
PerfMonitorOperation* pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Reset");
|
PerfMonitorOperation* pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Reset");
|
||||||
|
|
||||||
if (!sPlayerbotAIConfig.equipAndSpecPersistence ||
|
if (!PlayerbotAIConfig::instance().equipmentPersistence || level < PlayerbotAIConfig::instance().equipmentPersistenceLevel)
|
||||||
level < sPlayerbotAIConfig.equipAndSpecPersistenceLevel)
|
|
||||||
{
|
|
||||||
bot->resetTalents(true);
|
bot->resetTalents(true);
|
||||||
}
|
|
||||||
|
|
||||||
if (!incremental)
|
if (!incremental)
|
||||||
{
|
{
|
||||||
ClearSkills();
|
ClearSkills();
|
||||||
ClearSpells();
|
ClearSpells();
|
||||||
ResetQuests();
|
ResetQuests();
|
||||||
if (!sPlayerbotAIConfig.equipAndSpecPersistence ||
|
if (!PlayerbotAIConfig::instance().equipmentPersistence || level < PlayerbotAIConfig::instance().equipmentPersistenceLevel)
|
||||||
level < sPlayerbotAIConfig.equipAndSpecPersistenceLevel)
|
|
||||||
{
|
|
||||||
ClearAllItems();
|
ClearAllItems();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ClearInventory();
|
ClearInventory();
|
||||||
bot->RemoveAllSpellCooldown();
|
bot->RemoveAllSpellCooldown();
|
||||||
UnbindInstance();
|
UnbindInstance();
|
||||||
@ -627,8 +622,8 @@ void PlayerbotFactory::Randomize(bool incremental)
|
|||||||
|
|
||||||
pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Talents");
|
pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Talents");
|
||||||
LOG_DEBUG("playerbots", "Initializing talents...");
|
LOG_DEBUG("playerbots", "Initializing talents...");
|
||||||
if (!incremental || !sPlayerbotAIConfig.equipAndSpecPersistence ||
|
if (!incremental || !sPlayerbotAIConfig.equipmentPersistence ||
|
||||||
bot->GetLevel() < sPlayerbotAIConfig.equipAndSpecPersistenceLevel)
|
bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel)
|
||||||
{
|
{
|
||||||
uint32 specIndex = InitTalentsTree();
|
uint32 specIndex = InitTalentsTree();
|
||||||
sRandomPlayerbotMgr.SetValue(bot->GetGUID().GetCounter(), "specNo", specIndex + 1);
|
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");
|
pmo = sPerfMonitor.start(PERF_MON_RNDBOT, "PlayerbotFactory_Equip");
|
||||||
LOG_DEBUG("playerbots", "Initializing equipmemt...");
|
LOG_DEBUG("playerbots", "Initializing equipmemt...");
|
||||||
if (!incremental || !sPlayerbotAIConfig.equipAndSpecPersistence ||
|
if (!incremental || !sPlayerbotAIConfig.equipmentPersistence ||
|
||||||
bot->GetLevel() < sPlayerbotAIConfig.equipAndSpecPersistenceLevel)
|
bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel)
|
||||||
{
|
{
|
||||||
|
if (sPlayerbotAIConfig.incrementalGearInit || !incremental)
|
||||||
InitEquipment(incremental, incremental ? false : sPlayerbotAIConfig.twoRoundsGearInit);
|
InitEquipment(incremental, incremental ? false : sPlayerbotAIConfig.twoRoundsGearInit);
|
||||||
}
|
}
|
||||||
// bot->SaveToDB(false, false);
|
// bot->SaveToDB(false, false);
|
||||||
@ -815,8 +811,7 @@ void PlayerbotFactory::Randomize(bool incremental)
|
|||||||
void PlayerbotFactory::Refresh()
|
void PlayerbotFactory::Refresh()
|
||||||
{
|
{
|
||||||
// Prepare();
|
// Prepare();
|
||||||
// if (!sPlayerbotAIConfig.equipAndSpecPersistence ||
|
// if (!sPlayerbotAIConfig.equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel)
|
||||||
// bot->GetLevel() < sPlayerbotAIConfig.equipAndSpecPersistenceLevel)
|
|
||||||
// {
|
// {
|
||||||
// InitEquipment(true);
|
// InitEquipment(true);
|
||||||
// }
|
// }
|
||||||
@ -836,13 +831,14 @@ void PlayerbotFactory::Refresh()
|
|||||||
InitSpecialSpells();
|
InitSpecialSpells();
|
||||||
InitMounts();
|
InitMounts();
|
||||||
InitKeyring();
|
InitKeyring();
|
||||||
if (!sPlayerbotAIConfig.equipAndSpecPersistence ||
|
if (!sPlayerbotAIConfig.equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel)
|
||||||
bot->GetLevel() < sPlayerbotAIConfig.equipAndSpecPersistenceLevel)
|
|
||||||
{
|
{
|
||||||
InitTalentsTree(true, true, true);
|
InitTalentsTree(true, true, true);
|
||||||
}
|
}
|
||||||
if (bot->GetLevel() >= sPlayerbotAIConfig.minEnchantingBotLevel)
|
if (bot->GetLevel() >= sPlayerbotAIConfig.minEnchantingBotLevel)
|
||||||
|
{
|
||||||
ApplyEnchantAndGemsNew();
|
ApplyEnchantAndGemsNew();
|
||||||
|
}
|
||||||
bot->DurabilityRepairAll(false, 1.0f, false);
|
bot->DurabilityRepairAll(false, 1.0f, false);
|
||||||
if (bot->isDead())
|
if (bot->isDead())
|
||||||
bot->ResurrectPlayer(1.0f, false);
|
bot->ResurrectPlayer(1.0f, false);
|
||||||
@ -2041,6 +2037,9 @@ void Shuffle(std::vector<uint32>& items)
|
|||||||
|
|
||||||
void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
|
void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
|
||||||
{
|
{
|
||||||
|
if (incremental && !sPlayerbotAIConfig.incrementalGearInit)
|
||||||
|
return;
|
||||||
|
|
||||||
if (level < 5)
|
if (level < 5)
|
||||||
{
|
{
|
||||||
// original items
|
// original items
|
||||||
@ -2082,7 +2081,7 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
|
|||||||
return;
|
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);
|
// int tab = AiFactory::GetPlayerSpecTab(bot);
|
||||||
|
|
||||||
uint32 blevel = bot->GetLevel();
|
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 &&
|
if (slot == EQUIPMENT_SLOT_OFFHAND && bot->getClass() == CLASS_ROGUE &&
|
||||||
proto->Class != ITEM_CLASS_WEAPON)
|
proto->Class != ITEM_CLASS_WEAPON)
|
||||||
continue;
|
continue;
|
||||||
|
items[slot].push_back(itemId);
|
||||||
int32 bestRandomProp = 0;
|
|
||||||
if (proto->RandomProperty || proto->RandomSuffix)
|
|
||||||
bestRandomProp = calculator.PickBestRandomPropertyId(itemId);
|
|
||||||
items[slot].push_back({itemId, bestRandomProp});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (items[slot].size() < 25 && desiredQuality-- > ITEM_QUALITY_POOR);
|
} 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())
|
if (ids.empty())
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@ -2247,15 +2242,13 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
|
|||||||
|
|
||||||
float bestScoreForSlot = -1;
|
float bestScoreForSlot = -1;
|
||||||
uint32 bestItemForSlot = 0;
|
uint32 bestItemForSlot = 0;
|
||||||
int32 bestRandomPropForSlot = 0;
|
|
||||||
for (int index = 0; index < ids.size(); index++)
|
for (int index = 0; index < ids.size(); index++)
|
||||||
{
|
{
|
||||||
uint32 newItemId = ids[index].first;
|
uint32 newItemId = ids[index];
|
||||||
int32 newItemProp = ids[index].second;
|
|
||||||
|
|
||||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(newItemId);
|
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)
|
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;
|
continue;
|
||||||
bestScoreForSlot = cur_score;
|
bestScoreForSlot = cur_score;
|
||||||
bestItemForSlot = newItemId;
|
bestItemForSlot = newItemId;
|
||||||
bestRandomPropForSlot = newItemProp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2312,16 +2304,7 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
|
|||||||
if (oldItem)
|
if (oldItem)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (Item* equipped = bot->EquipNewItem(dest, bestItemForSlot, true))
|
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->AutoUnequipOffhandIfNeed();
|
bot->AutoUnequipOffhandIfNeed();
|
||||||
// if (newItem)
|
// if (newItem)
|
||||||
// {
|
// {
|
||||||
@ -2362,21 +2345,19 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
|
|||||||
if (Item* oldItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
if (Item* oldItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
||||||
bot->DestroyItem(INVENTORY_SLOT_BAG_0, slot, true);
|
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())
|
if (ids.empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
float bestScoreForSlot = -1;
|
float bestScoreForSlot = -1;
|
||||||
uint32 bestItemForSlot = 0;
|
uint32 bestItemForSlot = 0;
|
||||||
int32 bestRandomPropForSlot = 0;
|
|
||||||
for (int index = 0; index < ids.size(); index++)
|
for (int index = 0; index < ids.size(); index++)
|
||||||
{
|
{
|
||||||
uint32 newItemId = ids[index].first;
|
uint32 newItemId = ids[index];
|
||||||
int32 newItemProp = ids[index].second;
|
|
||||||
|
|
||||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(newItemId);
|
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)
|
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;
|
continue;
|
||||||
bestScoreForSlot = cur_score;
|
bestScoreForSlot = cur_score;
|
||||||
bestItemForSlot = newItemId;
|
bestItemForSlot = newItemId;
|
||||||
bestRandomPropForSlot = newItemProp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2406,16 +2386,7 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
|
|||||||
if (!CanEquipUnseenItem(slot, dest, bestItemForSlot))
|
if (!CanEquipUnseenItem(slot, dest, bestItemForSlot))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (Item* equipped = bot->EquipNewItem(dest, bestItemForSlot, true))
|
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->AutoUnequipOffhandIfNeed();
|
bot->AutoUnequipOffhandIfNeed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,6 @@
|
|||||||
#include "GuildMgr.h"
|
#include "GuildMgr.h"
|
||||||
#include "ObjectAccessor.h"
|
#include "ObjectAccessor.h"
|
||||||
#include "ObjectGuid.h"
|
#include "ObjectGuid.h"
|
||||||
#include "ObjectMgr.h"
|
|
||||||
#include "PlayerbotAIConfig.h"
|
#include "PlayerbotAIConfig.h"
|
||||||
#include "PlayerbotRepository.h"
|
#include "PlayerbotRepository.h"
|
||||||
#include "PlayerbotFactory.h"
|
#include "PlayerbotFactory.h"
|
||||||
@ -482,6 +481,12 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Player* master = botAI->GetMaster();
|
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();
|
Group* group = bot->GetGroup();
|
||||||
if (group)
|
if (group)
|
||||||
@ -732,10 +737,7 @@ std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, Obje
|
|||||||
bool addClassBot = sRandomPlayerbotMgr.IsAddclassBot(guid.GetCounter());
|
bool addClassBot = sRandomPlayerbotMgr.IsAddclassBot(guid.GetCounter());
|
||||||
|
|
||||||
if (!addClassBot)
|
if (!addClassBot)
|
||||||
{
|
return "ERROR: You can not use this command on non-addclass bot.";
|
||||||
if (!(cmd == "refresh=raid" && sPlayerbotAIConfig.resetInstanceIdForAltBots))
|
|
||||||
return "ERROR: You can only use this command on addclass bots.";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!admin)
|
if (!admin)
|
||||||
{
|
{
|
||||||
@ -1244,7 +1246,7 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
|
|||||||
std::vector<std::string> chars = split(charnameStr, ',');
|
std::vector<std::string> chars = split(charnameStr, ',');
|
||||||
for (std::vector<std::string>::iterator i = chars.begin(); i != chars.end(); i++)
|
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"))
|
if (!strcmp(cmd, "addaccount"))
|
||||||
{
|
{
|
||||||
@ -1253,13 +1255,7 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
|
|||||||
if (!accountId)
|
if (!accountId)
|
||||||
{
|
{
|
||||||
// If not found, try to get account ID from character name
|
// If not found, try to get account ID from character name
|
||||||
std::string charName = s;
|
ObjectGuid charGuid = sCharacterCache->GetCharacterGuidByName(s);
|
||||||
if (!normalizePlayerName(charName))
|
|
||||||
{
|
|
||||||
messages.push_back("Neither account nor character '" + s + "' found");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ObjectGuid charGuid = sCharacterCache->GetCharacterGuidByName(charName);
|
|
||||||
if (!charGuid)
|
if (!charGuid)
|
||||||
{
|
{
|
||||||
messages.push_back("Neither account nor character '" + s + "' found");
|
messages.push_back("Neither account nor character '" + s + "' found");
|
||||||
@ -1287,11 +1283,6 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// For regular add command, only add the specific character
|
// 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);
|
ObjectGuid charGuid = sCharacterCache->GetCharacterGuidByName(s);
|
||||||
if (!charGuid)
|
if (!charGuid)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -160,7 +160,6 @@ void RandomItemMgr::Init()
|
|||||||
BuildPotionCache();
|
BuildPotionCache();
|
||||||
BuildFoodCache();
|
BuildFoodCache();
|
||||||
BuildTradeCache();
|
BuildTradeCache();
|
||||||
LoadEnchantmentPool();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RandomItemMgr::InitAfterAhBot()
|
void RandomItemMgr::InitAfterAhBot()
|
||||||
@ -453,39 +452,6 @@ std::vector<uint32> RandomItemMgr::GetCachedEquipments(uint32 requiredLevel, uin
|
|||||||
return equipCacheNew[requiredLevel][inventoryType];
|
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)
|
bool RandomItemMgr::ShouldEquipArmorForSpec(uint8 playerclass, uint8 spec, ItemTemplate const* proto)
|
||||||
{
|
{
|
||||||
if (proto->InventoryType == INVTYPE_TABARD)
|
if (proto->InventoryType == INVTYPE_TABARD)
|
||||||
|
|||||||
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <unordered_map>
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -173,11 +172,9 @@ public:
|
|||||||
static bool IsUsedBySkill(ItemTemplate const* proto, uint32 skillId);
|
static bool IsUsedBySkill(ItemTemplate const* proto, uint32 skillId);
|
||||||
bool IsTestItem(uint32 itemId) { return itemForTest.find(itemId) != itemForTest.end(); }
|
bool IsTestItem(uint32 itemId) { return itemForTest.find(itemId) != itemForTest.end(); }
|
||||||
std::vector<uint32> GetCachedEquipments(uint32 requiredLevel, uint32 inventoryType);
|
std::vector<uint32> GetCachedEquipments(uint32 requiredLevel, uint32 inventoryType);
|
||||||
std::vector<uint32> const& GetEnchantmentPool(uint32 entry) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void BuildRandomItemCache();
|
void BuildRandomItemCache();
|
||||||
void LoadEnchantmentPool();
|
|
||||||
void BuildEquipCache();
|
void BuildEquipCache();
|
||||||
void BuildEquipCacheNew();
|
void BuildEquipCacheNew();
|
||||||
void BuildItemInfoCache();
|
void BuildItemInfoCache();
|
||||||
@ -220,8 +217,6 @@ private:
|
|||||||
static std::set<uint32> itemCache;
|
static std::set<uint32> itemCache;
|
||||||
// equipCacheNew[RequiredLevel][InventoryType]
|
// equipCacheNew[RequiredLevel][InventoryType]
|
||||||
std::map<uint32, std::map<uint32, std::vector<uint32>>> equipCacheNew;
|
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()
|
#define sRandomItemMgr RandomItemMgr::instance()
|
||||||
|
|||||||
@ -14,7 +14,6 @@
|
|||||||
#include "ObjectMgr.h"
|
#include "ObjectMgr.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
#include "PlayerbotFactory.h"
|
#include "PlayerbotFactory.h"
|
||||||
#include "RandomItemMgr.h"
|
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
#include "SpellAuraDefines.h"
|
#include "SpellAuraDefines.h"
|
||||||
#include "SpellMgr.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)
|
void StatsWeightCalculator::GenerateWeights(Player* player)
|
||||||
{
|
{
|
||||||
GenerateBasicWeights(player);
|
GenerateBasicWeights(player);
|
||||||
|
|||||||
@ -30,7 +30,6 @@ public:
|
|||||||
void Reset();
|
void Reset();
|
||||||
float CalculateItem(uint32 itemId, int32 randomPropertyId = 0, int32 slot = -1);
|
float CalculateItem(uint32 itemId, int32 randomPropertyId = 0, int32 slot = -1);
|
||||||
float CalculateEnchant(uint32 enchantId);
|
float CalculateEnchant(uint32 enchantId);
|
||||||
int32 PickBestRandomPropertyId(uint32 itemId);
|
|
||||||
|
|
||||||
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; }
|
||||||
|
|||||||
@ -147,6 +147,7 @@ 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);
|
||||||
preferClassArmorType = sConfigMgr->GetOption<bool>("AiPlayerbot.PreferClassArmorType", false);
|
preferClassArmorType = sConfigMgr->GetOption<bool>("AiPlayerbot.PreferClassArmorType", false);
|
||||||
@ -214,7 +215,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
attunementQuests);
|
attunementQuests);
|
||||||
|
|
||||||
LoadSet<std::set<uint32>>(
|
LoadSet<std::set<uint32>>(
|
||||||
sConfigMgr->GetOption<std::string>("AiPlayerbot.UnobtainableItems", "12468,44869,44870,46978"),
|
sConfigMgr->GetOption<std::string>("AiPlayerbot.UnobtainableItems", "12468,46978"),
|
||||||
unobtainableItems);
|
unobtainableItems);
|
||||||
|
|
||||||
botAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.BotAutologin", false);
|
botAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.BotAutologin", false);
|
||||||
@ -351,27 +352,32 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
|
|
||||||
// does not depend on global chance
|
// does not depend on global chance
|
||||||
broadcastChanceGuildManagement = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceGuildManagement", 30000);
|
broadcastChanceGuildManagement = sConfigMgr->GetOption<int32>("AiPlayerbot.BroadcastChanceGuildManagement", 30000);
|
||||||
|
////////////////////////////
|
||||||
|
|
||||||
toxicLinksRepliesChance = sConfigMgr->GetOption<int32>("AiPlayerbot.ToxicLinksRepliesChance", 30); // 0-100
|
toxicLinksRepliesChance = sConfigMgr->GetOption<int32>("AiPlayerbot.ToxicLinksRepliesChance", 30); // 0-100
|
||||||
thunderfuryRepliesChance = sConfigMgr->GetOption<int32>("AiPlayerbot.ThunderfuryRepliesChance", 40); // 0-100
|
thunderfuryRepliesChance = sConfigMgr->GetOption<int32>("AiPlayerbot.ThunderfuryRepliesChance", 40); // 0-100
|
||||||
guildRepliesRate = sConfigMgr->GetOption<int32>("AiPlayerbot.GuildRepliesRate", 100); // 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);
|
randomBotJoinBG = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotJoinBG", true);
|
||||||
randomBotAutoJoinBG = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotAutoJoinBG", false);
|
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");
|
randomBotAutoJoinICBrackets = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAutoJoinICBrackets", "0,1");
|
||||||
randomBotAutoJoinABBrackets = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAutoJoinABBrackets", "6");
|
randomBotAutoJoinEYBrackets = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAutoJoinEYBrackets", "0,1,2");
|
||||||
randomBotAutoJoinAVBrackets = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAutoJoinAVBrackets", "3");
|
randomBotAutoJoinAVBrackets = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAutoJoinAVBrackets", "0,1,2,3");
|
||||||
randomBotAutoJoinEYBrackets = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAutoJoinEYBrackets", "2");
|
randomBotAutoJoinABBrackets = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAutoJoinABBrackets", "0,1,2,3,4,5,6");
|
||||||
randomBotAutoJoinICBrackets = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotAutoJoinICBrackets", "1");
|
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);
|
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 =
|
randomBotAutoJoinBGRatedArena2v2Count =
|
||||||
sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAutoJoinBGRatedArena2v2Count", 0);
|
sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAutoJoinBGRatedArena2v2Count", 0);
|
||||||
@ -387,6 +393,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
randomBotMaxLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotMaxLevel", 80);
|
randomBotMaxLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotMaxLevel", 80);
|
||||||
if (randomBotMaxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
|
if (randomBotMaxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||||
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);
|
randomBotTeleLowerLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleLowerLevel", 1);
|
||||||
randomBotTeleHigherLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleHigherLevel", 3);
|
randomBotTeleHigherLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleHigherLevel", 3);
|
||||||
openGoSpell = sConfigMgr->GetOption<int32>("AiPlayerbot.OpenGoSpell", 6477);
|
openGoSpell = sConfigMgr->GetOption<int32>("AiPlayerbot.OpenGoSpell", 6477);
|
||||||
@ -552,8 +559,6 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
randomBotGuildSizeMax = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotGuildSizeMax", 15);
|
randomBotGuildSizeMax = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotGuildSizeMax", 15);
|
||||||
deleteRandomBotGuilds = sConfigMgr->GetOption<bool>("AiPlayerbot.DeleteRandomBotGuilds", false);
|
deleteRandomBotGuilds = sConfigMgr->GetOption<bool>("AiPlayerbot.DeleteRandomBotGuilds", false);
|
||||||
|
|
||||||
botSendMailEnabled = sConfigMgr->GetOption<bool>("AiPlayerbot.BotSendMailEnabled", true);
|
|
||||||
|
|
||||||
guildTaskEnabled = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableGuildTasks", false);
|
guildTaskEnabled = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableGuildTasks", false);
|
||||||
minGuildTaskChangeTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MinGuildTaskChangeTime", 3 * 24 * 3600);
|
minGuildTaskChangeTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MinGuildTaskChangeTime", 3 * 24 * 3600);
|
||||||
maxGuildTaskChangeTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxGuildTaskChangeTime", 4 * 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);
|
disableRandomLevels = sConfigMgr->GetOption<bool>("AiPlayerbot.DisableRandomLevels", false);
|
||||||
randomBotRandomPassword = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotRandomPassword", true);
|
randomBotRandomPassword = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotRandomPassword", true);
|
||||||
downgradeMaxLevelBot = sConfigMgr->GetOption<bool>("AiPlayerbot.DowngradeMaxLevelBot", true);
|
downgradeMaxLevelBot = sConfigMgr->GetOption<bool>("AiPlayerbot.DowngradeMaxLevelBot", true);
|
||||||
equipAndSpecPersistence = sConfigMgr->GetOption<bool>("AiPlayerbot.EquipAndSpecPersistence", true);
|
equipmentPersistence = sConfigMgr->GetOption<bool>("AiPlayerbot.EquipmentPersistence", false);
|
||||||
equipAndSpecPersistenceLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.EquipAndSpecPersistenceLevel", 1);
|
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);
|
keepAltsInGroup = sConfigMgr->GetOption<bool>("AiPlayerbot.KeepAltsInGroup", false);
|
||||||
allowSummonInCombat = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonInCombat", true);
|
allowSummonInCombat = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonInCombat", true);
|
||||||
@ -586,7 +591,6 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
reviveBotWhenSummoned = sConfigMgr->GetOption<int32>("AiPlayerbot.ReviveBotWhenSummoned", 1);
|
reviveBotWhenSummoned = sConfigMgr->GetOption<int32>("AiPlayerbot.ReviveBotWhenSummoned", 1);
|
||||||
botRepairWhenSummon = sConfigMgr->GetOption<bool>("AiPlayerbot.BotRepairWhenSummon", true);
|
botRepairWhenSummon = sConfigMgr->GetOption<bool>("AiPlayerbot.BotRepairWhenSummon", true);
|
||||||
autoInitOnly = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoInitOnly", false);
|
autoInitOnly = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoInitOnly", false);
|
||||||
resetInstanceIdForAltBots = sConfigMgr->GetOption<bool>("AiPlayerbot.ResetInstanceIdForAltBots", false);
|
|
||||||
autoInitEquipLevelLimitRatio = sConfigMgr->GetOption<float>("AiPlayerbot.AutoInitEquipLevelLimitRatio", 1.0);
|
autoInitEquipLevelLimitRatio = sConfigMgr->GetOption<float>("AiPlayerbot.AutoInitEquipLevelLimitRatio", 1.0);
|
||||||
|
|
||||||
maxAddedBots = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxAddedBots", 40);
|
maxAddedBots = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxAddedBots", 40);
|
||||||
@ -665,7 +669,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
dropObsoleteQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.DropObsoleteQuests", true);
|
dropObsoleteQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.DropObsoleteQuests", true);
|
||||||
allowLearnTrainerSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowLearnTrainerSpells", true);
|
allowLearnTrainerSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowLearnTrainerSpells", true);
|
||||||
autoPickTalents = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoPickTalents", 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);
|
hunterWolfPet = sConfigMgr->GetOption<int32>("AiPlayerbot.HunterWolfPet", 0);
|
||||||
defaultPetStance = sConfigMgr->GetOption<int32>("AiPlayerbot.DefaultPetStance", 1);
|
defaultPetStance = sConfigMgr->GetOption<int32>("AiPlayerbot.DefaultPetStance", 1);
|
||||||
petChatCommandDebug = sConfigMgr->GetOption<bool>("AiPlayerbot.PetChatCommandDebug", 0);
|
petChatCommandDebug = sConfigMgr->GetOption<bool>("AiPlayerbot.PetChatCommandDebug", 0);
|
||||||
|
|||||||
@ -3,8 +3,8 @@
|
|||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _PLAYERBOT_PLAYERBOTAICONFIG_H
|
#ifndef _PLAYERBOT_PLAYERbotAICONFIG_H
|
||||||
#define _PLAYERBOT_PLAYERBOTAICONFIG_H
|
#define _PLAYERBOT_PLAYERbotAICONFIG_H
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@ -134,6 +134,7 @@ 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;
|
||||||
bool preferClassArmorType;
|
bool preferClassArmorType;
|
||||||
@ -226,6 +227,10 @@ public:
|
|||||||
|
|
||||||
uint32 guildRepliesRate;
|
uint32 guildRepliesRate;
|
||||||
|
|
||||||
|
bool suggestDungeonsInLowerCaseRandomly;
|
||||||
|
|
||||||
|
// --
|
||||||
|
|
||||||
bool randomBotJoinBG;
|
bool randomBotJoinBG;
|
||||||
bool randomBotAutoJoinBG;
|
bool randomBotAutoJoinBG;
|
||||||
|
|
||||||
@ -247,6 +252,7 @@ public:
|
|||||||
uint32 randomBotAutoJoinBGRatedArena3v3Count;
|
uint32 randomBotAutoJoinBGRatedArena3v3Count;
|
||||||
uint32 randomBotAutoJoinBGRatedArena5v5Count;
|
uint32 randomBotAutoJoinBGRatedArena5v5Count;
|
||||||
|
|
||||||
|
bool randomBotLoginAtStartup;
|
||||||
uint32 randomBotTeleLowerLevel, randomBotTeleHigherLevel;
|
uint32 randomBotTeleLowerLevel, randomBotTeleHigherLevel;
|
||||||
std::map<uint32, std::pair<uint32, uint32>> zoneBrackets;
|
std::map<uint32, std::pair<uint32, uint32>> zoneBrackets;
|
||||||
bool logInGroupOnly, logValuesPerTick;
|
bool logInGroupOnly, logValuesPerTick;
|
||||||
@ -292,7 +298,6 @@ public:
|
|||||||
float periodicOnlineOfflineRatio;
|
float periodicOnlineOfflineRatio;
|
||||||
bool gearscorecheck;
|
bool gearscorecheck;
|
||||||
bool randomBotPreQuests;
|
bool randomBotPreQuests;
|
||||||
bool botSendMailEnabled;
|
|
||||||
|
|
||||||
bool guildTaskEnabled;
|
bool guildTaskEnabled;
|
||||||
uint32 minGuildTaskChangeTime, maxGuildTaskChangeTime;
|
uint32 minGuildTaskChangeTime, maxGuildTaskChangeTime;
|
||||||
@ -389,8 +394,8 @@ public:
|
|||||||
|
|
||||||
uint32 selfBotLevel;
|
uint32 selfBotLevel;
|
||||||
bool downgradeMaxLevelBot;
|
bool downgradeMaxLevelBot;
|
||||||
bool equipAndSpecPersistence;
|
bool equipmentPersistence;
|
||||||
int32 equipAndSpecPersistenceLevel;
|
int32 equipmentPersistenceLevel;
|
||||||
int32 groupInvitationPermission;
|
int32 groupInvitationPermission;
|
||||||
bool keepAltsInGroup = false;
|
bool keepAltsInGroup = false;
|
||||||
bool KeepAltsInGroup() const { return keepAltsInGroup; }
|
bool KeepAltsInGroup() const { return keepAltsInGroup; }
|
||||||
@ -400,7 +405,6 @@ public:
|
|||||||
int reviveBotWhenSummoned;
|
int reviveBotWhenSummoned;
|
||||||
bool botRepairWhenSummon;
|
bool botRepairWhenSummon;
|
||||||
bool autoInitOnly;
|
bool autoInitOnly;
|
||||||
bool resetInstanceIdForAltBots;
|
|
||||||
float autoInitEquipLevelLimitRatio;
|
float autoInitEquipLevelLimitRatio;
|
||||||
int32 maxAddedBots;
|
int32 maxAddedBots;
|
||||||
int32 addClassCommand;
|
int32 addClassCommand;
|
||||||
|
|||||||
@ -242,7 +242,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
group->ChangeLeader(newLeader->GetGUID());
|
group->ChangeLeader(newLeader->GetGUID());
|
||||||
group->SendUpdate();
|
|
||||||
LOG_DEBUG("playerbots", "GroupSetLeaderOperation: Changed leader to {}", newLeader->GetName());
|
LOG_DEBUG("playerbots", "GroupSetLeaderOperation: Changed leader to {}", newLeader->GetName());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user