TrinityCore
Loading...
Searching...
No Matches
StatSystem.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "Unit.h"
19#include "Creature.h"
20#include "Item.h"
21#include "Pet.h"
22#include "Player.h"
23#include "SharedDefines.h"
24#include "SpellAuras.h"
25#include "SpellAuraEffects.h"
26#include "SpellMgr.h"
27#include "World.h"
28#include <numeric>
29
30inline bool _ModifyUInt32(bool apply, uint32& baseValue, int32& amount)
31{
32 // If amount is negative, change sign and value of apply.
33 if (amount < 0)
34 {
35 apply = !apply;
36 amount = -amount;
37 }
38 if (apply)
39 baseValue += amount;
40 else
41 {
42 // Make sure we do not get uint32 overflow.
43 if (amount > int32(baseValue))
44 amount = baseValue;
45 baseValue -= amount;
46 }
47 return apply;
48}
49
50/*#######################################
51######## ########
52######## UNIT STAT SYSTEM ########
53######## ########
54#######################################*/
55
61
63{
64 float totalMin = 0.f;
65 float totalMax = 0.f;
66
67 float tmpMin, tmpMax;
68 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
69 {
70 CalculateMinMaxDamage(attType, false, true, tmpMin, tmpMax, i);
71 totalMin += tmpMin;
72 totalMax += tmpMax;
73 }
74
75 switch (attType)
76 {
77 case BASE_ATTACK:
78 default:
81 break;
82 case OFF_ATTACK:
85 break;
86 case RANGED_ATTACK:
89 break;
90 }
91}
92
93/*#######################################
94######## ########
95######## PLAYERS STAT SYSTEM ########
96######## ########
97#######################################*/
98
100{
101 if (stat > STAT_SPIRIT)
102 return false;
103
104 // value = ((base_value * base_pct) + total_value) * total_pct
105 float value = GetTotalStatValue(stat);
106
107 SetStat(stat, int32(value));
108
109 if (stat == STAT_STAMINA || stat == STAT_INTELLECT || stat == STAT_STRENGTH)
110 {
111 Pet* pet = GetPet();
112 if (pet)
113 pet->UpdateStats(stat);
114 }
115
116 switch (stat)
117 {
118 case STAT_STRENGTH:
120 break;
121 case STAT_AGILITY:
122 UpdateArmor();
125 break;
126 case STAT_STAMINA:
128 break;
129 case STAT_INTELLECT:
132 UpdateArmor(); //SPELL_AURA_MOD_RESISTANCE_OF_INTELLECT_PERCENT, only armor currently
133 break;
134 case STAT_SPIRIT:
135 break;
136 default:
137 break;
138 }
139
140 if (stat == STAT_STRENGTH)
141 {
145 }
146 else if (stat == STAT_AGILITY)
147 {
150 }
151 else
152 {
153 // Need update (exist AP from stat auras)
158 }
159
162
163 // Update ratings in exist SPELL_AURA_MOD_RATING_FROM_STAT and only depends from stat
164 uint32 mask = 0;
166 for (AuraEffectList::const_iterator i = modRatingFromStat.begin(); i != modRatingFromStat.end(); ++i)
167 if (Stats((*i)->GetMiscValueB()) == stat)
168 mask |= (*i)->GetMiscValue();
169 if (mask)
170 {
171 for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
172 if (mask & (1 << rating))
173 ApplyRatingMod(CombatRating(rating), 0, true);
174 }
175 return true;
176}
177
178void Player::ApplySpellPowerBonus(int32 amount, bool apply)
179{
180 apply = _ModifyUInt32(apply, m_baseSpellPower, amount);
181
182 // For speed just update for client
184 for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
186}
187
189{
190 // Magic damage modifiers implemented in Unit::SpellDamageBonusDone
191 // This information for client side use only
192 // Get healing bonus for all schools
194 // Get damage bonus for all schools
196 for (uint16 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
197 {
198 SetInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + i, std::accumulate(modDamageAuras.begin(), modDamageAuras.end(), 0, [i](int32 negativeMod, AuraEffect const* aurEff)
199 {
200 if (aurEff->GetAmount() < 0 && aurEff->GetMiscValue() & (1 << i))
201 negativeMod += aurEff->GetAmount();
202 return negativeMod;
203 }));
205 }
206}
207
241
243{
245 m_spellPenetrationItemMod += apply ? amount : -amount;
246}
247
249{
250 if (school > SPELL_SCHOOL_NORMAL)
251 {
253 SetResistance(SpellSchools(school), int32(value));
254
255 Pet* pet = GetPet();
256 if (pet)
257 pet->UpdateResistances(school);
258 }
259 else
260 UpdateArmor();
261}
262
264{
265 UnitMods unitMod = UNIT_MOD_ARMOR;
266
267 float value = GetFlatModifierValue(unitMod, BASE_VALUE); // base armor (from items)
268 value *= GetPctModifierValue(unitMod, BASE_PCT); // armor percent from items
269 value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats
270 value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
271
272 //add dynamic flat mods
274 for (AuraEffectList::const_iterator i = mResbyIntellect.begin(); i != mResbyIntellect.end(); ++i)
275 {
276 if ((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
277 value += CalculatePct(GetStat(Stats((*i)->GetMiscValueB())), (*i)->GetAmount());
278 }
279
280 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
281
282 SetArmor(int32(value));
283
284 Pet* pet = GetPet();
285 if (pet)
286 pet->UpdateArmor();
287}
288
290{
291 float stamina = GetStat(STAT_STAMINA);
292 float baseStam = std::min(20.0f, stamina);
293 float moreStam = stamina - baseStam;
294
295 return baseStam + (moreStam * 10.0f);
296}
297
299{
300 float intellect = GetStat(STAT_INTELLECT);
301
302 float baseInt = std::min(20.0f, intellect);
303 float moreInt = intellect - baseInt;
304
305 return baseInt + (moreInt * 15.0f);
306}
307
309{
310 UnitMods unitMod = UNIT_MOD_HEALTH;
311
312 float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
313 value *= GetPctModifierValue(unitMod, BASE_PCT);
315 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
316
317 SetMaxHealth((uint32)value);
318}
319
321{
323
324 float bonusPower = (power == POWER_MANA && GetCreatePowerValue(power) > 0) ? GetManaBonusFromIntellect() : 0;
325
326 float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreatePowerValue(power);
327 value *= GetPctModifierValue(unitMod, BASE_PCT);
328 value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + bonusPower;
329 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
330
331 SetMaxPower(power, uint32(std::lroundf(value)));
332}
333
334void Player::ApplyFeralAPBonus(int32 amount, bool apply)
335{
336 _ModifyUInt32(apply, m_baseFeralAP, amount);
338}
339
341{
342 float val2 = 0.0f;
343 float level = float(GetLevel());
344
346
347 if (ranged)
348 {
349 switch (GetClass())
350 {
351 case CLASS_HUNTER:
352 val2 = level * 2.0f + GetStat(STAT_AGILITY) - 10.0f;
353 break;
354 case CLASS_ROGUE:
355 val2 = level + GetStat(STAT_AGILITY) - 10.0f;
356 break;
357 case CLASS_WARRIOR:
358 val2 = level + GetStat(STAT_AGILITY) - 10.0f;
359 break;
360 case CLASS_DRUID:
361 switch (GetShapeshiftForm())
362 {
363 case FORM_CAT:
364 case FORM_BEAR:
365 case FORM_DIREBEAR:
366 val2 = 0.0f; break;
367 default:
368 val2 = GetStat(STAT_AGILITY) - 10.0f; break;
369 }
370 break;
371 default: val2 = GetStat(STAT_AGILITY) - 10.0f; break;
372 }
373 }
374 else
375 {
376 switch (GetClass())
377 {
378 case CLASS_WARRIOR:
379 val2 = level * 3.0f + GetStat(STAT_STRENGTH) * 2.0f - 20.0f;
380 break;
381 case CLASS_PALADIN:
382 val2 = level * 3.0f + GetStat(STAT_STRENGTH) * 2.0f - 20.0f;
383 break;
385 val2 = level * 3.0f + GetStat(STAT_STRENGTH) * 2.0f - 20.0f;
386 break;
387 case CLASS_ROGUE:
388 val2 = level * 2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f;
389 break;
390 case CLASS_HUNTER:
391 val2 = level * 2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f;
392 break;
393 case CLASS_SHAMAN:
394 val2 = level * 2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f;
395 break;
396 case CLASS_DRUID:
397 {
398 // Check if Predatory Strikes is skilled
399 float levelBonus = 0.0f;
400 float weaponBonus = 0.0f;
401 if (IsInFeralForm())
402 {
404 levelBonus = CalculatePct(1.0f, levelMod->GetAmount());
405
406 // = 0 if removing the weapon, do not calculate bonus (uses template)
407 if (m_baseFeralAP)
408 {
409 if (Item const* weapon = m_items[EQUIPMENT_SLOT_MAINHAND])
410 {
412 {
413 ItemTemplate const* itemTemplate = weapon->GetTemplate();
414 int32 bonusAP = itemTemplate->GetTotalAPBonus() + m_baseFeralAP;
415 weaponBonus = CalculatePct(static_cast<float>(bonusAP), weaponMod->GetAmount());
416 }
417 }
418 }
419 }
420
421 switch (GetShapeshiftForm())
422 {
423 case FORM_CAT:
424 val2 = GetLevel() * levelBonus + GetStat(STAT_STRENGTH) * 2.0f + GetStat(STAT_AGILITY) - 20.0f + weaponBonus + m_baseFeralAP;
425 break;
426 case FORM_BEAR:
427 case FORM_DIREBEAR:
428 val2 = GetLevel() * levelBonus + GetStat(STAT_STRENGTH) * 2.0f - 20.0f + weaponBonus + m_baseFeralAP;
429 break;
430 case FORM_MOONKIN:
431 val2 = GetStat(STAT_STRENGTH) * 2.0f - 20.0f + m_baseFeralAP;
432 break;
433 default:
434 val2 = GetStat(STAT_STRENGTH) * 2.0f - 20.0f;
435 break;
436 }
437 break;
438 }
439 case CLASS_MAGE:
440 val2 = GetStat(STAT_STRENGTH) - 10.0f;
441 break;
442 case CLASS_PRIEST:
443 val2 = GetStat(STAT_STRENGTH) - 10.0f;
444 break;
445 case CLASS_WARLOCK:
446 val2 = GetStat(STAT_STRENGTH) - 10.0f;
447 break;
448 }
449 }
450
451 float baseAttackPower = val2;
452 float attackPowerModPos = GetAttackPowerModifierValue(unitMod, AttackPowerModType::FlatPositive);
453 float attackPowerModNeg = GetAttackPowerModifierValue(unitMod, AttackPowerModType::FlatNegative);
454 float attackPowerMultiplier = GetAttackPowerModifierValue(unitMod, AttackPowerModType::Pct) - 1.0f;
455
456 // Dynamic flat mods: routed to pos or neg based on sign
457 auto accumulateMod = [&attackPowerModPos, &attackPowerModNeg](float value)
458 {
459 if (value >= 0.0f)
460 attackPowerModPos += value;
461 else
462 attackPowerModNeg += value;
463 };
464
465 if (ranged)
466 {
467 if ((GetClassMask() & CLASSMASK_WAND_USERS) == 0)
468 {
470 for (AuraEffect const* aurEff : mRAPbyStat)
471 accumulateMod(CalculatePct(GetStat(Stats(aurEff->GetMiscValue())), aurEff->GetAmount()));
472 }
473 }
474 else
475 {
477 for (AuraEffect const* aurEff : mAPbyStat)
478 accumulateMod(CalculatePct(GetStat(Stats(aurEff->GetMiscValue())), aurEff->GetAmount()));
479 }
480
481 // applies to both, amount updated in PeriodicTick each 30 seconds
483
484 if (ranged)
485 {
486 SetRangedAttackPower(int32(baseAttackPower));
487 SetRangedAttackPowerModPos(int32(attackPowerModPos));
488 SetRangedAttackPowerModNeg(int32(attackPowerModNeg));
489 SetRangedAttackPowerMultiplier(attackPowerMultiplier);
490 }
491 else
492 {
493 SetAttackPower(int32(baseAttackPower));
494 SetAttackPowerModPos(int32(attackPowerModPos));
495 SetAttackPowerModNeg(int32(attackPowerModNeg));
496 SetAttackPowerMultiplier(attackPowerMultiplier);
497 }
498
499 Pet* pet = GetPet(); //update pet's AP
500 Guardian* guardian = GetGuardianPet();
501 //automatically update weapon damage after attack power modification
502 if (ranged)
503 {
505 if (pet && pet->IsHunterPet()) // At ranged attack change for hunter pet
507 }
508 else
509 {
511 if (CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon
513 if (GetClass() == CLASS_SHAMAN || GetClass() == CLASS_PALADIN) // mental quickness
515
516 if (pet && (pet->IsPetGhoul() || pet->IsRisenAlly())) // At melee attack power change for DK pet
518
519 if (guardian && guardian->IsSpiritWolf()) // At melee attack power change for Shaman feral spirit
520 guardian->UpdateAttackPowerAndDamage();
521 }
522}
523
528
529void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex) const
530{
531 // Only proto damage, not affected by any mods
532 if (damageIndex != 0)
533 {
534 minDamage = 0.0f;
535 maxDamage = 0.0f;
536
537 if (!IsInFeralForm() && CanUseAttackType(attType))
538 {
539 minDamage = GetWeaponDamageRange(attType, MINDAMAGE, damageIndex);
540 maxDamage = GetWeaponDamageRange(attType, MAXDAMAGE, damageIndex);
541 }
542 return;
543 }
544
545 UnitMods unitMod;
546
547 switch (attType)
548 {
549 case BASE_ATTACK:
550 default:
551 unitMod = UNIT_MOD_DAMAGE_MAINHAND;
552 break;
553 case OFF_ATTACK:
554 unitMod = UNIT_MOD_DAMAGE_OFFHAND;
555 break;
556 case RANGED_ATTACK:
557 unitMod = UNIT_MOD_DAMAGE_RANGED;
558 break;
559 }
560
561 float const attackPowerMod = std::max(GetAPMultiplier(attType, normalized), 0.25f);
562
563 float baseValue = GetFlatModifierValue(unitMod, BASE_VALUE);
564 baseValue += GetTotalAttackPowerValue(attType) / 14.0f * attackPowerMod;
565
566 float basePct = GetPctModifierValue(unitMod, BASE_PCT);
567 float totalValue = GetFlatModifierValue(unitMod, TOTAL_VALUE);
568 float totalPct = addTotalPct ? GetPctModifierValue(unitMod, TOTAL_PCT) : 1.0f;
569
570 float weaponMinDamage = GetWeaponDamageRange(attType, MINDAMAGE);
571 float weaponMaxDamage = GetWeaponDamageRange(attType, MAXDAMAGE);
572
573 // check if player is druid and in cat or bear forms
574 if (IsInFeralForm())
575 {
576 uint8 lvl = GetLevel();
577 if (lvl > 60)
578 lvl = 60;
579
580 weaponMinDamage = lvl * 0.85f * attackPowerMod;
581 weaponMaxDamage = lvl * 1.25f * attackPowerMod;
582 }
583 else if (!CanUseAttackType(attType)) // check if player not in form but still can't use (disarm case)
584 {
585 // cannot use ranged/off attack, set values to 0
586 if (attType != BASE_ATTACK)
587 {
588 minDamage = 0.f;
589 maxDamage = 0.f;
590 return;
591 }
592
593 weaponMinDamage = BASE_MINDAMAGE;
594 weaponMaxDamage = BASE_MAXDAMAGE;
595 }
596 else if (attType == RANGED_ATTACK) // add ammo DPS to ranged primary damage
597 {
598 weaponMinDamage += GetAmmoDPS() * attackPowerMod;
599 weaponMaxDamage += GetAmmoDPS() * attackPowerMod;
600 }
601
602 minDamage = ((weaponMinDamage + baseValue) * basePct + totalValue) * totalPct;
603 maxDamage = ((weaponMaxDamage + baseValue) * basePct + totalValue) * totalPct;
604}
605
612
614{
615 // No block
616 float value = 0.0f;
617 if (CanBlock())
618 {
619 // Base value
620 value = 5.0f;
621 // Modify value from defense skill
622 value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
623 // Increase from SPELL_AURA_MOD_BLOCK_PERCENT aura
625 // Increase from rating
627
628 if (sWorld->getBoolConfig(CONFIG_STATS_LIMITS_ENABLE))
629 value = value > sWorld->getFloatConfig(CONFIG_STATS_LIMITS_BLOCK) ? sWorld->getFloatConfig(CONFIG_STATS_LIMITS_BLOCK) : value;
630
631 value = value < 0.0f ? 0.0f : value;
632 }
634}
635
637{
638 BaseModGroup modGroup;
639 uint16 index;
640 CombatRating cr;
641
642 switch (attType)
643 {
644 case OFF_ATTACK:
645 modGroup = OFFHAND_CRIT_PERCENTAGE;
647 cr = CR_CRIT_MELEE;
648 break;
649 case RANGED_ATTACK:
650 modGroup = RANGED_CRIT_PERCENTAGE;
652 cr = CR_CRIT_RANGED;
653 break;
654 case BASE_ATTACK:
655 default:
656 modGroup = CRIT_PERCENTAGE;
658 cr = CR_CRIT_MELEE;
659 break;
660 }
661
662 // flat = bonus from crit auras, pct = bonus from agility, combat rating = mods from items
663 float value = GetBaseModValue(modGroup, FLAT_MOD) + GetBaseModValue(modGroup, PCT_MOD) + GetRatingBonusValue(cr);
664
665 // Modify crit from weapon skill and maximized defense skill of same level victim difference
666 value += (int32(GetWeaponSkillValue(attType)) - int32(GetMaxSkillValueForLevel())) * 0.04f;
667
668 if (sWorld->getBoolConfig(CONFIG_STATS_LIMITS_ENABLE))
669 value = value > sWorld->getFloatConfig(CONFIG_STATS_LIMITS_CRIT) ? sWorld->getFloatConfig(CONFIG_STATS_LIMITS_CRIT) : value;
670
671 value = std::max(0.0f, value);
672 SetStatFloatValue(index, value);
673}
674
687
689{
690 0.9560f, // Warrior
691 0.9560f, // Paladin
692 0.9880f, // Hunter
693 0.9880f, // Rogue
694 0.9830f, // Priest
695 0.9560f, // DK
696 0.9880f, // Shaman
697 0.9830f, // Mage
698 0.9830f, // Warlock
699 0.0f, // ??
700 0.9720f // Druid
701};
702
703// helper function
704float CalculateDiminishingReturns(float const (&capArray)[MAX_CLASSES], uint8 playerClass, float nonDiminishValue, float diminishValue)
705{
706 // 1 1 k cx
707 // --- = --- + --- <=> x' = --------
708 // x' c x x + ck
709
710 // where:
711 // k is m_diminishing_k for that class
712 // c is capArray for that class
713 // x is chance before DR (diminishValue)
714 // x' is chance after DR (our result)
715
716 uint32 const classIdx = playerClass - 1;
717
718 float const k = m_diminishing_k[classIdx];
719 float const c = capArray[classIdx];
720
721 float result = c * diminishValue / (diminishValue + c * k);
722 result += nonDiminishValue;
723 return result;
724}
725
726float const miss_cap[MAX_CLASSES] =
727{
728 16.00f, // Warrior //correct
729 16.00f, // Paladin //correct
730 16.00f, // Hunter //?
731 16.00f, // Rogue //?
732 16.00f, // Priest //?
733 16.00f, // DK //correct
734 16.00f, // Shaman //?
735 16.00f, // Mage //?
736 16.00f, // Warlock //?
737 0.0f, // ??
738 16.00f // Druid //?
739};
740
742{
743 float diminishing = 0.0f, nondiminishing = 0.0f;
744 // Modify value from defense skill (only bonus from defense rating diminishes)
745 nondiminishing += (int32(GetSkillValue(SKILL_DEFENSE)) - int32(GetMaxSkillValueForLevel())) * 0.04f;
746 diminishing += (GetRatingBonusValue(CR_DEFENSE_SKILL) * 0.04f);
747
748 // apply diminishing formula to diminishing miss chance
749 return CalculateDiminishingReturns(miss_cap, GetClass(), nondiminishing, diminishing);
750}
751
752float const parry_cap[MAX_CLASSES] =
753{
754 47.003525f, // Warrior
755 47.003525f, // Paladin
756 145.560408f, // Hunter
757 145.560408f, // Rogue
758 0.0f, // Priest
759 47.003525f, // DK
760 145.560408f, // Shaman
761 0.0f, // Mage
762 0.0f, // Warlock
763 0.0f, // ??
764 0.0f // Druid
765};
766
768{
769 // No parry
770 float value = 0.0f;
771 uint32 pclass = GetClass() - 1;
772 if (CanParry() && parry_cap[pclass] > 0.0f)
773 {
774 float nondiminishing = 5.0f;
775 // Parry from rating
776 float diminishing = GetRatingBonusValue(CR_PARRY);
777 // Modify value from defense skill (only bonus from defense rating diminishes)
778 nondiminishing += (int32(GetSkillValue(SKILL_DEFENSE)) - int32(GetMaxSkillValueForLevel())) * 0.04f;
779 diminishing += (GetRatingBonusValue(CR_DEFENSE_SKILL) * 0.04f);
780 // Parry from SPELL_AURA_MOD_PARRY_PERCENT aura
782
783 // apply diminishing formula to diminishing parry chance
784 value = CalculateDiminishingReturns(parry_cap, GetClass(), nondiminishing, diminishing);
785
786 if (sWorld->getBoolConfig(CONFIG_STATS_LIMITS_ENABLE))
787 value = value > sWorld->getFloatConfig(CONFIG_STATS_LIMITS_PARRY) ? sWorld->getFloatConfig(CONFIG_STATS_LIMITS_PARRY) : value;
788
789 value = value < 0.0f ? 0.0f : value;
790 }
792}
793
794float const dodge_cap[MAX_CLASSES] =
795{
796 88.129021f, // Warrior
797 88.129021f, // Paladin
798 145.560408f, // Hunter
799 145.560408f, // Rogue
800 150.375940f, // Priest
801 88.129021f, // DK
802 145.560408f, // Shaman
803 150.375940f, // Mage
804 150.375940f, // Warlock
805 0.0f, // ??
806 116.890707f // Druid
807};
808
810{
811 float diminishing = 0.0f, nondiminishing = 0.0f;
812 GetDodgeFromAgility(diminishing, nondiminishing);
813 // Modify value from defense skill (only bonus from defense rating diminishes)
814 nondiminishing += (int32(GetSkillValue(SKILL_DEFENSE)) - int32(GetMaxSkillValueForLevel())) * 0.04f;
815 diminishing += (GetRatingBonusValue(CR_DEFENSE_SKILL) * 0.04f);
816 // Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura
818 // Dodge from rating
819 diminishing += GetRatingBonusValue(CR_DODGE);
820
821 // apply diminishing formula to diminishing dodge chance
822 float value = CalculateDiminishingReturns(dodge_cap, GetClass(), nondiminishing, diminishing);
823
824 if (sWorld->getBoolConfig(CONFIG_STATS_LIMITS_ENABLE))
825 value = value > sWorld->getFloatConfig(CONFIG_STATS_LIMITS_DODGE) ? sWorld->getFloatConfig(CONFIG_STATS_LIMITS_DODGE) : value;
826
827 value = value < 0.0f ? 0.0f : value;
829}
830
832{
833 // For normal school set zero crit chance
834 if (school == SPELL_SCHOOL_NORMAL)
835 {
837 return;
838 }
839 // For others recalculate it from:
840 float crit = 0.0f;
841 // Crit from Intellect
843 // Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE
845 // Increase crit from SPELL_AURA_MOD_CRIT_PCT
847 // Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
849 // Increase crit from spell crit ratings
851
852 // Store crit value
854}
855
861
866
871
877
883
885{
886 if (attack == RANGED_ATTACK)
887 return;
888
890
891 Item const* weapon = GetWeaponForAttack(attack, true);
892 expertise += GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE, [weapon](AuraEffect const* aurEff) -> bool
893 {
894 return aurEff->GetSpellInfo()->IsItemFitToSpellRequirements(weapon);
895 });
896
897 if (expertise < 0)
898 expertise = 0;
899
900 switch (attack)
901 {
902 case BASE_ATTACK:
904 break;
905 case OFF_ATTACK:
907 break;
908 default:
909 break;
910 }
911}
912
913void Player::ApplyManaRegenBonus(int32 amount, bool apply)
914{
915 _ModifyUInt32(apply, m_baseManaRegen, amount);
917}
918
919void Player::ApplyHealthRegenBonus(int32 amount, bool apply)
920{
921 _ModifyUInt32(apply, m_baseHealthRegen, amount);
922}
923
924static constexpr std::array<std::pair<float, Optional<Rates>>, MAX_POWERS> PowerRegenInfo =
925{{
926 { 0.f, RATE_POWER_MANA }, // POWER_MANA
927 { -12.5f, RATE_POWER_RAGE_LOSS }, // POWER_RAGE, -1.25 rage per second
928 { 0.f, std::nullopt }, // POWER_FOCUS
929 { 10.f, RATE_POWER_ENERGY }, // POWER_ENERGY, +10 energy per second
930 { 0.f, std::nullopt }, // POWER_HAPPINESS
931 { 0.f, std::nullopt }, // POWER_RUNE
932 { -12.5f, RATE_POWER_RUNICPOWER_LOSS } // POWER_RUNIC_POWER, -1.25 runic power per second
933}};
934
936{
937 if (power == POWER_HEALTH || power >= MAX_POWERS)
938 return;
939
940 float result_regen = 0.f; // Out-of-combat / without last mana use effect
941 float result_regen_interrupted = 0.f; // In combat / with last mana use effect
942 float modifier = 1.f; // Config rate or any other modifiers
943
946 {
949 return;
950 }
951
952 switch (power)
953 {
954 case POWER_MANA:
955 {
956 float Intellect = GetStat(STAT_INTELLECT);
957 // Mana regen from spirit and intellect
958 float power_regen = std::sqrt(Intellect) * OCTRegenMPPerSpirit();
959 // Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen
961
962 // Mana regen from SPELL_AURA_MOD_POWER_REGEN aura
964
965 // Get bonus from SPELL_AURA_MOD_MANA_REGEN_FROM_STAT aura
967 for (AuraEffectList::const_iterator i = regenAura.begin(); i != regenAura.end(); ++i)
968 power_regen_mp5 += GetStat(Stats((*i)->GetMiscValue())) * (*i)->GetAmount() / 500.0f;
969
970 // Set regen rate in cast state apply only on spirit based regen
972 if (modManaRegenInterrupt > 100)
973 modManaRegenInterrupt = 100;
974
975 result_regen = power_regen_mp5 + power_regen;
976 result_regen_interrupted = power_regen_mp5 + CalculatePct(power_regen, modManaRegenInterrupt);
977
978 if (GetLevel() < 15)
979 modifier *= 2.066f - (GetLevel() * 0.066f);
980 break;
981 }
982 case POWER_RAGE:
983 case POWER_ENERGY:
985 {
986 result_regen = PowerRegenInfo[AsUnderlyingType(power)].first;
987 result_regen_interrupted = 0.f;
988
990 result_regen_interrupted += static_cast<float>(GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, AsUnderlyingType(power))) / 5.f;
991
992 if (power != POWER_RUNIC_POWER) // Butchery requires combat
993 result_regen += result_regen_interrupted;
994 break;
995 }
996 default:
997 break;
998 }
999
1000 if (PowerRegenInfo[AsUnderlyingType(power)].second)
1001 modifier *= sWorld->getRate(*PowerRegenInfo[AsUnderlyingType(power)].second); // Config rate
1002
1003 result_regen *= modifier;
1004 result_regen_interrupted *= modifier;
1005
1006 // Unit fields contain an offset relative to the base power regeneration.
1007 if (power != POWER_MANA)
1008 result_regen -= PowerRegenInfo[AsUnderlyingType(power)].first;
1009
1010 if (power == POWER_ENERGY)
1011 result_regen_interrupted = result_regen;
1012
1015}
1016
1018{
1019 if (power == POWER_HEALTH || power >= MAX_POWERS)
1020 return 0.f;
1021
1022 bool interrupted = HasAuraType(SPELL_AURA_INTERRUPT_REGEN) ||
1023 (power == POWER_MANA && IsUnderLastManaUseEffect()) ||
1024 (power != POWER_MANA && IsInCombat());
1025
1027 if (power != POWER_MANA)
1028 regen += (power == POWER_ENERGY || !interrupted) ? PowerRegenInfo[AsUnderlyingType(power)].first : 0.f;
1029
1030 return regen;
1031}
1032
1034{
1035 if (rune >= NUM_RUNE_TYPES)
1036 return;
1037
1038 if (uint32 cooldown = GetRuneTypeBaseCooldown(rune))
1039 SetFloatValue(PLAYER_RUNE_REGEN_1 + uint8(rune), float(1 * IN_MILLISECONDS) / float(cooldown));
1040}
1041
1043{
1044 SetCanModifyStats(false);
1045
1048
1049 SetCanModifyStats(true);
1050
1052}
1053
1055{
1056 SetCanModifyStats(false);
1057
1060
1061 SetCanModifyStats(true);
1062
1064}
1065
1066/*#######################################
1067######## ########
1068######## MOBS STAT SYSTEM ########
1069######## ########
1070#######################################*/
1071
1073{
1074 return true;
1075}
1076
1078{
1082
1083 for (uint8 i = POWER_MANA; i < MAX_POWERS; ++i)
1085
1087
1088 return true;
1089}
1090
1092{
1093 if (school > SPELL_SCHOOL_NORMAL)
1094 {
1096 SetResistance(SpellSchools(school), int32(value));
1097 }
1098 else
1099 UpdateArmor();
1100}
1101
1103{
1104 float value = GetTotalAuraModValue(UNIT_MOD_ARMOR);
1105 SetArmor(int32(value));
1106}
1107
1109{
1111 SetMaxHealth(uint32(value));
1112}
1113
1115{
1117
1118 float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreatePowerValue(power);
1119 value *= GetPctModifierValue(unitMod, BASE_PCT);
1120 value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
1121 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
1122
1123 SetMaxPower(power, uint32(std::lroundf(value)));
1124}
1125
1127{
1129
1130 float baseAttackPower = ranged ? m_baseRangedAttackPower : m_baseAttackPower;
1131 float attackPowerModPos = GetAttackPowerModifierValue(unitMod, AttackPowerModType::FlatPositive);
1132 float attackPowerModNeg = GetAttackPowerModifierValue(unitMod, AttackPowerModType::FlatNegative);
1133 float attackPowerMultiplier = GetAttackPowerModifierValue(unitMod, AttackPowerModType::Pct) - 1.0f;
1134
1135 if (ranged)
1136 {
1137 SetRangedAttackPower(int32(baseAttackPower));
1138 SetRangedAttackPowerModPos(int32(attackPowerModPos));
1139 SetRangedAttackPowerModNeg(int32(attackPowerModNeg));
1140 SetRangedAttackPowerMultiplier(attackPowerMultiplier);
1141 }
1142 else
1143 {
1144 SetAttackPower(int32(baseAttackPower));
1145 SetAttackPowerModPos(int32(attackPowerModPos));
1146 SetAttackPowerModNeg(int32(attackPowerModNeg));
1147 SetAttackPowerMultiplier(attackPowerMultiplier);
1148 }
1149
1150 // automatically update weapon damage after attack power modification
1151 if (ranged)
1153 else
1154 {
1157 }
1158}
1159
1160void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex /*= 0*/) const
1161{
1162 // creatures only have one damage
1163 if (damageIndex != 0)
1164 {
1165 minDamage = 0.f;
1166 maxDamage = 0.f;
1167 return;
1168 }
1169
1170 float variance = 1.0f;
1171 UnitMods unitMod;
1172 switch (attType)
1173 {
1174 case BASE_ATTACK:
1175 default:
1176 variance = GetCreatureTemplate()->BaseVariance;
1177 unitMod = UNIT_MOD_DAMAGE_MAINHAND;
1178 break;
1179 case OFF_ATTACK:
1180 variance = GetCreatureTemplate()->BaseVariance;
1181 unitMod = UNIT_MOD_DAMAGE_OFFHAND;
1182 break;
1183 case RANGED_ATTACK:
1184 variance = GetCreatureTemplate()->RangeVariance;
1185 unitMod = UNIT_MOD_DAMAGE_RANGED;
1186 break;
1187 }
1188
1189 if (attType == OFF_ATTACK && !haveOffhandWeapon())
1190 {
1191 minDamage = 0.0f;
1192 maxDamage = 0.0f;
1193 return;
1194 }
1195
1196 float weaponMinDamage = GetWeaponDamageRange(attType, MINDAMAGE);
1197 float weaponMaxDamage = GetWeaponDamageRange(attType, MAXDAMAGE);
1198
1199 if (!CanUseAttackType(attType)) // disarm case
1200 {
1201 weaponMinDamage = 0.0f;
1202 weaponMaxDamage = 0.0f;
1203 }
1204
1205 float attackPower = GetTotalAttackPowerValue(attType);
1206 float attackSpeedMulti = GetAPMultiplier(attType, normalized);
1207 float baseValue = GetFlatModifierValue(unitMod, BASE_VALUE) + (attackPower / 14.0f) * variance;
1208 float basePct = GetPctModifierValue(unitMod, BASE_PCT) * attackSpeedMulti;
1209 float totalValue = GetFlatModifierValue(unitMod, TOTAL_VALUE);
1210 float totalPct = addTotalPct ? GetPctModifierValue(unitMod, TOTAL_PCT) : 1.0f;
1211 float dmgMultiplier = GetCreatureTemplate()->ModDamage; // = ModDamage * _GetDamageMod(rank);
1212
1213 minDamage = ((weaponMinDamage + baseValue) * dmgMultiplier * basePct + totalValue) * totalPct;
1214 maxDamage = ((weaponMaxDamage + baseValue) * dmgMultiplier * basePct + totalValue) * totalPct;
1215}
1216
1217/*#######################################
1218######## ########
1219######## PETS STAT SYSTEM ########
1220######## ########
1221#######################################*/
1222
1223#define ENTRY_IMP 416
1224#define ENTRY_VOIDWALKER 1860
1225#define ENTRY_SUCCUBUS 1863
1226#define ENTRY_FELHUNTER 417
1227#define ENTRY_FELGUARD 17252
1228#define ENTRY_WATER_ELEMENTAL 510
1229#define ENTRY_TREANT 1964
1230#define ENTRY_FIRE_ELEMENTAL 15438
1231#define ENTRY_GHOUL 26125
1232#define ENTRY_BLOODWORM 28017
1233
1235{
1236 if (stat >= MAX_STATS)
1237 return false;
1238
1239 // value = ((base_value * base_pct) + total_value) * total_pct
1240 float value = GetTotalStatValue(stat);
1241 //ApplyStatBuffMod(stat, m_statFromOwner[stat], false);
1242 float ownersBonus = 0.0f;
1243
1244 Unit* owner = GetOwner();
1245 // Handle Death Knight Glyphs and Talents
1246 float mod = 0.75f;
1247 if ((IsPetGhoul() || IsRisenAlly()) && (stat == STAT_STAMINA || stat == STAT_STRENGTH))
1248 {
1249 if (stat == STAT_STAMINA)
1250 mod = 0.3f; // Default Owner's Stamina scale
1251 else
1252 mod = 0.7f; // Default Owner's Strength scale
1253
1254 // Check just if owner has Ravenous Dead since it's effect is not an aura
1256 if (aurEff)
1257 {
1258 SpellInfo const* spellInfo = aurEff->GetSpellInfo(); // Then get the SpellProto and add the dummy effect value
1259 AddPct(mod, spellInfo->GetEffect(EFFECT_1).CalcValue()); // Ravenous Dead edits the original scale
1260 }
1261 // Glyph of the Ghoul
1262 aurEff = owner->GetAuraEffect(58686, 0);
1263 if (aurEff)
1264 mod += CalculatePct(1.0f, aurEff->GetAmount()); // Glyph of the Ghoul adds a flat value to the scale mod
1265 ownersBonus = float(owner->GetStat(stat)) * mod;
1266 value += ownersBonus;
1267 }
1268 else if (stat == STAT_STAMINA)
1269 {
1270 if (owner->GetClass() == CLASS_WARLOCK && IsPet())
1271 {
1272 ownersBonus = CalculatePct(owner->GetStat(STAT_STAMINA), 75);
1273 value += ownersBonus;
1274 }
1275 else
1276 {
1277 mod = 0.45f;
1278 if (IsPet())
1279 {
1280 PetSpellMap::const_iterator itr = (ToPet()->m_spells.find(62758)); // Wild Hunt rank 1
1281 if (itr == ToPet()->m_spells.end())
1282 itr = ToPet()->m_spells.find(62762); // Wild Hunt rank 2
1283
1284 if (itr != ToPet()->m_spells.end()) // If pet has Wild Hunt
1285 {
1286 SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); // Then get the SpellProto and add the dummy effect value
1287 AddPct(mod, spellInfo->GetEffect(EFFECT_0).CalcValue());
1288 }
1289 }
1290 ownersBonus = float(owner->GetStat(stat)) * mod;
1291 value += ownersBonus;
1292 }
1293 }
1294 //warlock's and mage's pets gain 30% of owner's intellect
1295 else if (stat == STAT_INTELLECT)
1296 {
1297 if (owner->GetClass() == CLASS_WARLOCK || owner->GetClass() == CLASS_MAGE)
1298 {
1299 ownersBonus = CalculatePct(owner->GetStat(stat), 30);
1300 value += ownersBonus;
1301 }
1302 }
1303/*
1304 else if (stat == STAT_STRENGTH)
1305 {
1306 if (IsPetGhoul())
1307 value += float(owner->GetStat(stat)) * 0.3f;
1308 }
1309*/
1310
1311 SetStat(stat, int32(value));
1312 m_statFromOwner[stat] = ownersBonus;
1313 UpdateStatBuffMod(stat);
1314
1315 switch (stat)
1316 {
1318 case STAT_AGILITY: UpdateArmor(); break;
1319 case STAT_STAMINA: UpdateMaxHealth(); break;
1321 case STAT_SPIRIT:
1322 default:
1323 break;
1324 }
1325
1326 return true;
1327}
1328
1330{
1332
1333 for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
1334 UpdateStats(Stats(i));
1335
1336 for (uint8 i = POWER_MANA; i < MAX_POWERS; ++i)
1338
1340
1341 return true;
1342}
1343
1345{
1346 if (school > SPELL_SCHOOL_NORMAL)
1347 {
1349
1350 // hunter and warlock pets gain 40% of owner's resistance
1351 if (IsPet())
1352 value += float(CalculatePct(m_owner->GetResistance(SpellSchools(school)), 40));
1353
1354 SetResistance(SpellSchools(school), int32(value));
1355 }
1356 else
1357 UpdateArmor();
1358}
1359
1361{
1362 float value = 0.0f;
1363 float bonus_armor = 0.0f;
1364 UnitMods unitMod = UNIT_MOD_ARMOR;
1365
1366 // hunter and warlock pets gain 35% of owner's armor value
1367 if (IsPet())
1368 bonus_armor = float(CalculatePct(m_owner->GetArmor(), 35));
1369
1370 value = GetFlatModifierValue(unitMod, BASE_VALUE);
1371 value *= GetPctModifierValue(unitMod, BASE_PCT);
1372 value += GetStat(STAT_AGILITY) * 2.0f;
1373 value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + bonus_armor;
1374 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
1375
1376 SetArmor(int32(value));
1377}
1378
1380{
1381 UnitMods unitMod = UNIT_MOD_HEALTH;
1382 float stamina = GetStat(STAT_STAMINA) - GetCreateStat(STAT_STAMINA);
1383
1384 float multiplicator;
1385 switch (GetEntry())
1386 {
1387 case ENTRY_IMP: multiplicator = 8.4f; break;
1388 case ENTRY_VOIDWALKER: multiplicator = 11.0f; break;
1389 case ENTRY_SUCCUBUS: multiplicator = 9.1f; break;
1390 case ENTRY_FELHUNTER: multiplicator = 9.5f; break;
1391 case ENTRY_FELGUARD: multiplicator = 11.0f; break;
1392 case ENTRY_BLOODWORM: multiplicator = 1.0f; break;
1393 default: multiplicator = 10.0f; break;
1394 }
1395
1396 float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
1397 value *= GetPctModifierValue(unitMod, BASE_PCT);
1398 value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + stamina * multiplicator;
1399 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
1400
1401 SetMaxHealth((uint32)value);
1402}
1403
1405{
1407
1408 float addValue = (power == POWER_MANA) ? GetStat(STAT_INTELLECT) - GetCreateStat(STAT_INTELLECT) : 0.0f;
1409 float multiplicator = 15.0f;
1410
1411 switch (GetEntry())
1412 {
1413 case ENTRY_IMP: multiplicator = 4.95f; break;
1414 case ENTRY_VOIDWALKER:
1415 case ENTRY_SUCCUBUS:
1416 case ENTRY_FELHUNTER:
1417 case ENTRY_FELGUARD: multiplicator = 11.5f; break;
1418 default: multiplicator = 15.0f; break;
1419 }
1420
1421 float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreatePowerValue(power);
1422 value *= GetPctModifierValue(unitMod, BASE_PCT);
1423 value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + addValue * multiplicator;
1424 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
1425
1426 SetMaxPower(power, uint32(value));
1427}
1428
1430{
1431 if (ranged)
1432 return;
1433
1434 float val = 0.0f;
1435 float bonusAP = 0.0f;
1437
1438 if (GetEntry() == ENTRY_IMP) // imp's attack power
1439 val = GetStat(STAT_STRENGTH) - 10.0f;
1440 else
1441 val = 2 * GetStat(STAT_STRENGTH) - 20.0f;
1442
1443 Unit* owner = GetOwner();
1444 if (owner && owner->GetTypeId() == TYPEID_PLAYER)
1445 {
1446 if (IsHunterPet()) //hunter pets benefit from owner's attack power
1447 {
1448 float mod = 1.0f; //Hunter contribution modifier
1449 if (IsPet())
1450 {
1451 PetSpellMap::const_iterator itr = ToPet()->m_spells.find(62758); //Wild Hunt rank 1
1452 if (itr == ToPet()->m_spells.end())
1453 itr = ToPet()->m_spells.find(62762); //Wild Hunt rank 2
1454
1455 if (itr != ToPet()->m_spells.end()) // If pet has Wild Hunt
1456 {
1457 SpellInfo const* sProto = sSpellMgr->AssertSpellInfo(itr->first); // Then get the SpellProto and add the dummy effect value
1458 mod += CalculatePct(1.0f, sProto->GetEffect(EFFECT_1).CalcValue());
1459 }
1460 }
1461
1462 bonusAP = owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.22f * mod;
1463 if (AuraEffect* aurEff = owner->GetAuraEffectOfRankedSpell(34453, EFFECT_1, owner->GetGUID())) // Animal Handler
1464 {
1465 AddPct(bonusAP, aurEff->GetAmount());
1466 AddPct(val, aurEff->GetAmount());
1467 }
1469 }
1470 else if (IsPetGhoul() || IsRisenAlly()) //ghouls benefit from deathknight's attack power (may be summon pet or not)
1471 {
1472 bonusAP = owner->GetTotalAttackPowerValue(BASE_ATTACK) * 0.22f;
1474 }
1475 else if (IsSpiritWolf()) //wolf benefit from shaman's attack power
1476 {
1477 float dmg_multiplier = 0.31f;
1478 if (m_owner->GetAuraEffect(63271, 0)) // Glyph of Feral Spirit
1479 dmg_multiplier = 0.61f;
1480 bonusAP = owner->GetTotalAttackPowerValue(BASE_ATTACK) * dmg_multiplier;
1481 SetBonusDamage(int32(owner->GetTotalAttackPowerValue(BASE_ATTACK) * dmg_multiplier));
1482 }
1483 //demons benefit from warlocks shadow or fire damage
1484 else if (IsPet())
1485 {
1488 int32 maximum = (fire > shadow) ? fire : shadow;
1489 if (maximum < 0)
1490 maximum = 0;
1491 SetBonusDamage(int32(maximum * 0.15f));
1492 bonusAP = maximum * 0.57f;
1493 }
1494 //water elementals benefit from mage's frost damage
1495 else if (GetEntry() == ENTRY_WATER_ELEMENTAL)
1496 {
1498 if (frost < 0)
1499 frost = 0;
1500 SetBonusDamage(int32(frost * 0.4f));
1501 }
1502 }
1503
1504 float base_attPower = val + bonusAP;
1505 float attPowerModPos = GetAttackPowerModifierValue(unitMod, AttackPowerModType::FlatPositive);
1506 float attPowerModNeg = GetAttackPowerModifierValue(unitMod, AttackPowerModType::FlatNegative);
1507 float attPowerMultiplier = GetAttackPowerModifierValue(unitMod, AttackPowerModType::Pct) - 1.0f;
1508
1509 SetAttackPower(int32(base_attPower));
1510 SetAttackPowerModPos(int32(attPowerModPos));
1511 SetAttackPowerModNeg(int32(attPowerModNeg));
1512 SetAttackPowerMultiplier(attPowerMultiplier);
1513
1514 //automatically update weapon damage after attack power modification
1516}
1517
1519{
1520 if (attType > BASE_ATTACK)
1521 return;
1522
1523 float bonusDamage = 0.0f;
1525 {
1526 //force of nature
1527 if (GetEntry() == ENTRY_TREANT)
1528 {
1530 if (spellDmg > 0)
1531 bonusDamage = spellDmg * 0.09f;
1532 }
1533 //greater fire elemental
1534 else if (GetEntry() == ENTRY_FIRE_ELEMENTAL)
1535 {
1537 if (spellDmg > 0)
1538 bonusDamage = spellDmg * 0.4f;
1539 }
1540 }
1541
1543
1544 float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f;
1545
1546 float base_value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * att_speed + bonusDamage;
1547 float base_pct = GetPctModifierValue(unitMod, BASE_PCT);
1548 float total_value = GetFlatModifierValue(unitMod, TOTAL_VALUE);
1549 float total_pct = GetPctModifierValue(unitMod, TOTAL_PCT);
1550
1551 float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
1552 float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
1553
1554 float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct;
1555 float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct;
1556
1557 // Pet's base damage changes depending on happiness
1558 if (IsHunterPet())
1559 {
1560 switch (ToPet()->GetHappinessState())
1561 {
1562 case HAPPY:
1563 // 125% of normal damage
1564 mindamage = mindamage * 1.25f;
1565 maxdamage = maxdamage * 1.25f;
1566 break;
1567 case CONTENT:
1568 // 100% of normal damage, nothing to modify
1569 break;
1570 case UNHAPPY:
1571 // 75% of normal damage
1572 mindamage = mindamage * 0.75f;
1573 maxdamage = maxdamage * 0.75f;
1574 break;
1575 }
1576 }
1577
1580 for (Unit::AuraEffectList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
1581 {
1582 switch ((*itr)->GetSpellInfo()->Id)
1583 {
1584 case 61682:
1585 case 61683:
1586 AddPct(mindamage, -(*itr)->GetAmount());
1587 AddPct(maxdamage, -(*itr)->GetAmount());
1588 break;
1589 default:
1590 break;
1591 }
1592 }
1593
1596}
1597
1599{
1600 m_bonusSpellDamage = damage;
1601 if (GetOwner()->GetTypeId() == TYPEID_PLAYER)
1603}
@ IN_MILLISECONDS
Definition Common.h:35
uint8_t uint8
Definition Define.h:135
int32_t int32
Definition Define.h:129
uint16_t uint16
Definition Define.h:134
uint32_t uint32
Definition Define.h:133
#define MAX_ITEM_PROTO_DAMAGES
@ TYPEID_PLAYER
Definition ObjectGuid.h:39
@ HAPPY
Definition PetDefines.h:52
@ CONTENT
Definition PetDefines.h:51
@ UNHAPPY
Definition PetDefines.h:50
@ EQUIPMENT_SLOT_MAINHAND
Definition Player.h:575
RuneType
Definition Player.h:289
@ NUM_RUNE_TYPES
Definition Player.h:294
@ EFFECT_1
@ EFFECT_0
SpellSchools
@ SPELL_SCHOOL_SHADOW
@ SPELL_SCHOOL_NORMAL
@ SPELL_SCHOOL_NATURE
@ SPELL_SCHOOL_FROST
@ SPELL_SCHOOL_FIRE
@ SPELL_SCHOOL_HOLY
@ MAX_SPELL_SCHOOL
#define CLASSMASK_WAND_USERS
SpellSchoolMask
@ SPELL_SCHOOL_MASK_NORMAL
@ SPELL_SCHOOL_MASK_ALL
WeaponAttackType
@ OFF_ATTACK
@ BASE_ATTACK
@ RANGED_ATTACK
@ CLASS_HUNTER
@ CLASS_DRUID
@ CLASS_SHAMAN
@ CLASS_PRIEST
@ CLASS_WARRIOR
@ CLASS_WARLOCK
@ CLASS_MAGE
@ CLASS_DEATH_KNIGHT
@ CLASS_PALADIN
@ CLASS_ROGUE
@ SPELLFAMILY_DRUID
@ SPELLFAMILY_DEATHKNIGHT
Powers
@ MAX_POWERS
@ POWER_RAGE
@ POWER_HEALTH
@ POWER_RUNIC_POWER
@ POWER_ENERGY
@ POWER_MANA
#define MAX_CLASSES
Stats
@ STAT_SPIRIT
@ STAT_INTELLECT
@ MAX_STATS
@ STAT_AGILITY
@ STAT_STRENGTH
@ STAT_STAMINA
@ SKILL_DEFENSE
@ SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE
@ SPELL_AURA_MOD_ATTACKSPEED
@ SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
@ SPELL_AURA_MOD_PARRY_PERCENT
@ SPELL_AURA_MOD_RATING_FROM_STAT
@ SPELL_AURA_MOD_SPELL_HIT_CHANCE
@ SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT
@ SPELL_AURA_MOD_EXPERTISE
@ SPELL_AURA_INTERRUPT_REGEN
@ SPELL_AURA_MOD_POWER_REGEN
@ SPELL_AURA_MOD_SPELL_CRIT_CHANCE
@ SPELL_AURA_DUMMY
@ SPELL_AURA_MOD_DODGE_PERCENT
@ SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
@ SPELL_AURA_MOD_CRIT_PCT
@ SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT
@ SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR
@ SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT
@ SPELL_AURA_MOD_POWER_REGEN_PERCENT
@ SPELL_AURA_MOD_MANA_REGEN_FROM_STAT
@ SPELL_AURA_MOD_DAMAGE_DONE
@ SPELL_AURA_PREVENT_REGENERATE_POWER
@ SPELL_AURA_MOD_BLOCK_PERCENT
@ FORM_DIREBEAR
@ FORM_MOONKIN
@ FORM_CAT
@ FORM_BEAR
#define sSpellMgr
Definition SpellMgr.h:738
float const miss_cap[MAX_CLASSES]
float const dodge_cap[MAX_CLASSES]
#define ENTRY_FELGUARD
#define ENTRY_FIRE_ELEMENTAL
#define ENTRY_BLOODWORM
#define ENTRY_VOIDWALKER
#define ENTRY_FELHUNTER
float CalculateDiminishingReturns(float const (&capArray)[MAX_CLASSES], uint8 playerClass, float nonDiminishValue, float diminishValue)
float const parry_cap[MAX_CLASSES]
#define ENTRY_TREANT
static constexpr std::array< std::pair< float, Optional< Rates > >, MAX_POWERS > PowerRegenInfo
bool _ModifyUInt32(bool apply, uint32 &baseValue, int32 &amount)
#define ENTRY_WATER_ELEMENTAL
#define ENTRY_SUCCUBUS
float const m_diminishing_k[MAX_CLASSES]
#define ENTRY_IMP
#define BASE_MAXDAMAGE
Definition UnitDefines.h:26
#define BASE_MINDAMAGE
Definition UnitDefines.h:25
@ BASE_VALUE
Definition Unit.h:139
@ TOTAL_VALUE
Definition Unit.h:140
@ FLAT_MOD
Definition Unit.h:203
@ PCT_MOD
Definition Unit.h:204
@ MINDAMAGE
Definition Unit.h:153
@ MAXDAMAGE
Definition Unit.h:154
UnitMods
Definition Unit.h:158
@ UNIT_MOD_DAMAGE_OFFHAND
Definition Unit.h:180
@ UNIT_MOD_ARMOR
Definition Unit.h:172
@ UNIT_MOD_RESISTANCE_START
Definition Unit.h:186
@ UNIT_MOD_HEALTH
Definition Unit.h:164
@ UNIT_MOD_DAMAGE_RANGED
Definition Unit.h:181
@ UNIT_MOD_POWER_START
Definition Unit.h:188
@ UNIT_MOD_DAMAGE_MAINHAND
Definition Unit.h:179
#define MAX_COMBAT_RATING
Definition Unit.h:363
BaseModGroup
Definition Unit.h:193
@ OFFHAND_CRIT_PERCENTAGE
Definition Unit.h:196
@ CRIT_PERCENTAGE
Definition Unit.h:194
@ RANGED_CRIT_PERCENTAGE
Definition Unit.h:195
AttackPowerModIndex
Definition Unit.h:209
CombatRating
Definition Unit.h:335
@ CR_EXPERTISE
Definition Unit.h:359
@ CR_HIT_MELEE
Definition Unit.h:341
@ CR_ARMOR_PENETRATION
Definition Unit.h:360
@ CR_CRIT_MELEE
Definition Unit.h:344
@ CR_CRIT_RANGED
Definition Unit.h:345
@ CR_PARRY
Definition Unit.h:339
@ CR_DODGE
Definition Unit.h:338
@ CR_DEFENSE_SKILL
Definition Unit.h:337
@ CR_BLOCK
Definition Unit.h:340
@ CR_HIT_SPELL
Definition Unit.h:343
@ CR_CRIT_SPELL
Definition Unit.h:346
@ CR_HIT_RANGED
Definition Unit.h:342
@ TOTAL_PCT
Definition Unit.h:147
@ BASE_PCT
Definition Unit.h:146
@ PLAYER_FIELD_MOD_DAMAGE_DONE_POS
@ UNIT_FIELD_MINDAMAGE
@ PLAYER_EXPERTISE
@ PLAYER_RANGED_CRIT_PERCENTAGE
@ PLAYER_CRIT_PERCENTAGE
@ PLAYER_SPELL_CRIT_PERCENTAGE1
@ PLAYER_FIELD_COMBAT_RATING_1
@ PLAYER_PARRY_PERCENTAGE
@ PLAYER_OFFHAND_CRIT_PERCENTAGE
@ PLAYER_SHIELD_BLOCK
@ UNIT_FIELD_MAXDAMAGE
@ PLAYER_FIELD_MOD_TARGET_RESISTANCE
@ PLAYER_BLOCK_PERCENTAGE
@ UNIT_FIELD_MAXOFFHANDDAMAGE
@ UNIT_FIELD_MAXRANGEDDAMAGE
@ PLAYER_DODGE_PERCENTAGE
@ PLAYER_RUNE_REGEN_1
@ PLAYER_OFFHAND_EXPERTISE
@ PLAYER_FIELD_MOD_HEALING_DONE_POS
@ UNIT_FIELD_MINRANGEDDAMAGE
@ PLAYER_PET_SPELL_POWER
@ UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER
@ PLAYER_FIELD_MOD_DAMAGE_DONE_NEG
@ UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER
@ UNIT_FIELD_MINOFFHANDDAMAGE
T AddPct(T &base, U pct)
Definition Util.h:77
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition Util.h:554
T CalculatePct(T base, U pct)
Definition Util.h:71
SpellInfo const * GetSpellInfo() const
int32 GetAmount() const
bool UpdateAllStats() override
void UpdateResistances(uint32 school) override
uint32 m_spells[MAX_CREATURE_SPELLS]
Definition Creature.h:238
bool UpdateStats(Stats stat) override
uint32 m_baseAttackPower
Definition Creature.h:420
void UpdateAttackPowerAndDamage(bool ranged=false) override
void UpdateArmor() override
CreatureTemplate const * GetCreatureTemplate() const
Definition Creature.h:195
void UpdateMaxPower(Powers power) override
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float &minDamage, float &maxDamage, uint8 damageIndex) const override
uint32 m_baseRangedAttackPower
Definition Creature.h:421
void UpdateMaxHealth() override
void UpdateResistances(uint32 school) override
void UpdateMaxPower(Powers power) override
void UpdateMaxHealth() override
bool UpdateStats(Stats stat) override
void SetBonusDamage(int32 damage)
int32 m_bonusSpellDamage
float m_statFromOwner[MAX_STATS]
void UpdateDamagePhysical(WeaponAttackType attType) override
void UpdateArmor() override
bool UpdateAllStats() override
void UpdateAttackPowerAndDamage(bool ranged=false) override
Definition Item.h:62
Unit * GetOwner() const
bool IsRisenAlly() const
bool IsSpiritWolf() const
Unit *const m_owner
bool IsPetGhoul() const
int32 GetInt32Value(uint16 index) const
Definition Object.cpp:235
void SetInt32Value(uint16 index, int32 value)
Definition Object.cpp:564
void ApplyModInt32Value(uint16 index, int32 val, bool apply)
Definition Object.cpp:729
TypeID GetTypeId() const
Definition Object.h:93
void ApplyModUInt32Value(uint16 index, int32 val, bool apply)
Definition Object.cpp:720
float GetFloatValue(uint16 index) const
Definition Object.cpp:253
uint32 GetEntry() const
Definition Object.h:81
void SetFloatValue(uint16 index, float value)
Definition Object.cpp:647
void SetStatFloatValue(uint16 index, float value)
Definition Object.cpp:704
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
void SetUInt32Value(uint16 index, uint32 value)
Definition Object.cpp:577
void SetStatInt32Value(uint16 index, int32 value)
Definition Object.cpp:712
Definition Pet.h:40
HappinessState GetHappinessState()
Definition Pet.cpp:722
PetSpellMap m_spells
Definition Pet.h:128
void UpdateParryPercentage()
void UpdateAllSpellCritChances()
void UpdateArmorPenetration(int32 amount)
void UpdateRuneRegen(RuneType rune)
float GetHealthBonusFromStamina()
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float &minDamage, float &maxDamage, uint8 damageIndex) const override
void UpdateDodgePercentage()
float GetPowerRegen(Powers power) const
void UpdateShieldBlockValue()
void UpdateMaxPower(Powers power) override
bool CanParry() const
Definition Player.h:1882
void ApplyRatingMod(CombatRating cr, int32 value, bool apply)
Definition Player.cpp:5279
void UpdateCritPercentage(WeaponAttackType attType)
uint16 GetSkillValue(uint32 skill) const
Definition Player.cpp:5906
void UpdatePowerRegen(Powers power)
float GetRatingBonusValue(CombatRating cr) const
Definition Player.cpp:5218
float GetManaBonusFromIntellect()
bool CanBlock() const
Definition Player.h:1884
void UpdateBlockPercentage()
void ApplySpellPenetrationBonus(int32 amount, bool apply)
void UpdateArmor() override
void RecalculateRating(CombatRating cr)
Definition Player.h:1660
Pet * GetPet() const
Definition Player.cpp:20284
uint32 m_baseFeralAP
Definition Player.h:2402
bool UpdateStats(Stats stat) override
void _RemoveAllItemMods()
Definition Player.cpp:7869
void _ApplyAllItemMods()
Definition Player.cpp:7914
void UpdateSpellHitChances()
void UpdateExpertise(WeaponAttackType attType)
void _ApplyAllStatBonuses()
float GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const
Definition Player.cpp:5085
float GetSpellCritFromIntellect() const
Definition Player.cpp:5185
void ApplyManaRegenBonus(int32 amount, bool apply)
void GetDodgeFromAgility(float &diminishing, float &nondiminishing) const
Definition Player.cpp:5132
void SetBaseModPctValue(BaseModGroup modGroup, float val)
Definition Player.cpp:5006
float GetAmmoDPS() const
Definition Player.h:1152
void UpdateResistances(uint32 school) override
void UpdateSpellDamageAndHealingBonus()
uint32 m_baseSpellPower
Definition Player.h:2401
void UpdateMaxHealth() override
void UpdateMeleeHitChances()
Item * m_items[PLAYER_SLOTS_COUNT]
Definition Player.h:2371
uint32 m_baseHealthRegen
Definition Player.h:2404
void UpdateRangedHitChances()
uint32 m_baseManaRegen
Definition Player.h:2403
void UpdateAllRatings()
Definition Player.cpp:5398
void ApplySpellPowerBonus(int32 amount, bool apply)
void UpdateAllCritPercentages()
float GetMeleeCritFromAgility() const
Definition Player.cpp:5115
bool UpdateAllStats() override
Item * GetWeaponForAttack(WeaponAttackType attackType, bool useable=false) const
Definition Player.cpp:9605
void _RemoveAllStatBonuses()
int32 m_spellPenetrationItemMod
Definition Player.h:2405
uint32 GetShieldBlockValue() const override
Definition Player.cpp:5109
void ApplyFeralAPBonus(int32 amount, bool apply)
void UpdateDefenseBonusesMod()
void ApplyHealthRegenBonus(int32 amount, bool apply)
float OCTRegenMPPerSpirit() const
Definition Player.cpp:5260
void UpdateAttackPowerAndDamage(bool ranged=false) override
uint32 GetRuneTypeBaseCooldown(RuneType runeType) const
Definition Player.cpp:24317
float GetMissPercentageFromDefense() const
void UpdateSpellCritChance(uint32 school)
int32 CalcValue(WorldObject const *caster=nullptr, int32 const *basePoints=nullptr) const
SpellEffectInfo const & GetEffect(SpellEffIndex index) const
Definition SpellInfo.h:483
Definition Unit.h:783
float GetPctModifierValue(UnitMods unitMod, UnitModifierPctType modifierType) const
Definition Unit.cpp:9040
bool IsUnderLastManaUseEffect() const
Definition Unit.cpp:10822
bool IsHunterPet() const
Definition Unit.h:899
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition Unit.h:1397
void SetStat(Stats stat, int32 val)
Definition Unit.h:918
float GetTotalAuraModValue(UnitMods unitMod) const
Definition Unit.cpp:9219
Pet * ToPet()
Definition Unit.h:1804
float GetTotalStatValue(Stats stat) const
Definition Unit.cpp:9206
bool HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscValue) const
Definition Unit.cpp:4578
uint8 GetClass() const
Definition Unit.h:909
bool CanUseAttackType(uint8 attacktype) const
Definition Unit.cpp:2405
uint32 GetClassMask() const
Definition Unit.h:911
virtual void UpdateAllResistances()
ShapeshiftForm GetShapeshiftForm() const
Definition Unit.h:1503
float GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type, uint8 damageIndex=0) const
Definition Unit.cpp:9307
uint32 GetDefenseSkillValue(Unit const *target=nullptr) const
Definition Unit.cpp:2580
void SetAttackPowerModNeg(int32 attackPowerMod)
Definition Unit.h:1559
bool haveOffhandWeapon() const
Definition Unit.cpp:518
bool IsPet() const
Definition Unit.h:898
bool CanDualWield() const
Definition Unit.h:851
AuraEffect * GetAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid casterGUID=ObjectGuid::Empty) const
Definition Unit.cpp:4382
virtual void UpdateResistances(uint32 school)=0
float m_modRangedHitChance
Definition Unit.h:1511
void SetRangedAttackPowerModNeg(int32 attackPowerMod)
Definition Unit.h:1563
void SetMaxPower(Powers power, uint32 val)
Definition Unit.cpp:9439
void SetRangedAttackPowerModPos(int32 attackPowerMod)
Definition Unit.h:1562
int32 GetTotalAuraModifierByMiscMask(AuraType auraType, uint32 misc_mask) const
Definition Unit.cpp:4835
virtual void UpdateDamagePhysical(WeaponAttackType attType)
void _ApplyAllAuraStatMods()
Definition Unit.cpp:4376
void SetRangedAttackPowerMultiplier(float attackPowerMult)
Definition Unit.h:1564
uint32 GetWeaponSkillValue(WeaponAttackType attType, Unit const *target=nullptr) const
Definition Unit.cpp:2809
void SetResistance(SpellSchools school, int32 val)
Definition Unit.h:924
float GetTotalAuraMultiplierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:4885
uint32 GetCreateHealth() const
Definition Unit.h:1463
AuraEffect * GetAuraEffectOfRankedSpell(uint32 spellId, uint8 effIndex, ObjectGuid casterGUID=ObjectGuid::Empty) const
Definition Unit.cpp:4396
bool HasAuraType(AuraType auraType) const
Definition Unit.cpp:4565
uint32 GetArmor() const
Definition Unit.h:919
float m_modMeleeHitChance
Definition Unit.h:1510
void _RemoveAllAuraStatMods()
Definition Unit.cpp:4370
uint32 GetAttackTime(WeaponAttackType att) const
Definition Unit.cpp:8411
int32 GetTotalAuraModifier(AuraType auraType) const
Definition Unit.cpp:4815
float GetAPMultiplier(WeaponAttackType attType, bool normalized) const
Definition Unit.cpp:10782
void SetAttackPower(int32 attackPower)
Definition Unit.h:1557
int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const
Definition Unit.cpp:7546
float GetCreateStat(Stats stat) const
Definition Unit.h:1469
void SetArmor(int32 val)
Definition Unit.h:920
float GetAttackPowerModifierValue(AttackPowerModIndex index, AttackPowerModType modifierType) const
Definition Unit.cpp:9115
bool IsInFeralForm() const
Definition Unit.cpp:8909
void SetCanModifyStats(bool modifyStats)
Definition Unit.h:1548
float GetFlatModifierValue(UnitMods unitMod, UnitModifierFlatType modifierType) const
Definition Unit.cpp:9029
float GetStat(Stats stat) const
Definition Unit.h:917
virtual void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float &minDamage, float &maxDamage, uint8 damageIndex) const =0
int32 GetTotalAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:4875
bool HasAuraTypeWithValue(AuraType auraType, int32 value) const
Definition Unit.cpp:4596
void SetMaxHealth(uint32 val)
Definition Unit.cpp:9370
std::list< AuraEffect * > AuraEffectList
Definition Unit.h:801
void SetRangedAttackPower(int32 attackPower)
Definition Unit.h:1561
int32 GetResistance(SpellSchools school) const
Definition Unit.h:922
float m_modSpellHitChance
Definition Unit.h:1512
Guardian * GetGuardianPet() const
Definition Unit.cpp:5836
void SetAttackPowerMultiplier(float attackPowerMult)
Definition Unit.h:1560
int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const
Definition Unit.cpp:6927
uint32 GetCreatePowerValue(Powers power) const
Definition Unit.cpp:9464
void SetAttackPowerModPos(int32 attackPowerMod)
Definition Unit.h:1558
uint8 GetLevel() const
Definition Unit.h:903
bool IsInCombat() const
Definition Unit.h:1158
float GetTotalAttackPowerValue(WeaponAttackType attType) const
Definition Unit.cpp:9289
void UpdateStatBuffMod(Stats stat)
Definition Unit.cpp:4992
uint32 GetMaxSkillValueForLevel(Unit const *target=nullptr) const
Definition Unit.h:1033
#define sWorld
Definition World.h:901
@ RATE_POWER_RAGE_LOSS
Definition World.h:414
@ RATE_POWER_RUNICPOWER_LOSS
Definition World.h:416
@ RATE_POWER_ENERGY
Definition World.h:418
@ RATE_POWER_MANA
Definition World.h:412
@ CONFIG_STATS_LIMITS_DODGE
Definition World.h:197
@ CONFIG_STATS_LIMITS_PARRY
Definition World.h:198
@ CONFIG_STATS_LIMITS_CRIT
Definition World.h:200
@ CONFIG_STATS_LIMITS_BLOCK
Definition World.h:199
@ CONFIG_STATS_LIMITS_ENABLE
Definition World.h:159
int32 GetTotalAPBonus() const