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();
|
||||
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)
|
||||
factory.InitEquipment(true);
|
||||
if (!sPlayerbotAIConfig.equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel)
|
||||
{
|
||||
if (sPlayerbotAIConfig.incrementalGearInit)
|
||||
factory.InitEquipment(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 ||
|
||||
|
||||
@ -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;
|
||||
applyAura = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
if (!applyAura)
|
||||
return false;
|
||||
|
||||
if (!botAI->CanCastSpell(spellId, bot, false, nullptr, item))
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) }));
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,22 +562,16 @@ 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();
|
||||
@ -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,10 +670,11 @@ 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)
|
||||
{
|
||||
InitEquipment(incremental, incremental ? false : sPlayerbotAIConfig.twoRoundsGearInit);
|
||||
if (sPlayerbotAIConfig.incrementalGearInit || !incremental)
|
||||
InitEquipment(incremental, incremental ? false : sPlayerbotAIConfig.twoRoundsGearInit);
|
||||
}
|
||||
// bot->SaveToDB(false, false);
|
||||
if (pmo)
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -242,7 +242,6 @@ public:
|
||||
}
|
||||
|
||||
group->ChangeLeader(newLeader->GetGUID());
|
||||
group->SendUpdate();
|
||||
LOG_DEBUG("playerbots", "GroupSetLeaderOperation: Changed leader to {}", newLeader->GetName());
|
||||
return true;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user