From 03487f83147fb2bcd27e9561ec509adb80e0a3bc Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 11 Aug 2024 22:22:16 +0800 Subject: [PATCH] More spell to stats calculation --- src/PlayerbotAI.cpp | 4 +- src/PlayerbotAI.h | 8 +- src/factory/PlayerbotFactory.cpp | 133 ++++++++++++++++------- src/factory/PlayerbotFactory.h | 1 + src/factory/StatsCollector.cpp | 76 +++++++++++-- src/factory/StatsWeightCalculator.cpp | 147 +++++++++++++++++++------- src/factory/StatsWeightCalculator.h | 3 +- 7 files changed, 278 insertions(+), 94 deletions(-) diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 34fba5ed..852df3cb 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -1677,7 +1677,7 @@ bool PlayerbotAI::IsTank(Player* player) switch (player->getClass()) { case CLASS_DEATH_KNIGHT: - if (tab == DEATHKNIGT_TAB_BLOOD) + if (tab == DEATHKNIGHT_TAB_BLOOD) { return true; } @@ -1781,7 +1781,7 @@ bool PlayerbotAI::IsDps(Player* player) } break; case CLASS_DEATH_KNIGHT: - if (tab != DEATHKNIGT_TAB_BLOOD) + if (tab != DEATHKNIGHT_TAB_BLOOD) { return true; } diff --git a/src/PlayerbotAI.h b/src/PlayerbotAI.h index fb2382fd..51e46d0b 100644 --- a/src/PlayerbotAI.h +++ b/src/PlayerbotAI.h @@ -233,11 +233,11 @@ enum PRIEST_TABS PRIEST_TAB_SHADOW, }; -enum DEATHKNIGT_TABS +enum DEATHKNIGHT_TABS { - DEATHKNIGT_TAB_BLOOD, - DEATHKNIGT_TAB_FROST, - DEATHKNIGT_TAB_UNHOLY, + DEATHKNIGHT_TAB_BLOOD, + DEATHKNIGHT_TAB_FROST, + DEATHKNIGHT_TAB_UNHOLY, }; enum DRUID_TABS diff --git a/src/factory/PlayerbotFactory.cpp b/src/factory/PlayerbotFactory.cpp index 5af68d03..23c99745 100644 --- a/src/factory/PlayerbotFactory.cpp +++ b/src/factory/PlayerbotFactory.cpp @@ -2291,6 +2291,7 @@ void PlayerbotFactory::InitClassSpells() bot->learnSpell(45462, true); bot->learnSpell(45902, true); // to leave DK starting area + bot->learnSpell(53428, false); bot->learnSpell(50977, false); break; case CLASS_HUNTER: @@ -2820,6 +2821,52 @@ void PlayerbotFactory::InitPotions() } } +std::vector PlayerbotFactory::GetCurrentGemsCount() +{ + std::vector curcount(4); + for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) + { + Item* pItem2 = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i); + if (pItem2 && !pItem2->IsBroken() && pItem2->HasSocket()) + { + for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot <= PRISMATIC_ENCHANTMENT_SLOT; ++enchant_slot) + { + if (enchant_slot == BONUS_ENCHANTMENT_SLOT) + continue; + + uint32 enchant_id = pItem2->GetEnchantmentId(EnchantmentSlot(enchant_slot)); + if (!enchant_id) + continue; + + SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if (!enchantEntry) + continue; + + uint32 gemid = enchantEntry->GemID; + if (!gemid) + continue; + + ItemTemplate const* gemProto = sObjectMgr->GetItemTemplate(gemid); + if (!gemProto) + continue; + + GemPropertiesEntry const* gemProperty = sGemPropertiesStore.LookupEntry(gemProto->GemProperties); + if (!gemProperty) + continue; + + uint8 GemColor = gemProperty->color; + + for (uint8 b = 0, tmpcolormask = 1; b < 4; b++, tmpcolormask <<= 1) + { + if (tmpcolormask & GemColor) + ++curcount[b]; + } + } + } + } + return curcount; +} + void PlayerbotFactory::InitFood() { if (sPlayerbotAIConfig->freeFood) @@ -3641,6 +3688,9 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destoryOld) { int32 bestGemEnchantId[4] = {-1, -1, -1, -1}; // 1, 2, 4, 8 color float bestGemScore[4] = {0, 0, 0, 0}; + std::vector curCount = GetCurrentGemsCount(); + int requiredActive = bot->GetLevel() <= 70 ? 2 : 1; + std::vector availableGems; for (const uint32& enchantGem : enchantGemIdCache) { ItemTemplate const* gemTemplate = sObjectMgr->GetItemTemplate(enchantGem); @@ -3676,28 +3726,7 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destoryOld) { continue; } - StatsWeightCalculator calculator(bot); - float score = calculator.CalculateEnchant(enchant_id); - if ((gemProperties->color & 1) && score >= bestGemScore[0]) - { - bestGemScore[0] = score; - bestGemEnchantId[0] = enchant_id; - } - if ((gemProperties->color & 2) && score >= bestGemScore[1]) - { - bestGemScore[1] = score; - bestGemEnchantId[1] = enchant_id; - } - if ((gemProperties->color & 4) && score >= bestGemScore[2]) - { - bestGemScore[2] = score; - bestGemEnchantId[2] = enchant_id; - } - if ((gemProperties->color & 8) && score >= bestGemScore[3]) - { - bestGemScore[3] = score; - bestGemEnchantId[3] = enchant_id; - } + availableGems.push_back(enchantGem); } for (uint8 slot = 0; slot < EQUIPMENT_SLOT_END; ++slot) @@ -3721,9 +3750,6 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destoryOld) { continue; } - - if (spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && bot->getClass() != CLASS_DEATH_KNIGHT) - continue; uint32 requiredLevel = spellInfo->BaseLevel; if (requiredLevel > bot->GetLevel()) @@ -3752,11 +3778,10 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destoryOld) { continue; } - if (enchant->requiredSkill && bot->GetSkillValue(enchant->requiredSkill) < enchant->requiredSkillValue) + if (enchant->requiredSkill && (!bot->HasSkill(enchant->requiredSkill) || (bot->GetSkillValue(enchant->requiredSkill) < enchant->requiredSkillValue))) { continue; } - if (enchant->requiredLevel > bot->GetLevel()) { continue; @@ -3787,20 +3812,52 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destoryOld) { continue; } - int32 gemId; - if (1 == socketColor) // meta - gemId = bestGemEnchantId[0]; - else if (2 == socketColor) // red - gemId = bestGemEnchantId[1]; - else if (4 == socketColor) // yellow - gemId = bestGemEnchantId[2]; - else if (8 == socketColor) // blue - gemId = bestGemEnchantId[3]; - else + int32 enchantIdChosen = -1; + int32 colorChosen; + float bestGemScore = -1; + for (uint32 &enchantGem : availableGems) + { + ItemTemplate const* gemTemplate = sObjectMgr->GetItemTemplate(enchantGem); + if (!gemTemplate) + continue; + + const GemPropertiesEntry* gemProperties = sGemPropertiesStore.LookupEntry(gemTemplate->GemProperties); + if (!gemProperties) + continue; + + if ((socketColor & gemProperties->color) == 0) + continue; + + uint32 enchant_id = gemProperties->spellitemenchantement; + if (!enchant_id) + continue; + + SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + StatsWeightCalculator calculator(bot); + float score = calculator.CalculateEnchant(enchant_id); + if (curCount[0] != 0) + // Ensure meta gem activation + for (int i = 1; i < curCount.size(); i++) + { + if (curCount[i] < requiredActive && (gemProperties->color & (1 << i))) + { + score *= 2; + break; + } + } + if (score > bestGemScore) + { + enchantIdChosen = enchant_id; + colorChosen = gemProperties->color; + bestGemScore = score; + } + } + if (enchantIdChosen == -1) continue; bot->ApplyEnchantment(item, EnchantmentSlot(enchant_slot), false); - item->SetEnchantment(EnchantmentSlot(enchant_slot), gemId, 0, 0, bot->GetGUID()); + item->SetEnchantment(EnchantmentSlot(enchant_slot), enchantIdChosen, 0, 0, bot->GetGUID()); bot->ApplyEnchantment(item, EnchantmentSlot(enchant_slot), true); + curCount = GetCurrentGemsCount(); } } } diff --git a/src/factory/PlayerbotFactory.h b/src/factory/PlayerbotFactory.h index 664c2b3d..65de201b 100644 --- a/src/factory/PlayerbotFactory.h +++ b/src/factory/PlayerbotFactory.h @@ -158,6 +158,7 @@ private: void ResetQuests(); void InitPotions(); + std::vector GetCurrentGemsCount(); bool CanEquipArmor(ItemTemplate const* proto); bool CanEquipWeapon(ItemTemplate const* proto); void EnchantItem(Item* item); diff --git a/src/factory/StatsCollector.cpp b/src/factory/StatsCollector.cpp index f940d7a9..8bfd63dd 100644 --- a/src/factory/StatsCollector.cpp +++ b/src/factory/StatsCollector.cpp @@ -43,7 +43,26 @@ void StatsCollector::CollectItemStats(ItemTemplate const* proto) } for (uint8 j = 0; j < MAX_ITEM_PROTO_SPELLS; j++) { - CollectSpellStats(proto->Spells[j].SpellId, 1.0f, proto->Spells[j].SpellCooldown); + switch (proto->Spells[j].SpellTrigger) + { + case ITEM_SPELLTRIGGER_ON_USE: + CollectSpellStats(proto->Spells[j].SpellId, 1.0f, proto->Spells[j].SpellCooldown); + break; + case ITEM_SPELLTRIGGER_ON_EQUIP: + CollectSpellStats(proto->Spells[j].SpellId, 1.0f, 0); + break; + case ITEM_SPELLTRIGGER_CHANCE_ON_HIT: + if (type_ == CollectorType::MELEE) + { + if (proto->Spells[j].SpellPPMRate > 0.01f) + CollectSpellStats(proto->Spells[j].SpellId, 1.0f, 60000 / proto->Spells[j].SpellPPMRate); + else + CollectSpellStats(proto->Spells[j].SpellId, 1.0f, 60000 / 1.8f); // Default PPM = 1.8 + } + break; + default: + break; + } } if (proto->socketBonus) @@ -79,7 +98,13 @@ void StatsCollector::CollectSpellStats(uint32 spellId, float multiplier, int32 s canNextTrigger = false; if (spellInfo->StackAmount) { - multiplier *= 0.2f + spellInfo->StackAmount * 0.8; + // Heuristic multiplier for stackAmount since high stackAmount may not be available + if (spellInfo->StackAmount <= 10) + multiplier *= spellInfo->StackAmount * 0.6; + else if (spellInfo->StackAmount <= 20) + multiplier *= 6 + (spellInfo->StackAmount - 10) * 0.4; + else + multiplier *= 10; } for (int i = 0; i < MAX_SPELL_EFFECTS; i++) @@ -105,22 +130,45 @@ void StatsCollector::CollectSpellStats(uint32 spellId, float multiplier, int32 s } case SPELL_EFFECT_HEAL: { + /// @todo Handle spell without cooldown if (!spellCooldown) break; - float normalizedCd = std::max(spellCooldown, 5000); + float normalizedCd = std::max((float)spellCooldown / 1000, 5.0f); int32 val = AverageValue(effectInfo); - stats[STATS_TYPE_HEAL_POWER] += (float)val / (normalizedCd / 1000) * multiplier; + float transfer_multiplier = 1; + stats[STATS_TYPE_HEAL_POWER] += (float)val / normalizedCd * multiplier * transfer_multiplier; break; } case SPELL_EFFECT_ENERGIZE: { + /// @todo Handle spell without cooldown if (!spellCooldown) break; if (effectInfo.MiscValue != POWER_MANA) break; - float normalizedCd = std::max(spellCooldown, 5000); + float normalizedCd = std::max((float)spellCooldown / 1000, 5.0f); int32 val = AverageValue(effectInfo); - stats[STATS_TYPE_MANA_REGENERATION] += (float)val / (normalizedCd / 1000 / 5) * multiplier; + float transfer_multiplier = 0.2; + stats[STATS_TYPE_MANA_REGENERATION] += (float)val / normalizedCd * multiplier * transfer_multiplier; + break; + } + case SPELL_EFFECT_SCHOOL_DAMAGE: + { + /// @todo Handle spell without cooldown + if (!spellCooldown) + break; + float normalizedCd = std::max((float)spellCooldown / 1000, 5.0f); + int32 val = AverageValue(effectInfo); + if (type_ == CollectorType::MELEE || type_ == CollectorType::RANGED) + { + float transfer_multiplier = 1; + stats[STATS_TYPE_ATTACK_POWER] += (float)val / normalizedCd * multiplier * transfer_multiplier; + } + else if (type_ == CollectorType::SPELL_DMG) + { + float transfer_multiplier = 0.5; + stats[STATS_TYPE_SPELL_POWER] += (float)val / normalizedCd * multiplier * transfer_multiplier; + } break; } default: @@ -144,12 +192,13 @@ void StatsCollector::CollectEnchantStats(SpellItemEnchantmentEntry const* enchan { case ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL: { - CollectSpellStats(enchant_spell_id, true); + if (type_ == CollectorType::MELEE) + CollectSpellStats(enchant_spell_id, 0.25f); break; } case ITEM_ENCHANTMENT_TYPE_EQUIP_SPELL: { - CollectSpellStats(enchant_spell_id, false); + CollectSpellStats(enchant_spell_id, 1.0f); break; } case ITEM_ENCHANTMENT_TYPE_STAT: @@ -207,10 +256,16 @@ bool StatsCollector::SpecialEnchantFilter(uint32 enchantSpellId) { switch (enchantSpellId) { + case 64440: + if (type_ == CollectorType::MELEE) + { + stats[STATS_TYPE_PARRY] += 50; + } + return true; case 53365: // Rune of the Fallen Crusader if (type_ == CollectorType::MELEE) { - stats[STATS_TYPE_STRENGTH] += 60; + stats[STATS_TYPE_STRENGTH] += 75; } return true; case 62157: // Rune of the Stoneskin Gargoyle @@ -296,7 +351,7 @@ void StatsCollector::CollectByItemStatType(uint32 itemStatType, int32 val) stats[STATS_TYPE_MANA_REGENERATION] += val / 10; break; case ITEM_MOD_HEALTH: - stats[STATS_TYPE_STAMINA] += val / 12; + stats[STATS_TYPE_STAMINA] += val / 15; break; case ITEM_MOD_AGILITY: stats[STATS_TYPE_AGILITY] += val; @@ -545,7 +600,6 @@ void StatsCollector::HandleApplyAura(const SpellEffectInfo& effectInfo, float mu break; } } - break; } } case SPELL_AURA_MOD_POWER_REGEN: diff --git a/src/factory/StatsWeightCalculator.cpp b/src/factory/StatsWeightCalculator.cpp index 267a5aef..2797ae0d 100644 --- a/src/factory/StatsWeightCalculator.cpp +++ b/src/factory/StatsWeightCalculator.cpp @@ -32,6 +32,7 @@ StatsWeightCalculator::StatsWeightCalculator(Player* player) : player_(player) enable_overflow_penalty_ = true; enable_item_set_bonus_ = true; + enable_quality_blend_ = true; } void StatsWeightCalculator::Reset() @@ -68,8 +69,9 @@ float StatsWeightCalculator::CalculateItem(uint32 itemId) CalculateSocketBonus(player_, proto); - // Blend with item quality and level - weight_ *= (proto->Quality + 1) * proto->ItemLevel; + // if (enable_quality_blend_) + // // Blend with item quality and level + // weight_ *= (proto->Quality + 1) * proto->ItemLevel; return weight_; } @@ -109,43 +111,112 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player) stats_weights_[STATS_TYPE_STAMINA] += 0.01f; stats_weights_[STATS_TYPE_ARMOR] += 0.001f; - if (cls == CLASS_HUNTER) + if (cls == CLASS_HUNTER && (tab == HUNTER_TAB_BEASTMASTER || tab == HUNTER_TAB_SURVIVAL)) { - stats_weights_[STATS_TYPE_AGILITY] += 2.5f; + stats_weights_[STATS_TYPE_AGILITY] += 2.4f; stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f; - stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 2.5f; - stats_weights_[STATS_TYPE_HIT] += 2.0f; + stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.3f; + stats_weights_[STATS_TYPE_HIT] += 1.6f; + stats_weights_[STATS_TYPE_CRIT] += 1.5f; + stats_weights_[STATS_TYPE_HASTE] += 1.4f; + stats_weights_[STATS_TYPE_RANGED_DPS] += 5.0f; + } + else if (cls == CLASS_HUNTER && tab == HUNTER_TAB_MARKSMANSHIP) + { + stats_weights_[STATS_TYPE_AGILITY] += 2.2f; + stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f; + stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 2.2f; + stats_weights_[STATS_TYPE_HIT] += 2.1f; stats_weights_[STATS_TYPE_CRIT] += 2.0f; - stats_weights_[STATS_TYPE_HASTE] += 2.0f; + stats_weights_[STATS_TYPE_HASTE] += 1.8f; stats_weights_[STATS_TYPE_RANGED_DPS] += 5.0f; } - else if (cls == CLASS_ROGUE || (cls == CLASS_DRUID && tab == DRUID_TAB_FERAL && !PlayerbotAI::IsTank(player))) + else if ((cls == CLASS_ROGUE && tab == ROGUE_TAB_COMBAT) || (cls == CLASS_DRUID && tab == DRUID_TAB_FERAL && !PlayerbotAI::IsTank(player))) { - stats_weights_[STATS_TYPE_AGILITY] += 2.0f; - stats_weights_[STATS_TYPE_STRENGTH] += 1.0f; + stats_weights_[STATS_TYPE_AGILITY] += 1.8f; + stats_weights_[STATS_TYPE_STRENGTH] += 1.1f; stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f; - stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.5f; - stats_weights_[STATS_TYPE_HIT] += 1.5f; - stats_weights_[STATS_TYPE_CRIT] += 1.5f; - stats_weights_[STATS_TYPE_HASTE] += 1.5f; - stats_weights_[STATS_TYPE_EXPERTISE] += 2.5f; + stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.2f; + stats_weights_[STATS_TYPE_HIT] += 2.0f; + stats_weights_[STATS_TYPE_CRIT] += 1.6f; + stats_weights_[STATS_TYPE_HASTE] += 1.4f; + stats_weights_[STATS_TYPE_EXPERTISE] += 2.0f; stats_weights_[STATS_TYPE_MELEE_DPS] += 5.0f; - } - else if ((cls == CLASS_PALADIN && tab == 2) || // retribution - (cls == CLASS_WARRIOR && tab != 2) || // arm / fury - (cls == CLASS_DEATH_KNIGHT && tab != 0) // ice / unholy - ) + } + else if (cls == CLASS_ROGUE && (tab == ROGUE_TAB_ASSASSINATION || tab == ROGUE_TAB_SUBTLETY)) { - stats_weights_[STATS_TYPE_AGILITY] += 1.0f; - stats_weights_[STATS_TYPE_STRENGTH] += 2.0f; + stats_weights_[STATS_TYPE_AGILITY] += 1.7f; + stats_weights_[STATS_TYPE_STRENGTH] += 1.1f; stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f; - stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 2.0f; - stats_weights_[STATS_TYPE_HIT] += 1.5f; - stats_weights_[STATS_TYPE_CRIT] += 1.5f; + stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.0f; + stats_weights_[STATS_TYPE_HIT] += 1.6f; + stats_weights_[STATS_TYPE_CRIT] += 1.3f; stats_weights_[STATS_TYPE_HASTE] += 1.5f; stats_weights_[STATS_TYPE_EXPERTISE] += 2.0f; stats_weights_[STATS_TYPE_MELEE_DPS] += 5.0f; } + else if (cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY) // fury + { + stats_weights_[STATS_TYPE_AGILITY] += 1.8f; + stats_weights_[STATS_TYPE_STRENGTH] += 2.6f; + stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f; + stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 2.1f; + stats_weights_[STATS_TYPE_HIT] += 2.3f; + stats_weights_[STATS_TYPE_CRIT] += 2.2f; + stats_weights_[STATS_TYPE_HASTE] += 1.8f; + stats_weights_[STATS_TYPE_EXPERTISE] += 2.5f; + stats_weights_[STATS_TYPE_MELEE_DPS] += 7.0f; + } + else if (cls == CLASS_WARRIOR && tab == WARRIOR_TAB_ARMS) // arm + { + stats_weights_[STATS_TYPE_AGILITY] += 1.6f; + stats_weights_[STATS_TYPE_STRENGTH] += 2.3f; + stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f; + stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.7f; + stats_weights_[STATS_TYPE_HIT] += 2.0f; + stats_weights_[STATS_TYPE_CRIT] += 1.9f; + stats_weights_[STATS_TYPE_HASTE] += 0.8f; + stats_weights_[STATS_TYPE_EXPERTISE] += 1.4f; + stats_weights_[STATS_TYPE_MELEE_DPS] += 7.0f; + } + else if (cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_FROST) // frost dk + { + stats_weights_[STATS_TYPE_AGILITY] += 1.8f; + stats_weights_[STATS_TYPE_STRENGTH] += 2.6f; + stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f; + stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 2.1f; + stats_weights_[STATS_TYPE_HIT] += 2.3f; + stats_weights_[STATS_TYPE_CRIT] += 2.2f; + stats_weights_[STATS_TYPE_HASTE] += 1.8f; + stats_weights_[STATS_TYPE_EXPERTISE] += 2.5f; + stats_weights_[STATS_TYPE_MELEE_DPS] += 7.0f; + } + else if (cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_UNHOLY) + { + stats_weights_[STATS_TYPE_AGILITY] += 0.5f; + stats_weights_[STATS_TYPE_STRENGTH] += 2.5f; + stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f; + stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 1.0f; + stats_weights_[STATS_TYPE_HIT] += 1.8f; + stats_weights_[STATS_TYPE_CRIT] += 1.0f; + stats_weights_[STATS_TYPE_HASTE] += 1.7f; + stats_weights_[STATS_TYPE_EXPERTISE] += 1.0f; + stats_weights_[STATS_TYPE_MELEE_DPS] += 5.0f; + } + else if (cls == CLASS_PALADIN && tab == PALADIN_TAB_RETRIBUTION) // retribution + { + stats_weights_[STATS_TYPE_AGILITY] += 1.1f; + stats_weights_[STATS_TYPE_STRENGTH] += 2.5f; + stats_weights_[STATS_TYPE_INTELLECT] += 0.15f; + stats_weights_[STATS_TYPE_ATTACK_POWER] += 1.0f; + stats_weights_[STATS_TYPE_SPELL_POWER] += 0.3f; + stats_weights_[STATS_TYPE_ARMOR_PENETRATION] += 0.8f; + stats_weights_[STATS_TYPE_HIT] += 1.9f; + stats_weights_[STATS_TYPE_CRIT] += 1.2f; + stats_weights_[STATS_TYPE_HASTE] += 1.3f; + stats_weights_[STATS_TYPE_EXPERTISE] += 2.0f; + stats_weights_[STATS_TYPE_MELEE_DPS] += 7.0f; + } else if ((cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ENHANCEMENT)) // enhancement { stats_weights_[STATS_TYPE_AGILITY] += 1.6f; @@ -158,7 +229,7 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player) stats_weights_[STATS_TYPE_CRIT] += 1.4f; stats_weights_[STATS_TYPE_HASTE] += 1.8f; stats_weights_[STATS_TYPE_EXPERTISE] += 2.0f; - stats_weights_[STATS_TYPE_MELEE_DPS] += 5.0f; + stats_weights_[STATS_TYPE_MELEE_DPS] += 5.2f; } else if (cls == CLASS_WARLOCK || cls == CLASS_MAGE || (cls == CLASS_PRIEST && tab == PRIEST_TAB_SHADOW) || // shadow @@ -166,11 +237,11 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player) (cls == CLASS_DRUID && tab == DRUID_TAB_BALANCE)) // balance { stats_weights_[STATS_TYPE_INTELLECT] += 0.5f; - stats_weights_[STATS_TYPE_SPIRIT] += 0.5f; + stats_weights_[STATS_TYPE_SPIRIT] += 0.4f; stats_weights_[STATS_TYPE_SPELL_POWER] += 1.0f; stats_weights_[STATS_TYPE_SPELL_PENETRATION] += 1.0f; - stats_weights_[STATS_TYPE_HIT] += 1.0f; - stats_weights_[STATS_TYPE_CRIT] += 1.0f; + stats_weights_[STATS_TYPE_HIT] += 1.1f; + stats_weights_[STATS_TYPE_CRIT] += 0.8f; stats_weights_[STATS_TYPE_HASTE] += 1.0f; stats_weights_[STATS_TYPE_RANGED_DPS] += 1.0f; } @@ -182,12 +253,12 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player) stats_weights_[STATS_TYPE_INTELLECT] += 0.8f; stats_weights_[STATS_TYPE_SPIRIT] += 0.8f; stats_weights_[STATS_TYPE_HEAL_POWER] += 1.0f; - stats_weights_[STATS_TYPE_MANA_REGENERATION] += 1.5f; + stats_weights_[STATS_TYPE_MANA_REGENERATION] += 1.2f; stats_weights_[STATS_TYPE_CRIT] += 0.7f; stats_weights_[STATS_TYPE_HASTE] += 1.0f; stats_weights_[STATS_TYPE_RANGED_DPS] += 1.0f; } - else if ((cls == CLASS_WARRIOR && tab == 2) || (cls == CLASS_PALADIN && tab == 1)) + else if ((cls == CLASS_WARRIOR && tab == WARRIOR_TAB_PROTECTION) || (cls == CLASS_PALADIN && tab == PALADIN_TAB_PROTECTION)) { stats_weights_[STATS_TYPE_AGILITY] += 2.0f; stats_weights_[STATS_TYPE_STRENGTH] += 1.0f; @@ -199,14 +270,14 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player) stats_weights_[STATS_TYPE_RESILIENCE] += 2.0f; stats_weights_[STATS_TYPE_BLOCK_RATING] += 1.0f; stats_weights_[STATS_TYPE_BLOCK_VALUE] += 0.5f; - stats_weights_[STATS_TYPE_ARMOR] += 0.3f; + stats_weights_[STATS_TYPE_ARMOR] += 0.15f; stats_weights_[STATS_TYPE_HIT] += 2.0f; stats_weights_[STATS_TYPE_CRIT] += 0.2f; stats_weights_[STATS_TYPE_HASTE] += 0.5f; stats_weights_[STATS_TYPE_EXPERTISE] += 3.0f; stats_weights_[STATS_TYPE_MELEE_DPS] += 2.0f; } - else if (cls == CLASS_DEATH_KNIGHT && tab == 0) + else if (cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_BLOOD) { stats_weights_[STATS_TYPE_AGILITY] += 2.0f; stats_weights_[STATS_TYPE_STRENGTH] += 1.0f; @@ -216,7 +287,7 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player) stats_weights_[STATS_TYPE_PARRY] += 2.0f; stats_weights_[STATS_TYPE_DODGE] += 2.0f; stats_weights_[STATS_TYPE_RESILIENCE] += 2.0f; - stats_weights_[STATS_TYPE_ARMOR] += 0.3f; + stats_weights_[STATS_TYPE_ARMOR] += 0.15f; stats_weights_[STATS_TYPE_HIT] += 2.0f; stats_weights_[STATS_TYPE_CRIT] += 0.5f; stats_weights_[STATS_TYPE_HASTE] += 0.5f; @@ -249,7 +320,7 @@ void StatsWeightCalculator::GenerateAdditionalWeights(Player* player) if (cls == CLASS_HUNTER) { if (player->HasAura(34484)) - stats_weights_[STATS_TYPE_INTELLECT] += 1.0f; + stats_weights_[STATS_TYPE_INTELLECT] += 1.1f; } else if (cls == CLASS_WARRIOR) { @@ -259,7 +330,7 @@ void StatsWeightCalculator::GenerateAdditionalWeights(Player* player) else if (cls == CLASS_SHAMAN) { if (player->HasAura(51885)) - stats_weights_[STATS_TYPE_INTELLECT] += 1.0f; + stats_weights_[STATS_TYPE_INTELLECT] += 1.1f; } } @@ -348,7 +419,7 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto) // enhancement, rogue, ice dk, unholy dk, shield tank, fury warrior without titan's grip but with duel wield if (isDoubleHand && ((cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ENHANCEMENT && player_->CanDualWield()) || - (cls == CLASS_ROGUE) || (cls == CLASS_DEATH_KNIGHT && tab != DEATHKNIGT_TAB_BLOOD) || + (cls == CLASS_ROGUE) || (cls == CLASS_DEATH_KNIGHT && tab != DEATHKNIGHT_TAB_BLOOD) || (cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !player_->CanTitanGrip() && player_->CanDualWield()) || (cls == CLASS_WARRIOR && tab == WARRIOR_TAB_PROTECTION) || (cls == CLASS_PALADIN && tab == PALADIN_TAB_PROTECTION))) @@ -361,7 +432,7 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto) ((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 == DEATHKNIGT_TAB_BLOOD) || + (cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_BLOOD) || (cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ENHANCEMENT && !player_->CanDualWield()))) { weight_ *= 10; diff --git a/src/factory/StatsWeightCalculator.h b/src/factory/StatsWeightCalculator.h index 1bef2a56..030f1540 100644 --- a/src/factory/StatsWeightCalculator.h +++ b/src/factory/StatsWeightCalculator.h @@ -52,7 +52,8 @@ private: int tab; bool enable_overflow_penalty_; bool enable_item_set_bonus_; - + bool enable_quality_blend_; + float weight_; float stats_weights_[STATS_TYPE_MAX]; };