mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-02-03 10:53:48 +00:00
Calculation of the power of items with random properties (#1312)
* Score calculation of item random property * Equip auto repair on repop * Item random property calculation * Random Property calculation
This commit is contained in:
@@ -305,6 +305,49 @@ ItemIds ChatHelper::parseItems(std::string const text)
|
|||||||
return itemIds;
|
return itemIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ItemWithRandomProperty ChatHelper::parseItemWithRandomProperty(std::string const text)
|
||||||
|
{
|
||||||
|
ItemWithRandomProperty res;
|
||||||
|
|
||||||
|
size_t itemStart = text.find("Hitem:");
|
||||||
|
if (itemStart == std::string::npos)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
itemStart += 6;
|
||||||
|
if (itemStart >= text.length())
|
||||||
|
return res;
|
||||||
|
|
||||||
|
size_t colonPos = text.find(':', itemStart);
|
||||||
|
if (colonPos == std::string::npos)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
std::string itemIdStr = text.substr(itemStart, colonPos - itemStart);
|
||||||
|
res.itemId = atoi(itemIdStr.c_str());
|
||||||
|
|
||||||
|
std::vector<std::string> params;
|
||||||
|
size_t currentPos = colonPos + 1;
|
||||||
|
|
||||||
|
while (currentPos < text.length()) {
|
||||||
|
size_t nextColon = text.find(':', currentPos);
|
||||||
|
if (nextColon == std::string::npos) {
|
||||||
|
size_t hTag = text.find("|h", currentPos);
|
||||||
|
if (hTag != std::string::npos) {
|
||||||
|
params.push_back(text.substr(currentPos, hTag - currentPos));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
params.push_back(text.substr(currentPos, nextColon - currentPos));
|
||||||
|
currentPos = nextColon + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.size() >= 6) {
|
||||||
|
res.randomPropertyId = atoi(params[5].c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
std::string const ChatHelper::FormatQuest(Quest const* quest)
|
std::string const ChatHelper::FormatQuest(Quest const* quest)
|
||||||
{
|
{
|
||||||
if (!quest)
|
if (!quest)
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ struct ItemTemplate;
|
|||||||
typedef std::set<uint32> ItemIds;
|
typedef std::set<uint32> ItemIds;
|
||||||
typedef std::set<uint32> SpellIds;
|
typedef std::set<uint32> SpellIds;
|
||||||
|
|
||||||
|
struct ItemWithRandomProperty {
|
||||||
|
uint32 itemId{0};
|
||||||
|
int32 randomPropertyId{0};
|
||||||
|
};
|
||||||
|
|
||||||
class ChatHelper : public PlayerbotAIAware
|
class ChatHelper : public PlayerbotAIAware
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -33,6 +38,7 @@ public:
|
|||||||
static std::string const formatMoney(uint32 copper);
|
static std::string const formatMoney(uint32 copper);
|
||||||
static uint32 parseMoney(std::string const text);
|
static uint32 parseMoney(std::string const text);
|
||||||
static ItemIds parseItems(std::string const text);
|
static ItemIds parseItems(std::string const text);
|
||||||
|
static ItemWithRandomProperty parseItemWithRandomProperty(std::string const text);
|
||||||
uint32 parseSpell(std::string const text);
|
uint32 parseSpell(std::string const text);
|
||||||
static std::string parseValue(const std::string& type, const std::string& text);
|
static std::string parseValue(const std::string& type, const std::string& text);
|
||||||
|
|
||||||
|
|||||||
@@ -1742,7 +1742,7 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
|
|||||||
|
|
||||||
if (incremental && oldItem)
|
if (incremental && oldItem)
|
||||||
{
|
{
|
||||||
float old_score = calculator.CalculateItem(oldItem->GetEntry());
|
float old_score = calculator.CalculateItem(oldItem->GetEntry(), oldItem->GetItemRandomPropertyId());
|
||||||
if (bestScoreForSlot < 1.2f * old_score)
|
if (bestScoreForSlot < 1.2f * old_score)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "DBCStores.h"
|
#include "DBCStores.h"
|
||||||
|
#include "ItemEnchantmentMgr.h"
|
||||||
#include "ItemTemplate.h"
|
#include "ItemTemplate.h"
|
||||||
#include "ObjectMgr.h"
|
#include "ObjectMgr.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
@@ -205,7 +206,7 @@ void StatsCollector::CollectSpellStats(uint32 spellId, float multiplier, int32 s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatsCollector::CollectEnchantStats(SpellItemEnchantmentEntry const* enchant)
|
void StatsCollector::CollectEnchantStats(SpellItemEnchantmentEntry const* enchant, uint32 default_enchant_amount)
|
||||||
{
|
{
|
||||||
for (int s = 0; s < MAX_SPELL_ITEM_ENCHANTMENT_EFFECTS; ++s)
|
for (int s = 0; s < MAX_SPELL_ITEM_ENCHANTMENT_EFFECTS; ++s)
|
||||||
{
|
{
|
||||||
@@ -231,6 +232,10 @@ void StatsCollector::CollectEnchantStats(SpellItemEnchantmentEntry const* enchan
|
|||||||
}
|
}
|
||||||
case ITEM_ENCHANTMENT_TYPE_STAT:
|
case ITEM_ENCHANTMENT_TYPE_STAT:
|
||||||
{
|
{
|
||||||
|
// for item random suffix
|
||||||
|
if (!enchant_amount)
|
||||||
|
enchant_amount = default_enchant_amount;
|
||||||
|
|
||||||
if (!enchant_amount)
|
if (!enchant_amount)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@@ -250,7 +255,7 @@ bool StatsCollector::SpecialSpellFilter(uint32 spellId)
|
|||||||
// trinket
|
// trinket
|
||||||
switch (spellId)
|
switch (spellId)
|
||||||
{
|
{
|
||||||
case 60764: // Totem of Splintering
|
case 60764: // Totem of Splintering
|
||||||
if (type_ & (CollectorType::SPELL))
|
if (type_ & (CollectorType::SPELL))
|
||||||
return true;
|
return true;
|
||||||
break;
|
break;
|
||||||
@@ -744,7 +749,7 @@ void StatsCollector::HandleApplyAura(const SpellEffectInfo& effectInfo, float mu
|
|||||||
|
|
||||||
int32 StatsCollector::AverageValue(const SpellEffectInfo& effectInfo)
|
int32 StatsCollector::AverageValue(const SpellEffectInfo& effectInfo)
|
||||||
{
|
{
|
||||||
//float basePointsPerLevel = effectInfo.RealPointsPerLevel; //not used, line marked for removal.
|
// float basePointsPerLevel = effectInfo.RealPointsPerLevel; //not used, line marked for removal.
|
||||||
int32 basePoints = effectInfo.BasePoints;
|
int32 basePoints = effectInfo.BasePoints;
|
||||||
int32 randomPoints = int32(effectInfo.DieSides);
|
int32 randomPoints = int32(effectInfo.DieSides);
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public:
|
|||||||
void Reset();
|
void Reset();
|
||||||
void CollectItemStats(ItemTemplate const* proto);
|
void CollectItemStats(ItemTemplate const* proto);
|
||||||
void CollectSpellStats(uint32 spellId, float multiplier = 1.0f, int32 spellCooldown = -1);
|
void CollectSpellStats(uint32 spellId, float multiplier = 1.0f, int32 spellCooldown = -1);
|
||||||
void CollectEnchantStats(SpellItemEnchantmentEntry const* enchant);
|
void CollectEnchantStats(SpellItemEnchantmentEntry const* enchant, uint32 default_enchant_amount = 0);
|
||||||
bool CanBeTriggeredByType(SpellInfo const* spellInfo, uint32 procFlags, bool strict = true);
|
bool CanBeTriggeredByType(SpellInfo const* spellInfo, uint32 procFlags, bool strict = true);
|
||||||
bool CheckSpellValidation(uint32 spellFamilyName, flag96 spelFalimyFlags, bool strict = true);
|
bool CheckSpellValidation(uint32 spellFamilyName, flag96 spelFalimyFlags, bool strict = true);
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "AiFactory.h"
|
#include "AiFactory.h"
|
||||||
#include "DBCStores.h"
|
#include "DBCStores.h"
|
||||||
|
#include "ItemEnchantmentMgr.h"
|
||||||
#include "ItemTemplate.h"
|
#include "ItemTemplate.h"
|
||||||
#include "ObjectMgr.h"
|
#include "ObjectMgr.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
@@ -59,7 +60,7 @@ void StatsWeightCalculator::Reset()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float StatsWeightCalculator::CalculateItem(uint32 itemId)
|
float StatsWeightCalculator::CalculateItem(uint32 itemId, int32 randomPropertyIds)
|
||||||
{
|
{
|
||||||
ItemTemplate const* proto = &sObjectMgr->GetItemTemplateStore()->at(itemId);
|
ItemTemplate const* proto = &sObjectMgr->GetItemTemplateStore()->at(itemId);
|
||||||
|
|
||||||
@@ -70,6 +71,9 @@ float StatsWeightCalculator::CalculateItem(uint32 itemId)
|
|||||||
|
|
||||||
collector_->CollectItemStats(proto);
|
collector_->CollectItemStats(proto);
|
||||||
|
|
||||||
|
if (randomPropertyIds != 0)
|
||||||
|
CalculateRandomProperty(randomPropertyIds, itemId);
|
||||||
|
|
||||||
if (enable_overflow_penalty_)
|
if (enable_overflow_penalty_)
|
||||||
ApplyOverflowPenalty(player_);
|
ApplyOverflowPenalty(player_);
|
||||||
|
|
||||||
@@ -116,6 +120,53 @@ float StatsWeightCalculator::CalculateEnchant(uint32 enchantId)
|
|||||||
return weight_;
|
return weight_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StatsWeightCalculator::CalculateRandomProperty(int32 randomPropertyId, uint32 itemId)
|
||||||
|
{
|
||||||
|
if (randomPropertyId > 0)
|
||||||
|
{
|
||||||
|
ItemRandomPropertiesEntry const* item_rand = sItemRandomPropertiesStore.LookupEntry(randomPropertyId);
|
||||||
|
if (!item_rand)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32 i = PROP_ENCHANTMENT_SLOT_0; i < MAX_ENCHANTMENT_SLOT; ++i)
|
||||||
|
{
|
||||||
|
uint32 enchantId = item_rand->Enchantment[i - PROP_ENCHANTMENT_SLOT_0];
|
||||||
|
SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId);
|
||||||
|
if (enchant)
|
||||||
|
collector_->CollectEnchantStats(enchant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ItemRandomSuffixEntry const* item_rand = sItemRandomSuffixStore.LookupEntry(-randomPropertyId);
|
||||||
|
if (!item_rand)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32 i = PROP_ENCHANTMENT_SLOT_0; i < MAX_ENCHANTMENT_SLOT; ++i)
|
||||||
|
{
|
||||||
|
uint32 enchantId = item_rand->Enchantment[i - PROP_ENCHANTMENT_SLOT_0];
|
||||||
|
SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId);
|
||||||
|
uint32 enchant_amount = 0;
|
||||||
|
|
||||||
|
for (int k = 0; k < MAX_ITEM_ENCHANTMENT_EFFECTS; ++k)
|
||||||
|
{
|
||||||
|
if (item_rand->Enchantment[k] == enchantId)
|
||||||
|
{
|
||||||
|
enchant_amount = uint32((item_rand->AllocationPct[k] * GenerateEnchSuffixFactor(itemId)) / 10000);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enchant)
|
||||||
|
collector_->CollectEnchantStats(enchant, enchant_amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void StatsWeightCalculator::GenerateWeights(Player* player)
|
void StatsWeightCalculator::GenerateWeights(Player* player)
|
||||||
{
|
{
|
||||||
GenerateBasicWeights(player);
|
GenerateBasicWeights(player);
|
||||||
@@ -293,8 +344,8 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
|
|||||||
stats_weights_[STATS_TYPE_CRIT] += 0.8f;
|
stats_weights_[STATS_TYPE_CRIT] += 0.8f;
|
||||||
stats_weights_[STATS_TYPE_HASTE] += 1.0f;
|
stats_weights_[STATS_TYPE_HASTE] += 1.0f;
|
||||||
}
|
}
|
||||||
else if ((cls == CLASS_PALADIN && tab == PALADIN_TAB_HOLY) || // holy
|
else if ((cls == CLASS_PALADIN && tab == PALADIN_TAB_HOLY) || // holy
|
||||||
(cls == CLASS_SHAMAN && tab == SHAMAN_TAB_RESTORATION)) // heal
|
(cls == CLASS_SHAMAN && tab == SHAMAN_TAB_RESTORATION)) // heal
|
||||||
{
|
{
|
||||||
stats_weights_[STATS_TYPE_INTELLECT] += 0.9f;
|
stats_weights_[STATS_TYPE_INTELLECT] += 0.9f;
|
||||||
stats_weights_[STATS_TYPE_SPIRIT] += 0.15f;
|
stats_weights_[STATS_TYPE_SPIRIT] += 0.15f;
|
||||||
@@ -303,7 +354,7 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
|
|||||||
stats_weights_[STATS_TYPE_CRIT] += 0.6f;
|
stats_weights_[STATS_TYPE_CRIT] += 0.6f;
|
||||||
stats_weights_[STATS_TYPE_HASTE] += 0.8f;
|
stats_weights_[STATS_TYPE_HASTE] += 0.8f;
|
||||||
}
|
}
|
||||||
else if ((cls == CLASS_PRIEST && tab != PRIEST_TAB_SHADOW) || // discipline / holy
|
else if ((cls == CLASS_PRIEST && tab != PRIEST_TAB_SHADOW) || // discipline / holy
|
||||||
(cls == CLASS_DRUID && tab == DRUID_TAB_RESTORATION))
|
(cls == CLASS_DRUID && tab == DRUID_TAB_RESTORATION))
|
||||||
{
|
{
|
||||||
stats_weights_[STATS_TYPE_INTELLECT] += 0.8f;
|
stats_weights_[STATS_TYPE_INTELLECT] += 0.8f;
|
||||||
@@ -464,9 +515,9 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto)
|
|||||||
// {
|
// {
|
||||||
// weight_ *= 1.0;
|
// weight_ *= 1.0;
|
||||||
// }
|
// }
|
||||||
// double hand
|
|
||||||
if (proto->Class == ITEM_CLASS_WEAPON)
|
if (proto->Class == ITEM_CLASS_WEAPON)
|
||||||
{
|
{
|
||||||
|
// double hand
|
||||||
bool isDoubleHand = proto->Class == ITEM_CLASS_WEAPON &&
|
bool isDoubleHand = proto->Class == ITEM_CLASS_WEAPON &&
|
||||||
!(ITEM_SUBCLASS_MASK_SINGLE_HAND & (1 << proto->SubClass)) &&
|
!(ITEM_SUBCLASS_MASK_SINGLE_HAND & (1 << proto->SubClass)) &&
|
||||||
!(ITEM_SUBCLASS_MASK_WEAPON_RANGED & (1 << proto->SubClass));
|
!(ITEM_SUBCLASS_MASK_WEAPON_RANGED & (1 << proto->SubClass));
|
||||||
@@ -474,29 +525,41 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto)
|
|||||||
if (isDoubleHand)
|
if (isDoubleHand)
|
||||||
{
|
{
|
||||||
weight_ *= 0.5;
|
weight_ *= 0.5;
|
||||||
}
|
// spec without double hand
|
||||||
// spec without double hand
|
// enhancement, rogue, ice dk, unholy dk, shield tank, fury warrior without titan's grip but with duel wield
|
||||||
// enhancement, rogue, ice dk, unholy dk, shield tank, fury warrior without titan's grip but with duel wield
|
if (((cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ENHANCEMENT && player_->CanDualWield()) ||
|
||||||
if (isDoubleHand &&
|
(cls == CLASS_ROGUE) || (cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_FROST) ||
|
||||||
((cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ENHANCEMENT && player_->CanDualWield()) ||
|
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !player_->CanTitanGrip() && player_->CanDualWield()) ||
|
||||||
(cls == CLASS_ROGUE) || (cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_FROST) ||
|
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_PROTECTION) ||
|
||||||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !player_->CanTitanGrip() && player_->CanDualWield()) ||
|
(cls == CLASS_PALADIN && tab == PALADIN_TAB_PROTECTION)))
|
||||||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_PROTECTION) ||
|
{
|
||||||
(cls == CLASS_PALADIN && tab == PALADIN_TAB_PROTECTION)))
|
weight_ *= 0.1;
|
||||||
{
|
}
|
||||||
weight_ *= 0.1;
|
|
||||||
}
|
}
|
||||||
// spec with double hand
|
// spec with double hand
|
||||||
// fury without duel wield, arms, bear, retribution, blood dk
|
// fury without duel wield, arms, bear, retribution, blood dk
|
||||||
if (!isDoubleHand &&
|
if (!isDoubleHand)
|
||||||
((cls == CLASS_HUNTER && !player_->CanDualWield()) ||
|
|
||||||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !player_->CanDualWield()) ||
|
|
||||||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_ARMS) || (cls == CLASS_DRUID && tab == DRUID_TAB_FERAL) ||
|
|
||||||
(cls == CLASS_PALADIN && tab == PALADIN_TAB_RETRIBUTION) ||
|
|
||||||
(cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_BLOOD) ||
|
|
||||||
(cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ENHANCEMENT && !player_->CanDualWield())))
|
|
||||||
{
|
{
|
||||||
weight_ *= 0.1;
|
if ((cls == CLASS_HUNTER && !player_->CanDualWield()) ||
|
||||||
|
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !player_->CanDualWield()) ||
|
||||||
|
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_ARMS) || (cls == CLASS_DRUID && tab == DRUID_TAB_FERAL) ||
|
||||||
|
(cls == CLASS_PALADIN && tab == PALADIN_TAB_RETRIBUTION) ||
|
||||||
|
(cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_BLOOD) ||
|
||||||
|
(cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ENHANCEMENT && !player_->CanDualWield()))
|
||||||
|
{
|
||||||
|
weight_ *= 0.1;
|
||||||
|
}
|
||||||
|
// caster's main hand (cannot duel weapon but can equip two-hands stuff)
|
||||||
|
if (cls == CLASS_MAGE ||
|
||||||
|
cls == CLASS_PRIEST ||
|
||||||
|
cls == CLASS_WARLOCK ||
|
||||||
|
cls == CLASS_DRUID ||
|
||||||
|
(cls == CLASS_SHAMAN && !player_->CanDualWield()))
|
||||||
|
{
|
||||||
|
weight_ *= 0.65;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// fury with titan's grip
|
// fury with titan's grip
|
||||||
if ((!isDoubleHand || proto->SubClass == ITEM_SUBCLASS_WEAPON_POLEARM ||
|
if ((!isDoubleHand || proto->SubClass == ITEM_SUBCLASS_WEAPON_POLEARM ||
|
||||||
@@ -505,15 +568,18 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto)
|
|||||||
{
|
{
|
||||||
weight_ *= 0.1;
|
weight_ *= 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cls == CLASS_HUNTER && proto->SubClass == ITEM_SUBCLASS_WEAPON_THROWN)
|
if (cls == CLASS_HUNTER && proto->SubClass == ITEM_SUBCLASS_WEAPON_THROWN)
|
||||||
{
|
{
|
||||||
weight_ *= 0.1;
|
weight_ *= 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cls == CLASS_ROGUE && (tab == ROGUE_TAB_ASSASSINATION || tab == ROGUE_TAB_SUBTLETY) &&
|
if (cls == CLASS_ROGUE && (tab == ROGUE_TAB_ASSASSINATION || tab == ROGUE_TAB_SUBTLETY) &&
|
||||||
proto->SubClass != ITEM_SUBCLASS_WEAPON_DAGGER)
|
proto->SubClass != ITEM_SUBCLASS_WEAPON_DAGGER)
|
||||||
{
|
{
|
||||||
weight_ *= 0.5;
|
weight_ *= 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cls == CLASS_ROGUE && player_->HasAura(13964) &&
|
if (cls == CLASS_ROGUE && player_->HasAura(13964) &&
|
||||||
(proto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD || proto->SubClass == ITEM_SUBCLASS_WEAPON_AXE))
|
(proto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD || proto->SubClass == ITEM_SUBCLASS_WEAPON_AXE))
|
||||||
{
|
{
|
||||||
@@ -559,12 +625,13 @@ void StatsWeightCalculator::ApplyOverflowPenalty(Player* player)
|
|||||||
if (hitOverflowType_ & CollectorType::SPELL)
|
if (hitOverflowType_ & CollectorType::SPELL)
|
||||||
{
|
{
|
||||||
hit_current = player->GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HIT_CHANCE);
|
hit_current = player->GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HIT_CHANCE);
|
||||||
hit_current += player->GetTotalAuraModifier(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT); // suppression (18176)
|
hit_current +=
|
||||||
|
player->GetTotalAuraModifier(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT); // suppression (18176)
|
||||||
hit_current += player->GetRatingBonusValue(CR_HIT_SPELL);
|
hit_current += player->GetRatingBonusValue(CR_HIT_SPELL);
|
||||||
|
|
||||||
if (cls == CLASS_PRIEST && tab == PRIEST_TAB_SHADOW && player->HasAura(15835)) // Shadow Focus
|
if (cls == CLASS_PRIEST && tab == PRIEST_TAB_SHADOW && player->HasAura(15835)) // Shadow Focus
|
||||||
hit_current += 3;
|
hit_current += 3;
|
||||||
if (cls == CLASS_MAGE && tab == MAGE_TAB_ARCANE && player->HasAura(12840)) // Arcane Focus
|
if (cls == CLASS_MAGE && tab == MAGE_TAB_ARCANE && player->HasAura(12840)) // Arcane Focus
|
||||||
hit_current += 3;
|
hit_current += 3;
|
||||||
|
|
||||||
hit_overflow = SPELL_HIT_OVERFLOW;
|
hit_overflow = SPELL_HIT_OVERFLOW;
|
||||||
@@ -657,7 +724,7 @@ void StatsWeightCalculator::ApplyWeightFinetune(Player* player)
|
|||||||
{
|
{
|
||||||
if (type_ & (CollectorType::MELEE | CollectorType::RANGED))
|
if (type_ & (CollectorType::MELEE | CollectorType::RANGED))
|
||||||
{
|
{
|
||||||
float armor_penetration_current/*, armor_penetration_overflow*/; //not used, line marked for removal.
|
float armor_penetration_current /*, armor_penetration_overflow*/; // not used, line marked for removal.
|
||||||
armor_penetration_current = player->GetRatingBonusValue(CR_ARMOR_PENETRATION);
|
armor_penetration_current = player->GetRatingBonusValue(CR_ARMOR_PENETRATION);
|
||||||
if (armor_penetration_current > 50)
|
if (armor_penetration_current > 50)
|
||||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] *= 1.2f;
|
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] *= 1.2f;
|
||||||
|
|||||||
@@ -28,18 +28,19 @@ class StatsWeightCalculator
|
|||||||
public:
|
public:
|
||||||
StatsWeightCalculator(Player* player);
|
StatsWeightCalculator(Player* player);
|
||||||
void Reset();
|
void Reset();
|
||||||
float CalculateItem(uint32 itemId);
|
float CalculateItem(uint32 itemId, int32 randomPropertyId = 0);
|
||||||
float CalculateEnchant(uint32 enchantId);
|
float CalculateEnchant(uint32 enchantId);
|
||||||
|
|
||||||
void SetOverflowPenalty(bool apply) { enable_overflow_penalty_ = apply; }
|
void SetOverflowPenalty(bool apply) { enable_overflow_penalty_ = apply; }
|
||||||
void SetItemSetBonus(bool apply) { enable_item_set_bonus_ = apply; }
|
void SetItemSetBonus(bool apply) { enable_item_set_bonus_ = apply; }
|
||||||
void SetQualityBlend(bool apply) { enable_quality_blend_ = apply; }
|
void SetQualityBlend(bool apply) { enable_quality_blend_ = apply; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void GenerateWeights(Player* player);
|
void GenerateWeights(Player* player);
|
||||||
void GenerateBasicWeights(Player* player);
|
void GenerateBasicWeights(Player* player);
|
||||||
void GenerateAdditionalWeights(Player* player);
|
void GenerateAdditionalWeights(Player* player);
|
||||||
|
|
||||||
|
void CalculateRandomProperty(int32 randomPropertyId, uint32 itemId);
|
||||||
void CalculateItemSetMod(Player* player, ItemTemplate const* proto);
|
void CalculateItemSetMod(Player* player, ItemTemplate const* proto);
|
||||||
void CalculateSocketBonus(Player* player, ItemTemplate const* proto);
|
void CalculateSocketBonus(Player* player, ItemTemplate const* proto);
|
||||||
|
|
||||||
|
|||||||
@@ -232,6 +232,20 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CollectItemsVisitor : public IterateItemsVisitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CollectItemsVisitor() : IterateItemsVisitor() {}
|
||||||
|
|
||||||
|
std::vector<Item*> items;
|
||||||
|
|
||||||
|
bool Visit(Item* item) override
|
||||||
|
{
|
||||||
|
items.push_back(item);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class ItemCountByQuality : public IterateItemsVisitor
|
class ItemCountByQuality : public IterateItemsVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "Event.h"
|
#include "Event.h"
|
||||||
#include "ItemCountValue.h"
|
#include "ItemCountValue.h"
|
||||||
#include "ItemUsageValue.h"
|
#include "ItemUsageValue.h"
|
||||||
|
#include "ItemVisitors.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "StatsWeightCalculator.h"
|
#include "StatsWeightCalculator.h"
|
||||||
|
|
||||||
@@ -311,19 +312,28 @@ bool EquipUpgradesAction::Execute(Event event)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ListItemsVisitor visitor;
|
CollectItemsVisitor visitor;
|
||||||
IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS);
|
IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS);
|
||||||
|
|
||||||
ItemIds items;
|
ItemIds items;
|
||||||
for (std::map<uint32, uint32>::iterator i = visitor.items.begin(); i != visitor.items.end(); ++i)
|
for (auto i = visitor.items.begin(); i != visitor.items.end(); ++i)
|
||||||
{
|
{
|
||||||
ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", i->first);
|
Item* item = *i;
|
||||||
|
if (!item)
|
||||||
|
break;
|
||||||
|
int32 randomProperty = item->GetItemRandomPropertyId();
|
||||||
|
uint32 itemId = item->GetTemplate()->ItemId;
|
||||||
|
std::string itemUsageParam;
|
||||||
|
if (randomProperty != 0) {
|
||||||
|
itemUsageParam = std::to_string(itemId) + "," + std::to_string(randomProperty);
|
||||||
|
} else {
|
||||||
|
itemUsageParam = std::to_string(itemId);
|
||||||
|
}
|
||||||
|
ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", itemUsageParam);
|
||||||
|
|
||||||
if (usage == ITEM_USAGE_EQUIP || usage == ITEM_USAGE_REPLACE || usage == ITEM_USAGE_BAD_EQUIP)
|
if (usage == ITEM_USAGE_EQUIP || usage == ITEM_USAGE_REPLACE || usage == ITEM_USAGE_BAD_EQUIP)
|
||||||
{
|
{
|
||||||
// LOG_INFO("playerbots", "Bot {} <{}> EquipUpgradesAction {} ({})", bot->GetGUID().ToString().c_str(),
|
items.insert(itemId);
|
||||||
// bot->GetName().c_str(), i->first, usage == 1 ? "no item in slot" : usage == 2 ? "replace" : usage == 3 ?
|
|
||||||
// "wrong item but empty slot" : "");
|
|
||||||
items.insert(i->first);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,21 +343,31 @@ bool EquipUpgradesAction::Execute(Event event)
|
|||||||
|
|
||||||
bool EquipUpgradeAction::Execute(Event event)
|
bool EquipUpgradeAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
ListItemsVisitor visitor;
|
CollectItemsVisitor visitor;
|
||||||
IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS);
|
IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS);
|
||||||
|
|
||||||
ItemIds items;
|
ItemIds items;
|
||||||
for (std::map<uint32, uint32>::iterator i = visitor.items.begin(); i != visitor.items.end(); ++i)
|
for (auto i = visitor.items.begin(); i != visitor.items.end(); ++i)
|
||||||
{
|
{
|
||||||
ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", i->first);
|
Item* item = *i;
|
||||||
|
if (!item)
|
||||||
|
break;
|
||||||
|
int32 randomProperty = item->GetItemRandomPropertyId();
|
||||||
|
uint32 itemId = item->GetTemplate()->ItemId;
|
||||||
|
std::string itemUsageParam;
|
||||||
|
if (randomProperty != 0) {
|
||||||
|
itemUsageParam = std::to_string(itemId) + "," + std::to_string(randomProperty);
|
||||||
|
} else {
|
||||||
|
itemUsageParam = std::to_string(itemId);
|
||||||
|
}
|
||||||
|
ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", itemUsageParam);
|
||||||
|
|
||||||
if (usage == ITEM_USAGE_EQUIP || usage == ITEM_USAGE_REPLACE || usage == ITEM_USAGE_BAD_EQUIP)
|
if (usage == ITEM_USAGE_EQUIP || usage == ITEM_USAGE_REPLACE || usage == ITEM_USAGE_BAD_EQUIP)
|
||||||
{
|
{
|
||||||
// LOG_INFO("playerbots", "Bot {} <{}> EquipUpgradeAction item {} ({})", bot->GetGUID().ToString().c_str(),
|
items.insert(itemId);
|
||||||
// bot->GetName().c_str(), i->first, usage == 1 ? "no item in slot" : usage == 2 ? "replace" : usage == 3 ?
|
|
||||||
// "wrong item but empty slot" : "");
|
|
||||||
items.insert(i->first);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EquipItems(items);
|
EquipItems(items);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "Group.h"
|
#include "Group.h"
|
||||||
#include "ItemUsageValue.h"
|
#include "ItemUsageValue.h"
|
||||||
#include "LootAction.h"
|
#include "LootAction.h"
|
||||||
|
#include "ObjectMgr.h"
|
||||||
#include "PlayerbotAIConfig.h"
|
#include "PlayerbotAIConfig.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
@@ -30,12 +31,24 @@ bool LootRollAction::Execute(Event event)
|
|||||||
ObjectGuid guid = roll->itemGUID;
|
ObjectGuid guid = roll->itemGUID;
|
||||||
uint32 slot = roll->itemSlot;
|
uint32 slot = roll->itemSlot;
|
||||||
uint32 itemId = roll->itemid;
|
uint32 itemId = roll->itemid;
|
||||||
|
int32 randomProperty = 0;
|
||||||
|
if (roll->itemRandomPropId)
|
||||||
|
randomProperty = roll->itemRandomPropId;
|
||||||
|
else if (roll->itemRandomSuffix)
|
||||||
|
randomProperty = -((int)roll->itemRandomSuffix);
|
||||||
|
|
||||||
RollVote vote = PASS;
|
RollVote vote = PASS;
|
||||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
|
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
|
||||||
if (!proto)
|
if (!proto)
|
||||||
continue;
|
continue;
|
||||||
ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", itemId);
|
|
||||||
|
std::string itemUsageParam;
|
||||||
|
if (randomProperty != 0) {
|
||||||
|
itemUsageParam = std::to_string(itemId) + "," + std::to_string(randomProperty);
|
||||||
|
} else {
|
||||||
|
itemUsageParam = std::to_string(itemId);
|
||||||
|
}
|
||||||
|
ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", itemUsageParam);
|
||||||
|
|
||||||
// Armor Tokens are classed as MISC JUNK (Class 15, Subclass 0), luckily no other items I found have class bits and epic quality.
|
// Armor Tokens are classed as MISC JUNK (Class 15, Subclass 0), luckily no other items I found have class bits and epic quality.
|
||||||
if (proto->Class == ITEM_CLASS_MISC && proto->SubClass == ITEM_SUBCLASS_JUNK && proto->Quality == ITEM_QUALITY_EPIC)
|
if (proto->Class == ITEM_CLASS_MISC && proto->SubClass == ITEM_SUBCLASS_JUNK && proto->Quality == ITEM_QUALITY_EPIC)
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ bool ReleaseSpiritAction::Execute(Event event)
|
|||||||
botAI->TellMasterNoFacing(message);
|
botAI->TellMasterNoFacing(message);
|
||||||
|
|
||||||
IncrementDeathCount();
|
IncrementDeathCount();
|
||||||
|
bot->DurabilityRepairAll(false, 1.0f, false);
|
||||||
LogRelease("released");
|
LogRelease("released");
|
||||||
|
|
||||||
WorldPacket releasePacket(CMSG_REPOP_REQUEST);
|
WorldPacket releasePacket(CMSG_REPOP_REQUEST);
|
||||||
@@ -79,6 +80,7 @@ void ReleaseSpiritAction::LogRelease(const std::string& releaseMsg, bool isAutoR
|
|||||||
bool AutoReleaseSpiritAction::Execute(Event event)
|
bool AutoReleaseSpiritAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
IncrementDeathCount();
|
IncrementDeathCount();
|
||||||
|
bot->DurabilityRepairAll(false, 1.0f, false);
|
||||||
LogRelease("auto released", true);
|
LogRelease("auto released", true);
|
||||||
|
|
||||||
WorldPacket packet(CMSG_REPOP_REQUEST);
|
WorldPacket packet(CMSG_REPOP_REQUEST);
|
||||||
|
|||||||
@@ -140,17 +140,16 @@ bool TellEstimatedDpsAction::Execute(Event event)
|
|||||||
bool TellCalculateItemAction::Execute(Event event)
|
bool TellCalculateItemAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
std::string const text = event.getParam();
|
std::string const text = event.getParam();
|
||||||
ItemIds ids = chat->parseItems(text);
|
ItemWithRandomProperty item = chat->parseItemWithRandomProperty(text);
|
||||||
StatsWeightCalculator calculator(bot);
|
StatsWeightCalculator calculator(bot);
|
||||||
for (const uint32 &id : ids)
|
|
||||||
{
|
const ItemTemplate* proto = sObjectMgr->GetItemTemplate(item.itemId);
|
||||||
const ItemTemplate* proto = sObjectMgr->GetItemTemplate(id);
|
if (!proto)
|
||||||
if (!proto)
|
return false;
|
||||||
continue;
|
float score = calculator.CalculateItem(item.itemId, item.randomPropertyId);
|
||||||
float score = calculator.CalculateItem(id);
|
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << "Calculated score of " << chat->FormatItem(proto) << " : " << score;
|
out << "Calculated score of " << chat->FormatItem(proto) << " : " << score;
|
||||||
botAI->TellMasterNoFacing(out.str());
|
botAI->TellMasterNoFacing(out.str());
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "AiFactory.h"
|
#include "AiFactory.h"
|
||||||
#include "ChatHelper.h"
|
#include "ChatHelper.h"
|
||||||
#include "GuildTaskMgr.h"
|
#include "GuildTaskMgr.h"
|
||||||
|
#include "Item.h"
|
||||||
#include "LootObjectStack.h"
|
#include "LootObjectStack.h"
|
||||||
#include "PlayerbotAIConfig.h"
|
#include "PlayerbotAIConfig.h"
|
||||||
#include "PlayerbotFactory.h"
|
#include "PlayerbotFactory.h"
|
||||||
@@ -18,7 +19,16 @@
|
|||||||
|
|
||||||
ItemUsage ItemUsageValue::Calculate()
|
ItemUsage ItemUsageValue::Calculate()
|
||||||
{
|
{
|
||||||
uint32 itemId = atoi(qualifier.c_str());
|
uint32 itemId = 0;
|
||||||
|
uint32 randomPropertyId = 0;
|
||||||
|
size_t pos = qualifier.find(",");
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
itemId = atoi(qualifier.substr(0, pos).c_str());
|
||||||
|
randomPropertyId = atoi(qualifier.substr(pos + 1).c_str());
|
||||||
|
} else {
|
||||||
|
itemId = atoi(qualifier.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
if (!itemId)
|
if (!itemId)
|
||||||
return ITEM_USAGE_NONE;
|
return ITEM_USAGE_NONE;
|
||||||
|
|
||||||
@@ -89,7 +99,7 @@ ItemUsage ItemUsageValue::Calculate()
|
|||||||
if (bot->GetGuildId() && sGuildTaskMgr->IsGuildTaskItem(itemId, bot->GetGuildId()))
|
if (bot->GetGuildId() && sGuildTaskMgr->IsGuildTaskItem(itemId, bot->GetGuildId()))
|
||||||
return ITEM_USAGE_GUILD_TASK;
|
return ITEM_USAGE_GUILD_TASK;
|
||||||
|
|
||||||
ItemUsage equip = QueryItemUsageForEquip(proto);
|
ItemUsage equip = QueryItemUsageForEquip(proto, randomPropertyId);
|
||||||
if (equip != ITEM_USAGE_NONE)
|
if (equip != ITEM_USAGE_NONE)
|
||||||
return equip;
|
return equip;
|
||||||
|
|
||||||
@@ -224,7 +234,7 @@ ItemUsage ItemUsageValue::Calculate()
|
|||||||
return ITEM_USAGE_NONE;
|
return ITEM_USAGE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto)
|
ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto, int32 randomPropertyId)
|
||||||
{
|
{
|
||||||
if (bot->CanUseItem(itemProto) != EQUIP_ERR_OK)
|
if (bot->CanUseItem(itemProto) != EQUIP_ERR_OK)
|
||||||
return ITEM_USAGE_NONE;
|
return ITEM_USAGE_NONE;
|
||||||
@@ -296,7 +306,8 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto)
|
|||||||
calculator.SetItemSetBonus(false);
|
calculator.SetItemSetBonus(false);
|
||||||
calculator.SetOverflowPenalty(false);
|
calculator.SetOverflowPenalty(false);
|
||||||
|
|
||||||
float itemScore = calculator.CalculateItem(itemProto->ItemId);
|
float itemScore = calculator.CalculateItem(itemProto->ItemId, randomPropertyId);
|
||||||
|
|
||||||
if (itemScore)
|
if (itemScore)
|
||||||
shouldEquip = true;
|
shouldEquip = true;
|
||||||
|
|
||||||
@@ -380,7 +391,7 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ItemTemplate const* oldItemProto = oldItem->GetTemplate();
|
ItemTemplate const* oldItemProto = oldItem->GetTemplate();
|
||||||
float oldScore = calculator.CalculateItem(oldItemProto->ItemId);
|
float oldScore = calculator.CalculateItem(oldItemProto->ItemId, oldItem->GetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID));
|
||||||
if (oldItem)
|
if (oldItem)
|
||||||
{
|
{
|
||||||
// uint32 oldStatWeight = sRandomItemMgr->GetLiveStatWeight(bot, oldItemProto->ItemId);
|
// uint32 oldStatWeight = sRandomItemMgr->GetLiveStatWeight(bot, oldItemProto->ItemId);
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public:
|
|||||||
ItemUsage Calculate() override;
|
ItemUsage Calculate() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ItemUsage QueryItemUsageForEquip(ItemTemplate const* proto);
|
ItemUsage QueryItemUsageForEquip(ItemTemplate const* proto, int32 randomPropertyId = 0);
|
||||||
uint32 GetSmallestBagSize();
|
uint32 GetSmallestBagSize();
|
||||||
bool IsItemUsefulForQuest(Player* player, ItemTemplate const* proto);
|
bool IsItemUsefulForQuest(Player* player, ItemTemplate const* proto);
|
||||||
bool IsItemNeededForSkill(ItemTemplate const* proto);
|
bool IsItemNeededForSkill(ItemTemplate const* proto);
|
||||||
|
|||||||
Reference in New Issue
Block a user