Core/Auras: reworked multiplicative AuraEffects calculation

Port From (https://github.com/TrinityCore/TrinityCore/commit/ebc06b1d0401be69066986e18d0e926170c58023)
This commit is contained in:
hondacrx
2020-05-05 18:38:43 -04:00
parent 5a178644b5
commit 9ec956becf
15 changed files with 796 additions and 428 deletions
+11 -7
View File
@@ -87,7 +87,7 @@ namespace Framework.Constants
public enum BaseModType public enum BaseModType
{ {
FlatMod, FlatMod,
PCTmod, PctMod,
End End
} }
@@ -178,14 +178,18 @@ namespace Framework.Constants
PowerStart = Mana, PowerStart = Mana,
PowerEnd = Pain + 1 PowerEnd = Pain + 1
} }
public enum UnitModifierType public enum UnitModifierFlatType
{ {
BaseValue = 0, Base = 0,
BasePCTExcludeCreate = 1, // percent modifier affecting all stat values from auras and gear but not player base for level BasePCTExcludeCreate = 1, // percent modifier affecting all stat values from auras and gear but not player base for level
BasePCT = 2, Total = 2,
TotalValue = 3, End = 3
TotalPCT = 4, }
End = 5 public enum UnitModifierPctType
{
Base = 0,
Total = 1,
End = 2
} }
public enum VictimState public enum VictimState
{ {
+14 -17
View File
@@ -312,12 +312,12 @@ namespace Game.Entities
UpdateLevelDependantStats(); // We still re-initialize level dependant stats on entry update UpdateLevelDependantStats(); // We still re-initialize level dependant stats on entry update
SetMeleeDamageSchool((SpellSchools)cInfo.DmgSchool); SetMeleeDamageSchool((SpellSchools)cInfo.DmgSchool);
SetModifierValue(UnitMods.ResistanceHoly, UnitModifierType.BaseValue, cInfo.Resistance[(int)SpellSchools.Holy]); SetStatFlatModifier(UnitMods.ResistanceHoly, UnitModifierFlatType.Base, cInfo.Resistance[(int)SpellSchools.Holy]);
SetModifierValue(UnitMods.ResistanceFire, UnitModifierType.BaseValue, cInfo.Resistance[(int)SpellSchools.Fire]); SetStatFlatModifier(UnitMods.ResistanceFire, UnitModifierFlatType.Base, cInfo.Resistance[(int)SpellSchools.Fire]);
SetModifierValue(UnitMods.ResistanceNature, UnitModifierType.BaseValue, cInfo.Resistance[(int)SpellSchools.Nature]); SetStatFlatModifier(UnitMods.ResistanceNature, UnitModifierFlatType.Base, cInfo.Resistance[(int)SpellSchools.Nature]);
SetModifierValue(UnitMods.ResistanceFrost, UnitModifierType.BaseValue, cInfo.Resistance[(int)SpellSchools.Frost]); SetStatFlatModifier(UnitMods.ResistanceFrost, UnitModifierFlatType.Base, cInfo.Resistance[(int)SpellSchools.Frost]);
SetModifierValue(UnitMods.ResistanceShadow, UnitModifierType.BaseValue, cInfo.Resistance[(int)SpellSchools.Shadow]); SetStatFlatModifier(UnitMods.ResistanceShadow, UnitModifierFlatType.Base, cInfo.Resistance[(int)SpellSchools.Shadow]);
SetModifierValue(UnitMods.ResistanceArcane, UnitModifierType.BaseValue, cInfo.Resistance[(int)SpellSchools.Arcane]); SetStatFlatModifier(UnitMods.ResistanceArcane, UnitModifierFlatType.Base, cInfo.Resistance[(int)SpellSchools.Arcane]);
SetCanModifyStats(true); SetCanModifyStats(true);
UpdateAllStats(); UpdateAllStats();
@@ -563,7 +563,7 @@ namespace Game.Entities
if (curValue >= maxValue) if (curValue >= maxValue)
return; return;
float addvalue = 0.0f; float addvalue;
switch (power) switch (power)
{ {
@@ -614,7 +614,7 @@ namespace Game.Entities
if (curValue >= maxValue) if (curValue >= maxValue)
return; return;
long addvalue = 0; long addvalue;
// Not only pet, but any controlled creature (and not polymorphed) // Not only pet, but any controlled creature (and not polymorphed)
if (!GetCharmerOrOwnerGUID().IsEmpty() && !IsPolymorphed()) if (!GetCharmerOrOwnerGUID().IsEmpty() && !IsPolymorphed())
@@ -1166,7 +1166,7 @@ namespace Game.Entities
break; break;
} }
SetModifierValue(UnitMods.Health, UnitModifierType.BaseValue, health); SetStatFlatModifier(UnitMods.Health, UnitModifierFlatType.Base, health);
//Damage //Damage
float basedamage = stats.GenerateBaseDamage(cInfo); float basedamage = stats.GenerateBaseDamage(cInfo);
@@ -1182,11 +1182,11 @@ namespace Game.Entities
SetBaseWeaponDamage(WeaponAttackType.RangedAttack, WeaponDamageRange.MinDamage, weaponBaseMinDamage); SetBaseWeaponDamage(WeaponAttackType.RangedAttack, WeaponDamageRange.MinDamage, weaponBaseMinDamage);
SetBaseWeaponDamage(WeaponAttackType.RangedAttack, WeaponDamageRange.MaxDamage, weaponBaseMaxDamage); SetBaseWeaponDamage(WeaponAttackType.RangedAttack, WeaponDamageRange.MaxDamage, weaponBaseMaxDamage);
SetModifierValue(UnitMods.AttackPower, UnitModifierType.BaseValue, stats.AttackPower); SetStatFlatModifier(UnitMods.AttackPower, UnitModifierFlatType.Base, stats.AttackPower);
SetModifierValue(UnitMods.AttackPowerRanged, UnitModifierType.BaseValue, stats.RangedAttackPower); SetStatFlatModifier(UnitMods.AttackPowerRanged, UnitModifierFlatType.Base, stats.RangedAttackPower);
float armor = stats.GenerateArmor(cInfo); // @todo Why is this treated as uint32 when it's a float? float armor = stats.GenerateArmor(cInfo); // @todo Why is this treated as uint32 when it's a float?
SetModifierValue(UnitMods.Armor, UnitModifierType.BaseValue, armor); SetStatFlatModifier(UnitMods.Armor, UnitModifierFlatType.Base, armor);
} }
float _GetHealthMod(CreatureEliteType Rank) float _GetHealthMod(CreatureEliteType Rank)
@@ -2026,7 +2026,6 @@ namespace Game.Entities
return false; return false;
} }
Unit myVictim = GetAttackerForHelper();
Unit targetVictim = target.GetAttackerForHelper(); Unit targetVictim = target.GetAttackerForHelper();
// if I'm already fighting target, or I'm hostile towards the target, the target is acceptable // if I'm already fighting target, or I'm hostile towards the target, the target is acceptable
@@ -2263,13 +2262,11 @@ namespace Game.Entities
public void GetRespawnPosition(out float x, out float y, out float z) public void GetRespawnPosition(out float x, out float y, out float z)
{ {
float notUsed; GetRespawnPosition(out x, out y, out z, out _, out _);
GetRespawnPosition(out x, out y, out z, out notUsed, out notUsed);
} }
public void GetRespawnPosition(out float x, out float y, out float z, out float ori) public void GetRespawnPosition(out float x, out float y, out float z, out float ori)
{ {
float notUsed; GetRespawnPosition(out x, out y, out z, out ori, out _);
GetRespawnPosition(out x, out y, out z, out ori, out notUsed);
} }
public void GetRespawnPosition(out float x, out float y, out float z, out float ori, out float dist) public void GetRespawnPosition(out float x, out float y, out float z, out float ori, out float dist)
{ {
+1 -6
View File
@@ -157,7 +157,7 @@ namespace Game.Entities
return; return;
// @todo research if talents/effects that increase total agility by x% should increase non-diminishing part // @todo research if talents/effects that increase total agility by x% should increase non-diminishing part
float base_agility = GetCreateStat(Stats.Agility) * m_auraModifiersGroup[(int)UnitMods.StatAgility][(int)UnitModifierType.BasePCT]; float base_agility = GetCreateStat(Stats.Agility) * GetPctModifierValue(UnitMods(UNIT_MOD_STAT_START + STAT_AGILITY), BASE_PCT);
float bonus_agility = GetStat(Stats.Agility) - base_agility; float bonus_agility = GetStat(Stats.Agility) - base_agility;
// calculate diminishing (green in char screen) and non-diminishing (white) contribution // calculate diminishing (green in char screen) and non-diminishing (white) contribution
@@ -166,11 +166,6 @@ namespace Game.Entities
*/ */
} }
float GetTotalPercentageModValue(BaseModGroup modGroup)
{
return m_auraBaseMod[(int)modGroup][0] + m_auraBaseMod[(int)modGroup][1];
}
public float GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) public float GetExpertiseDodgeOrParryReduction(WeaponAttackType attType)
{ {
float baseExpertise = 7.5f; float baseExpertise = 7.5f;
+2 -1
View File
@@ -141,7 +141,8 @@ namespace Game.Entities
//Combat //Combat
int[] baseRatingValue = new int[(int)CombatRating.Max]; int[] baseRatingValue = new int[(int)CombatRating.Max];
public float[][] m_auraBaseMod = new float[(int)BaseModGroup.End][]; float[] m_auraBaseFlatMod = new float[(int)BaseModGroup.End];
float[] m_auraBasePctMod = new float[(int)BaseModGroup.End];
public DuelInfo duel; public DuelInfo duel;
bool m_canParry; bool m_canParry;
bool m_canBlock; bool m_canBlock;
+56 -51
View File
@@ -1098,8 +1098,7 @@ namespace Game.Entities
} }
public InventoryResult CanStoreNewItem(byte bag, byte slot, List<ItemPosCount> dest, uint item, uint count) public InventoryResult CanStoreNewItem(byte bag, byte slot, List<ItemPosCount> dest, uint item, uint count)
{ {
uint notused; return CanStoreItem(bag, slot, dest, item, count, null, false, out _);
return CanStoreItem(bag, slot, dest, item, count, null, false, out notused);
} }
Item _StoreItem(ushort pos, Item pItem, uint count, bool clone, bool update) Item _StoreItem(ushort pos, Item pItem, uint count, bool clone, bool update)
@@ -1233,8 +1232,7 @@ namespace Game.Entities
// attempt equip by one // attempt equip by one
while (titem_amount > 0) while (titem_amount > 0)
{ {
ushort eDest = 0; msg = CanEquipNewItem(ItemConst.NullSlot, out ushort eDest, titem_id, false);
msg = CanEquipNewItem(ItemConst.NullSlot, out eDest, titem_id, false);
if (msg != InventoryResult.Ok) if (msg != InventoryResult.Ok)
break; break;
@@ -1890,7 +1888,7 @@ namespace Game.Entities
//Add/Remove/Misc Item //Add/Remove/Misc Item
public bool AddItem(uint itemId, uint count) public bool AddItem(uint itemId, uint count)
{ {
uint noSpaceForCount = 0; uint noSpaceForCount;
List<ItemPosCount> dest = new List<ItemPosCount>(); List<ItemPosCount> dest = new List<ItemPosCount>();
InventoryResult msg = CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, itemId, count, out noSpaceForCount); InventoryResult msg = CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, itemId, count, out noSpaceForCount);
if (msg != InventoryResult.Ok) if (msg != InventoryResult.Ok)
@@ -3525,7 +3523,7 @@ namespace Game.Entities
} }
uint stacks = count / crItem.maxcount; uint stacks = count / crItem.maxcount;
ItemExtendedCostRecord iece = null; ItemExtendedCostRecord iece;
if (crItem.ExtendedCost != 0) if (crItem.ExtendedCost != 0)
{ {
iece = CliDB.ItemExtendedCostStorage.LookupByKey(crItem.ExtendedCost); iece = CliDB.ItemExtendedCostStorage.LookupByKey(crItem.ExtendedCost);
@@ -3991,8 +3989,15 @@ namespace Game.Entities
_ApplyItemBonuses(item, slot, apply); _ApplyItemBonuses(item, slot, apply);
ApplyItemEquipSpell(item, apply); ApplyItemEquipSpell(item, apply);
if (updateItemAuras) if (updateItemAuras)
{
ApplyItemDependentAuras(item, apply); ApplyItemDependentAuras(item, apply);
WeaponAttackType attackType = Player.GetAttackBySlot(slot, item.GetTemplate().GetInventoryType());
if (attackType != WeaponAttackType.Max)
UpdateWeaponDependentAuras(attackType);
}
ApplyArtifactPowers(item, apply); ApplyArtifactPowers(item, apply);
ApplyAzeritePowers(item, apply); ApplyAzeritePowers(item, apply);
ApplyEnchantment(item, apply); ApplyEnchantment(item, apply);
@@ -4025,22 +4030,22 @@ namespace Game.Entities
switch ((ItemModType)statType) switch ((ItemModType)statType)
{ {
case ItemModType.Mana: case ItemModType.Mana:
HandleStatModifier(UnitMods.Mana, UnitModifierType.BaseValue, (float)val, apply); HandleStatFlatModifier(UnitMods.Mana, UnitModifierFlatType.Base, (float)val, apply);
break; break;
case ItemModType.Health: // modify HP case ItemModType.Health: // modify HP
HandleStatModifier(UnitMods.Health, UnitModifierType.BaseValue, (float)val, apply); HandleStatFlatModifier(UnitMods.Health, UnitModifierFlatType.Base, (float)val, apply);
break; break;
case ItemModType.Agility: // modify agility case ItemModType.Agility: // modify agility
HandleStatModifier(UnitMods.StatAgility, UnitModifierType.BaseValue, (float)val, apply); HandleStatFlatModifier(UnitMods.StatAgility, UnitModifierFlatType.Base, (float)val, apply);
ApplyStatBuffMod(Stats.Agility, MathFunctions.CalculatePct(val, GetModifierValue(UnitMods.StatAgility, UnitModifierType.BasePCTExcludeCreate)), apply); UpdateStatBuffMod(Stats.Agility);
break; break;
case ItemModType.Strength: //modify strength case ItemModType.Strength: //modify strength
HandleStatModifier(UnitMods.StatStrength, UnitModifierType.BaseValue, (float)val, apply); HandleStatFlatModifier(UnitMods.StatStrength, UnitModifierFlatType.Base, (float)val, apply);
ApplyStatBuffMod(Stats.Strength, MathFunctions.CalculatePct(val, GetModifierValue(UnitMods.StatStrength, UnitModifierType.BasePCTExcludeCreate)), apply); UpdateStatBuffMod(Stats.Strength);
break; break;
case ItemModType.Intellect: //modify intellect case ItemModType.Intellect: //modify intellect
HandleStatModifier(UnitMods.StatIntellect, UnitModifierType.BaseValue, (float)val, apply); HandleStatFlatModifier(UnitMods.StatIntellect, UnitModifierFlatType.Base, (float)val, apply);
ApplyStatBuffMod(Stats.Intellect, MathFunctions.CalculatePct(val, GetModifierValue(UnitMods.StatIntellect, UnitModifierType.BasePCTExcludeCreate)), apply); UpdateStatBuffMod(Stats.Intellect);
break; break;
//case ItemModType.Spirit: //modify spirit //case ItemModType.Spirit: //modify spirit
//HandleStatModifier(UnitMods.StatSpirit, UnitModifierType.BaseValue, (float)val, apply); //HandleStatModifier(UnitMods.StatSpirit, UnitModifierType.BaseValue, (float)val, apply);
@@ -4051,8 +4056,8 @@ namespace Game.Entities
if (staminaMult != null) if (staminaMult != null)
val = (int)(val * CliDB.GetIlvlStatMultiplier(staminaMult, proto.GetInventoryType())); val = (int)(val * CliDB.GetIlvlStatMultiplier(staminaMult, proto.GetInventoryType()));
HandleStatModifier(UnitMods.StatStamina, UnitModifierType.BaseValue, (float)val, apply); HandleStatFlatModifier(UnitMods.StatStamina, UnitModifierFlatType.Base, (float)val, apply);
ApplyStatBuffMod(Stats.Stamina, MathFunctions.CalculatePct(val, GetModifierValue(UnitMods.StatStamina, UnitModifierType.BasePCTExcludeCreate)), apply); UpdateStatBuffMod(Stats.Stamina);
break; break;
case ItemModType.DefenseSkillRating: case ItemModType.DefenseSkillRating:
ApplyRatingMod(CombatRating.DefenseSkill, (int)(val * combatRatingMultiplier), apply); ApplyRatingMod(CombatRating.DefenseSkill, (int)(val * combatRatingMultiplier), apply);
@@ -4118,11 +4123,11 @@ namespace Game.Entities
ApplyRatingMod(CombatRating.Expertise, (int)(val * combatRatingMultiplier), apply); ApplyRatingMod(CombatRating.Expertise, (int)(val * combatRatingMultiplier), apply);
break; break;
case ItemModType.AttackPower: case ItemModType.AttackPower:
HandleStatModifier(UnitMods.AttackPower, UnitModifierType.TotalValue, (float)val, apply); HandleStatFlatModifier(UnitMods.AttackPower, UnitModifierFlatType.Total, (float)val, apply);
HandleStatModifier(UnitMods.AttackPowerRanged, UnitModifierType.TotalValue, (float)val, apply); HandleStatFlatModifier(UnitMods.AttackPowerRanged, UnitModifierFlatType.Total, (float)val, apply);
break; break;
case ItemModType.RangedAttackPower: case ItemModType.RangedAttackPower:
HandleStatModifier(UnitMods.AttackPowerRanged, UnitModifierType.TotalValue, (float)val, apply); HandleStatFlatModifier(UnitMods.AttackPowerRanged, UnitModifierFlatType.Total, (float)val, apply);
break; break;
case ItemModType.Versatility: case ItemModType.Versatility:
ApplyRatingMod(CombatRating.VersatilityDamageDone, (int)(val * combatRatingMultiplier), apply); ApplyRatingMod(CombatRating.VersatilityDamageDone, (int)(val * combatRatingMultiplier), apply);
@@ -4148,25 +4153,25 @@ namespace Game.Entities
ApplyRatingMod(CombatRating.Mastery, (int)(val * combatRatingMultiplier), apply); ApplyRatingMod(CombatRating.Mastery, (int)(val * combatRatingMultiplier), apply);
break; break;
case ItemModType.ExtraArmor: case ItemModType.ExtraArmor:
HandleStatModifier(UnitMods.Armor, UnitModifierType.TotalValue, (float)val, apply); HandleStatFlatModifier(UnitMods.Armor, UnitModifierFlatType.Total, (float)val, apply);
break; break;
case ItemModType.FireResistance: case ItemModType.FireResistance:
HandleStatModifier(UnitMods.ResistanceFire, UnitModifierType.BaseValue, (float)val, apply); HandleStatFlatModifier(UnitMods.ResistanceFire, UnitModifierFlatType.Base, (float)val, apply);
break; break;
case ItemModType.FrostResistance: case ItemModType.FrostResistance:
HandleStatModifier(UnitMods.ResistanceFrost, UnitModifierType.BaseValue, (float)val, apply); HandleStatFlatModifier(UnitMods.ResistanceFrost, UnitModifierFlatType.Base, (float)val, apply);
break; break;
case ItemModType.HolyResistance: case ItemModType.HolyResistance:
HandleStatModifier(UnitMods.ResistanceHoly, UnitModifierType.BaseValue, (float)val, apply); HandleStatFlatModifier(UnitMods.ResistanceHoly, UnitModifierFlatType.Base, (float)val, apply);
break; break;
case ItemModType.ShadowResistance: case ItemModType.ShadowResistance:
HandleStatModifier(UnitMods.ResistanceShadow, UnitModifierType.BaseValue, (float)val, apply); HandleStatFlatModifier(UnitMods.ResistanceShadow, UnitModifierFlatType.Base, (float)val, apply);
break; break;
case ItemModType.NatureResistance: case ItemModType.NatureResistance:
HandleStatModifier(UnitMods.ResistanceNature, UnitModifierType.BaseValue, (float)val, apply); HandleStatFlatModifier(UnitMods.ResistanceNature, UnitModifierFlatType.Base, (float)val, apply);
break; break;
case ItemModType.ArcaneResistance: case ItemModType.ArcaneResistance:
HandleStatModifier(UnitMods.ResistanceArcane, UnitModifierType.BaseValue, (float)val, apply); HandleStatFlatModifier(UnitMods.ResistanceArcane, UnitModifierFlatType.Base, (float)val, apply);
break; break;
case ItemModType.PvpPower: case ItemModType.PvpPower:
ApplyRatingMod(CombatRating.PvpPower, val, apply); ApplyRatingMod(CombatRating.PvpPower, val, apply);
@@ -4202,37 +4207,37 @@ namespace Game.Entities
ApplyRatingMod(CombatRating.Unused12, val, apply); ApplyRatingMod(CombatRating.Unused12, val, apply);
break; break;
case ItemModType.AgiStrInt: case ItemModType.AgiStrInt:
HandleStatModifier(UnitMods.StatAgility, UnitModifierType.BaseValue, val, apply); HandleStatFlatModifier(UnitMods.StatAgility, UnitModifierFlatType.Base, val, apply);
HandleStatModifier(UnitMods.StatStrength, UnitModifierType.BaseValue, val, apply); HandleStatFlatModifier(UnitMods.StatStrength, UnitModifierFlatType.Base, val, apply);
HandleStatModifier(UnitMods.StatIntellect, UnitModifierType.BaseValue, val, apply); HandleStatFlatModifier(UnitMods.StatIntellect, UnitModifierFlatType.Base, val, apply);
ApplyStatBuffMod(Stats.Agility, MathFunctions.CalculatePct(val, GetModifierValue(UnitMods.StatAgility, UnitModifierType.BasePCTExcludeCreate)), apply); UpdateStatBuffMod(Stats.Agility);
ApplyStatBuffMod(Stats.Strength, MathFunctions.CalculatePct(val, GetModifierValue(UnitMods.StatStrength, UnitModifierType.BasePCTExcludeCreate)), apply); UpdateStatBuffMod(Stats.Strength);
ApplyStatBuffMod(Stats.Intellect, MathFunctions.CalculatePct(val, GetModifierValue(UnitMods.StatIntellect, UnitModifierType.BasePCTExcludeCreate)), apply); UpdateStatBuffMod(Stats.Intellect);
break; break;
case ItemModType.AgiStr: case ItemModType.AgiStr:
HandleStatModifier(UnitMods.StatAgility, UnitModifierType.BaseValue, val, apply); HandleStatFlatModifier(UnitMods.StatAgility, UnitModifierFlatType.Base, val, apply);
HandleStatModifier(UnitMods.StatStrength, UnitModifierType.BaseValue, val, apply); HandleStatFlatModifier(UnitMods.StatStrength, UnitModifierFlatType.Base, val, apply);
ApplyStatBuffMod(Stats.Agility, MathFunctions.CalculatePct(val, GetModifierValue(UnitMods.StatAgility, UnitModifierType.BasePCTExcludeCreate)), apply); UpdateStatBuffMod(Stats.Agility);
ApplyStatBuffMod(Stats.Strength, MathFunctions.CalculatePct(val, GetModifierValue(UnitMods.StatStrength, UnitModifierType.BasePCTExcludeCreate)), apply); UpdateStatBuffMod(Stats.Strength);
break; break;
case ItemModType.AgiInt: case ItemModType.AgiInt:
HandleStatModifier(UnitMods.StatAgility, UnitModifierType.BaseValue, val, apply); HandleStatFlatModifier(UnitMods.StatAgility, UnitModifierFlatType.Base, val, apply);
HandleStatModifier(UnitMods.StatIntellect, UnitModifierType.BaseValue, val, apply); HandleStatFlatModifier(UnitMods.StatIntellect, UnitModifierFlatType.Base, val, apply);
ApplyStatBuffMod(Stats.Agility, MathFunctions.CalculatePct(val, GetModifierValue(UnitMods.StatAgility, UnitModifierType.BasePCTExcludeCreate)), apply); UpdateStatBuffMod(Stats.Agility);
ApplyStatBuffMod(Stats.Intellect, MathFunctions.CalculatePct(val, GetModifierValue(UnitMods.StatIntellect, UnitModifierType.BasePCTExcludeCreate)), apply); UpdateStatBuffMod(Stats.Intellect);
break; break;
case ItemModType.StrInt: case ItemModType.StrInt:
HandleStatModifier(UnitMods.StatStrength, UnitModifierType.BaseValue, val, apply); HandleStatFlatModifier(UnitMods.StatStrength, UnitModifierFlatType.Base, val, apply);
HandleStatModifier(UnitMods.StatIntellect, UnitModifierType.BaseValue, val, apply); HandleStatFlatModifier(UnitMods.StatIntellect, UnitModifierFlatType.Base, val, apply);
ApplyStatBuffMod(Stats.Strength, MathFunctions.CalculatePct(val, GetModifierValue(UnitMods.StatStrength, UnitModifierType.BasePCTExcludeCreate)), apply); UpdateStatBuffMod(Stats.Strength);
ApplyStatBuffMod(Stats.Intellect, MathFunctions.CalculatePct(val, GetModifierValue(UnitMods.StatIntellect, UnitModifierType.BasePCTExcludeCreate)), apply); UpdateStatBuffMod(Stats.Intellect);
break; break;
} }
} }
uint armor = item.GetArmor(this); uint armor = item.GetArmor(this);
if (armor != 0) if (armor != 0)
HandleStatModifier(UnitMods.Armor, UnitModifierType.BaseValue, (float)armor, apply); HandleStatFlatModifier(UnitMods.Armor, UnitModifierFlatType.Base, (float)armor, apply);
WeaponAttackType attType = WeaponAttackType.BaseAttack; WeaponAttackType attType = WeaponAttackType.BaseAttack;
if (slot == EquipmentSlot.MainHand && (proto.GetInventoryType() == InventoryType.Ranged || proto.GetInventoryType() == InventoryType.RangedRight)) if (slot == EquipmentSlot.MainHand && (proto.GetInventoryType() == InventoryType.Ranged || proto.GetInventoryType() == InventoryType.RangedRight))
@@ -4425,6 +4430,10 @@ namespace Game.Entities
ApplyItemDependentAuras(m_items[i], true); ApplyItemDependentAuras(m_items[i], true);
_ApplyItemBonuses(m_items[i], i, true); _ApplyItemBonuses(m_items[i], i, true);
WeaponAttackType attackType = Player.GetAttackBySlot(i, m_items[i].GetTemplate().GetInventoryType());
if (attackType != WeaponAttackType.Max)
UpdateWeaponDependentAuras(attackType);
} }
} }
@@ -6229,11 +6238,7 @@ namespace Game.Entities
public void SetLootGUID(ObjectGuid guid) { SetUpdateFieldValue(m_values.ModifyValue(m_playerData).ModifyValue(m_playerData.LootTargetGUID), guid); } public void SetLootGUID(ObjectGuid guid) { SetUpdateFieldValue(m_values.ModifyValue(m_playerData).ModifyValue(m_playerData.LootTargetGUID), guid); }
public void StoreLootItem(byte lootSlot, Loot loot, AELootResult aeResult = null) public void StoreLootItem(byte lootSlot, Loot loot, AELootResult aeResult = null)
{ {
NotNormalLootItem qitem = null; LootItem item = loot.LootItemInSlot(lootSlot, this, out NotNormalLootItem qitem, out NotNormalLootItem ffaitem, out NotNormalLootItem conditem);
NotNormalLootItem ffaitem = null;
NotNormalLootItem conditem = null;
LootItem item = loot.LootItemInSlot(lootSlot, this, out qitem, out ffaitem, out conditem);
if (item == null) if (item == null)
{ {
SendEquipError(InventoryResult.LootGone); SendEquipError(InventoryResult.LootGone);
@@ -6385,7 +6390,7 @@ namespace Game.Entities
if (!currentLootGuid.IsEmpty() && !aeLooting) if (!currentLootGuid.IsEmpty() && !aeLooting)
Session.DoLootRelease(currentLootGuid); Session.DoLootRelease(currentLootGuid);
Loot loot = null; Loot loot;
PermissionTypes permission = PermissionTypes.All; PermissionTypes permission = PermissionTypes.All;
Log.outDebug(LogFilter.Loot, "Player.SendLoot"); Log.outDebug(LogFilter.Loot, "Player.SendLoot");
+78 -41
View File
@@ -153,9 +153,6 @@ namespace Game.Entities
if (skillStatusData == null || skillStatusData.State == SkillState.Deleted || skillInfo.SkillRank[skillStatusData.Pos] == 0) if (skillStatusData == null || skillStatusData.State == SkillState.Deleted || skillInfo.SkillRank[skillStatusData.Pos] == 0)
return 0; return 0;
var field = (ushort)(skillStatusData.Pos / 2);
var offset = (byte)(skillStatusData.Pos & 1);
return skillInfo.SkillStep[skillStatusData.Pos]; return skillInfo.SkillStep[skillStatusData.Pos];
} }
@@ -613,15 +610,11 @@ namespace Game.Entities
// processed in Player.CastItemCombatSpell // processed in Player.CastItemCombatSpell
break; break;
case ItemEnchantmentType.Damage: case ItemEnchantmentType.Damage:
if (item.GetSlot() == EquipmentSlot.MainHand)
{ {
if (item.GetTemplate().GetInventoryType() != InventoryType.Ranged && item.GetTemplate().GetInventoryType() != InventoryType.RangedRight) WeaponAttackType attackType = Player.GetAttackBySlot(item.GetSlot(), item.GetTemplate().GetInventoryType());
HandleStatModifier(UnitMods.DamageMainHand, UnitModifierType.TotalValue, enchant_amount, apply); if (attackType != WeaponAttackType.Max)
else UpdateDamageDoneMods(attackType);
HandleStatModifier(UnitMods.DamageRanged, UnitModifierType.TotalValue, enchant_amount, apply);
} }
else if (item.GetSlot() == EquipmentSlot.OffHand)
HandleStatModifier(UnitMods.DamageOffHand, UnitModifierType.TotalValue, enchant_amount, apply);
break; break;
case ItemEnchantmentType.EquipSpell: case ItemEnchantmentType.EquipSpell:
if (enchant_spell_id != 0) if (enchant_spell_id != 0)
@@ -654,7 +647,7 @@ namespace Game.Entities
} }
enchant_amount = Math.Max(enchant_amount, 1u); enchant_amount = Math.Max(enchant_amount, 1u);
HandleStatModifier((UnitMods)((uint)UnitMods.ResistanceStart + enchant_spell_id), UnitModifierType.TotalValue, enchant_amount, apply); HandleStatFlatModifier((UnitMods)((uint)UnitMods.ResistanceStart + enchant_spell_id), UnitModifierFlatType.Total, enchant_amount, apply);
break; break;
case ItemEnchantmentType.Stat: case ItemEnchantmentType.Stat:
{ {
@@ -685,26 +678,26 @@ namespace Game.Entities
{ {
case ItemModType.Mana: case ItemModType.Mana:
Log.outDebug(LogFilter.Player, "+ {0} MANA", enchant_amount); Log.outDebug(LogFilter.Player, "+ {0} MANA", enchant_amount);
HandleStatModifier(UnitMods.Mana, UnitModifierType.BaseValue, enchant_amount, apply); HandleStatFlatModifier(UnitMods.Mana, UnitModifierFlatType.Base, enchant_amount, apply);
break; break;
case ItemModType.Health: case ItemModType.Health:
Log.outDebug(LogFilter.Player, "+ {0} HEALTH", enchant_amount); Log.outDebug(LogFilter.Player, "+ {0} HEALTH", enchant_amount);
HandleStatModifier(UnitMods.Health, UnitModifierType.BaseValue, enchant_amount, apply); HandleStatFlatModifier(UnitMods.Health, UnitModifierFlatType.Base, enchant_amount, apply);
break; break;
case ItemModType.Agility: case ItemModType.Agility:
Log.outDebug(LogFilter.Player, "+ {0} AGILITY", enchant_amount); Log.outDebug(LogFilter.Player, "+ {0} AGILITY", enchant_amount);
HandleStatModifier(UnitMods.StatAgility, UnitModifierType.TotalValue, enchant_amount, apply); HandleStatFlatModifier(UnitMods.StatAgility, UnitModifierFlatType.Total, enchant_amount, apply);
ApplyStatBuffMod(Stats.Agility, enchant_amount, apply); UpdateStatBuffMod(Stats.Agility);
break; break;
case ItemModType.Strength: case ItemModType.Strength:
Log.outDebug(LogFilter.Player, "+ {0} STRENGTH", enchant_amount); Log.outDebug(LogFilter.Player, "+ {0} STRENGTH", enchant_amount);
HandleStatModifier(UnitMods.StatStrength, UnitModifierType.TotalValue, enchant_amount, apply); HandleStatFlatModifier(UnitMods.StatStrength, UnitModifierFlatType.Total, enchant_amount, apply);
ApplyStatBuffMod(Stats.Strength, enchant_amount, apply); UpdateStatBuffMod(Stats.Strength);
break; break;
case ItemModType.Intellect: case ItemModType.Intellect:
Log.outDebug(LogFilter.Player, "+ {0} INTELLECT", enchant_amount); Log.outDebug(LogFilter.Player, "+ {0} INTELLECT", enchant_amount);
HandleStatModifier(UnitMods.StatIntellect, UnitModifierType.TotalValue, enchant_amount, apply); HandleStatFlatModifier(UnitMods.StatIntellect, UnitModifierFlatType.Total, enchant_amount, apply);
ApplyStatBuffMod(Stats.Intellect, enchant_amount, apply); UpdateStatBuffMod(Stats.Intellect);
break; break;
//case ItemModType.Spirit: //case ItemModType.Spirit:
//Log.outDebug(LogFilter.Player, "+ {0} SPIRIT", enchant_amount); //Log.outDebug(LogFilter.Player, "+ {0} SPIRIT", enchant_amount);
@@ -713,8 +706,8 @@ namespace Game.Entities
//break; //break;
case ItemModType.Stamina: case ItemModType.Stamina:
Log.outDebug(LogFilter.Player, "+ {0} STAMINA", enchant_amount); Log.outDebug(LogFilter.Player, "+ {0} STAMINA", enchant_amount);
HandleStatModifier(UnitMods.StatStamina, UnitModifierType.TotalValue, enchant_amount, apply); HandleStatFlatModifier(UnitMods.StatStamina, UnitModifierFlatType.Total, enchant_amount, apply);
ApplyStatBuffMod(Stats.Stamina, enchant_amount, apply); UpdateStatBuffMod(Stats.Stamina);
break; break;
case ItemModType.DefenseSkillRating: case ItemModType.DefenseSkillRating:
ApplyRatingMod(CombatRating.DefenseSkill, (int)enchant_amount, apply); ApplyRatingMod(CombatRating.DefenseSkill, (int)enchant_amount, apply);
@@ -786,12 +779,12 @@ namespace Game.Entities
Log.outDebug(LogFilter.Player, "+ {0} EXPERTISE", enchant_amount); Log.outDebug(LogFilter.Player, "+ {0} EXPERTISE", enchant_amount);
break; break;
case ItemModType.AttackPower: case ItemModType.AttackPower:
HandleStatModifier(UnitMods.AttackPower, UnitModifierType.TotalValue, enchant_amount, apply); HandleStatFlatModifier(UnitMods.AttackPower, UnitModifierFlatType.Total, enchant_amount, apply);
HandleStatModifier(UnitMods.AttackPowerRanged, UnitModifierType.TotalValue, enchant_amount, apply); HandleStatFlatModifier(UnitMods.AttackPowerRanged, UnitModifierFlatType.Total, enchant_amount, apply);
Log.outDebug(LogFilter.Player, "+ {0} ATTACK_POWER", enchant_amount); Log.outDebug(LogFilter.Player, "+ {0} ATTACK_POWER", enchant_amount);
break; break;
case ItemModType.RangedAttackPower: case ItemModType.RangedAttackPower:
HandleStatModifier(UnitMods.AttackPowerRanged, UnitModifierType.TotalValue, enchant_amount, apply); HandleStatFlatModifier(UnitMods.AttackPowerRanged, UnitModifierFlatType.Total, enchant_amount, apply);
Log.outDebug(LogFilter.Player, "+ {0} RANGED_ATTACK_POWER", enchant_amount); Log.outDebug(LogFilter.Player, "+ {0} RANGED_ATTACK_POWER", enchant_amount);
break; break;
case ItemModType.ManaRegeneration: case ItemModType.ManaRegeneration:
@@ -815,7 +808,7 @@ namespace Game.Entities
Log.outDebug(LogFilter.Player, "+ {0} SPELL_PENETRATION", enchant_amount); Log.outDebug(LogFilter.Player, "+ {0} SPELL_PENETRATION", enchant_amount);
break; break;
case ItemModType.BlockValue: case ItemModType.BlockValue:
HandleBaseModValue(BaseModGroup.ShieldBlockValue, BaseModType.FlatMod, enchant_amount, apply); HandleBaseModFlatValue(BaseModGroup.ShieldBlockValue, enchant_amount, apply);
Log.outDebug(LogFilter.Player, "+ {0} BLOCK_VALUE", enchant_amount); Log.outDebug(LogFilter.Player, "+ {0} BLOCK_VALUE", enchant_amount);
break; break;
case ItemModType.MasteryRating: case ItemModType.MasteryRating:
@@ -835,20 +828,9 @@ namespace Game.Entities
} }
case ItemEnchantmentType.Totem: // Shaman Rockbiter Weapon case ItemEnchantmentType.Totem: // Shaman Rockbiter Weapon
{ {
if (GetClass() == Class.Shaman) WeaponAttackType attackType = Player.GetAttackBySlot(item.GetSlot(), item.GetTemplate().GetInventoryType());
{ if (attackType != WeaponAttackType.Max)
float addValue = 0.0f; UpdateDamageDoneMods(attackType);
if (item.GetSlot() == EquipmentSlot.MainHand)
{
addValue = enchant_amount * item.GetTemplate().GetDelay() / 1000.0f;
HandleStatModifier(UnitMods.DamageMainHand, UnitModifierType.TotalValue, addValue, apply);
}
else if (item.GetSlot() == EquipmentSlot.OffHand)
{
addValue = enchant_amount * item.GetTemplate().GetDelay() / 1000.0f;
HandleStatModifier(UnitMods.DamageOffHand, UnitModifierType.TotalValue, addValue, apply);
}
}
break; break;
} }
case ItemEnchantmentType.UseSpell: case ItemEnchantmentType.UseSpell:
@@ -1187,14 +1169,14 @@ namespace Game.Entities
if (skillSlot == 0) if (skillSlot == 0)
{ {
Log.outError(LogFilter.Misc, $"Tried to add skill {id} but player {GetName()} ({GetGUID().ToString()}) cannot have additional skills"); Log.outError(LogFilter.Misc, $"Tried to add skill {id} but player {GetName()} ({GetGUID()}) cannot have additional skills");
return; return;
} }
SkillLineRecord skillEntry = CliDB.SkillLineStorage.LookupByKey(id); SkillLineRecord skillEntry = CliDB.SkillLineStorage.LookupByKey(id);
if (skillEntry == null) if (skillEntry == null)
{ {
Log.outError(LogFilter.Misc, $"Player.SetSkill: Skill (SkillID: {id}) not found in SkillLineStore for player '{GetName()}' ({GetGUID().ToString()})"); Log.outError(LogFilter.Misc, $"Player.SetSkill: Skill (SkillID: {id}) not found in SkillLineStore for player '{GetName()}' ({GetGUID()})");
return; return;
} }
@@ -1829,6 +1811,48 @@ namespace Game.Entities
} }
} }
// this one rechecks weapon auras and stores them in BaseModGroup container
// needed for things like axe specialization applying only to axe weapons in case of dual-wield
void UpdateWeaponDependentCritAuras(WeaponAttackType attackType)
{
BaseModGroup modGroup;
switch (attackType)
{
case WeaponAttackType.BaseAttack:
modGroup = BaseModGroup.CritPercentage;
break;
case WeaponAttackType.OffAttack:
modGroup = BaseModGroup.OffhandCritPercentage;
break;
case WeaponAttackType.RangedAttack:
modGroup = BaseModGroup.RangedCritPercentage;
break;
default:
return;
}
float amount = 0.0f;
amount += GetTotalAuraModifier(AuraType.ModWeaponCritPercent, auraEffect => CheckAttackFitToAuraRequirement(attackType, auraEffect));
// these auras don't have item requirement (only Combat Expertise in 3.3.5a)
amount += GetTotalAuraModifier(AuraType.ModCritPct);
SetBaseModFlatValue(modGroup, amount);
}
public void UpdateAllWeaponDependentCritAuras()
{
for (var attackType = WeaponAttackType.BaseAttack; attackType < WeaponAttackType.Max; ++attackType)
UpdateWeaponDependentCritAuras(attackType);
}
public void UpdateWeaponDependentAuras(WeaponAttackType attackType)
{
UpdateWeaponDependentCritAuras(attackType);
UpdateDamageDoneMods(attackType);
UpdateDamagePctDoneMods(attackType);
}
public void ApplyItemDependentAuras(Item item, bool apply) public void ApplyItemDependentAuras(Item item, bool apply)
{ {
if (apply) if (apply)
@@ -1851,6 +1875,19 @@ namespace Game.Entities
RemoveItemDependentAurasAndCasts(item); RemoveItemDependentAurasAndCasts(item);
} }
public override bool CheckAttackFitToAuraRequirement(WeaponAttackType attackType, AuraEffect aurEff)
{
SpellInfo spellInfo = aurEff.GetSpellInfo();
if (spellInfo.EquippedItemClass == ItemClass.None)
return true;
Item item = GetWeaponForAttack(attackType, true);
if (item == null || !item.IsFitToSpellRequirements(spellInfo))
return false;
return true;
}
public void AddTemporarySpell(uint spellId) public void AddTemporarySpell(uint spellId)
{ {
var spell = m_spells.LookupByKey(spellId); var spell = m_spells.LookupByKey(spellId);
+116 -24
View File
@@ -83,7 +83,10 @@ namespace Game.Entities
_specializationInfo = new SpecializationInfo(); _specializationInfo = new SpecializationInfo();
for (byte i = 0; i < (byte)BaseModGroup.End; ++i) for (byte i = 0; i < (byte)BaseModGroup.End; ++i)
m_auraBaseMod[i] = new float[] { 0.0f, 1.0f }; {
m_auraBaseFlatMod[i] = 0.0f;
m_auraBasePctMod[i] = 1.0f;
}
for (var i = 0; i < (int)SpellModOp.Max; ++i) for (var i = 0; i < (int)SpellModOp.Max; ++i)
{ {
@@ -3791,7 +3794,7 @@ namespace Game.Entities
if (powerType == null) if (powerType == null)
return; return;
float addvalue = 0.0f; float addvalue;
if (!IsInCombat()) if (!IsInCombat())
{ {
@@ -4695,7 +4698,7 @@ namespace Game.Entities
SpawnCorpseBones(); SpawnCorpseBones();
} }
WorldSafeLocsEntry ClosestGrave = null; WorldSafeLocsEntry ClosestGrave;
// Special handle for Battlegroundmaps // Special handle for Battlegroundmaps
Battleground bg = GetBattleground(); Battleground bg = GetBattleground();
@@ -5333,8 +5336,7 @@ namespace Game.Entities
PlayerLevelInfo info = Global.ObjectMgr.GetPlayerLevelInfo(GetRace(), GetClass(), level); PlayerLevelInfo info = Global.ObjectMgr.GetPlayerLevelInfo(GetRace(), GetClass(), level);
uint basemana = 0; Global.ObjectMgr.GetPlayerClassLevelInfo(GetClass(), level, out uint basemana);
Global.ObjectMgr.GetPlayerClassLevelInfo(GetClass(), level, out basemana);
LevelUpInfo packet = new LevelUpInfo(); LevelUpInfo packet = new LevelUpInfo();
packet.Level = level; packet.Level = level;
@@ -6567,7 +6569,7 @@ namespace Game.Entities
if (level >= WorldConfig.GetIntValue(WorldCfg.MaxPlayerLevel)) if (level >= WorldConfig.GetIntValue(WorldCfg.MaxPlayerLevel))
return; return;
uint bonus_xp = 0; uint bonus_xp;
bool recruitAFriend = GetsRecruitAFriendBonus(true); bool recruitAFriend = GetsRecruitAFriendBonus(true);
// RaF does NOT stack with rested experience // RaF does NOT stack with rested experience
@@ -6603,36 +6605,104 @@ namespace Game.Entities
SetXP(newXP); SetXP(newXP);
} }
public void HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, float amount, bool apply) public void HandleBaseModFlatValue(BaseModGroup modGroup, float amount, bool apply)
{ {
if (modGroup >= BaseModGroup.End || modType >= BaseModType.End) if (modGroup >= BaseModGroup.End)
{ {
Log.outError(LogFilter.Spells, "ERROR in HandleBaseModValue(): non existed BaseModGroup of wrong BaseModType!"); Log.outError(LogFilter.Spells, $"Player.HandleBaseModFlatValue: Invalid BaseModGroup ({modGroup}) for player '{GetName()}' ({GetGUID()})");
return;
}
m_auraBaseFlatMod[(int)modGroup] += apply ? amount : -amount;
UpdateBaseModGroup(modGroup);
}
public void ApplyBaseModPctValue(BaseModGroup modGroup, float pct)
{
if (modGroup >= BaseModGroup.End)
{
Log.outError(LogFilter.Spells, $"Player.ApplyBaseModPctValue: Invalid BaseModGroup/BaseModType ({modGroup}/{BaseModType.FlatMod}) for player '{GetName()}' ({GetGUID()})");
return; return;
} }
switch (modType) MathFunctions.AddPct(ref m_auraBasePctMod[(int)modGroup], pct);
UpdateBaseModGroup(modGroup);
}
public void SetBaseModFlatValue(BaseModGroup modGroup, float val)
{
if (m_auraBaseFlatMod[(int)modGroup] == val)
return;
m_auraBaseFlatMod[(int)modGroup] = val;
UpdateBaseModGroup(modGroup);
}
public void SetBaseModPctValue(BaseModGroup modGroup, float val)
{
if (m_auraBasePctMod[(int)modGroup] == val)
return;
m_auraBasePctMod[(int)modGroup] = val;
UpdateBaseModGroup(modGroup);
}
public override void UpdateDamageDoneMods(WeaponAttackType attackType)
{
base.UpdateDamageDoneMods(attackType);
UnitMods unitMod = attackType switch
{ {
case BaseModType.FlatMod: WeaponAttackType.BaseAttack => UnitMods.DamageMainHand,
m_auraBaseMod[(int)modGroup][(int)modType] += apply ? amount : -amount; WeaponAttackType.OffAttack => UnitMods.DamageOffHand,
break; WeaponAttackType.RangedAttack => UnitMods.DamageRanged,
case BaseModType.PCTmod: _ => throw new NotImplementedException(),
MathFunctions.ApplyPercentModFloatVar(ref m_auraBaseMod[(int)modGroup][(int)modType], amount, apply); };
break;
float amount = 0.0f;
Item item = GetWeaponForAttack(attackType, true);
if (item == null)
return;
for (var slot = EnchantmentSlot.Perm; slot < EnchantmentSlot.Max; ++slot)
{
SpellItemEnchantmentRecord enchantmentEntry = CliDB.SpellItemEnchantmentStorage.LookupByKey(item.GetEnchantmentId(slot));
if (enchantmentEntry == null)
continue;
for (byte i = 0; i < ItemConst.MaxItemEnchantmentEffects; ++i)
{
switch (enchantmentEntry.Effect[i])
{
case ItemEnchantmentType.Damage:
amount += enchantmentEntry.EffectScalingPoints[i];
break;
case ItemEnchantmentType.Totem:
if (GetClass() == Class.Shaman)
amount += enchantmentEntry.EffectScalingPoints[i] * item.GetTemplate().GetDelay() / 1000.0f;
break;
default:
break;
}
}
} }
HandleStatFlatModifier(unitMod, UnitModifierFlatType.Total, amount, true);
}
void UpdateBaseModGroup(BaseModGroup modGroup)
{
if (!CanModifyStats()) if (!CanModifyStats())
return; return;
switch (modGroup) switch (modGroup)
{ {
case BaseModGroup.CritPercentage: case BaseModGroup.CritPercentage:
UpdateCritPercentage(WeaponAttackType.BaseAttack); UpdateCritPercentage(WeaponAttackType.BaseAttack);
break; break;
case BaseModGroup.RangedCritPercentage: case BaseModGroup.RangedCritPercentage:
UpdateCritPercentage(WeaponAttackType.RangedAttack); UpdateCritPercentage(WeaponAttackType.RangedAttack);
break; break;
case BaseModGroup.OffhandCritPercentage: case BaseModGroup.OffhandCritPercentage:
UpdateCritPercentage(WeaponAttackType.OffAttack); UpdateCritPercentage(WeaponAttackType.OffAttack);
break; break;
default: default:
@@ -6640,6 +6710,28 @@ namespace Game.Entities
} }
} }
float GetBaseModValue(BaseModGroup modGroup, BaseModType modType)
{
if (modGroup >= BaseModGroup.End || modType >= BaseModType.End)
{
Log.outError(LogFilter.Spells, $"Player.GetBaseModValue: Invalid BaseModGroup/BaseModType ({modGroup}/{modType}) for player '{GetName()}' ({GetGUID()})");
return 0.0f;
}
return (modType == BaseModType.FlatMod ? m_auraBaseFlatMod[(int)modGroup] : m_auraBasePctMod[(int)modGroup]);
}
float GetTotalBaseModValue(BaseModGroup modGroup)
{
if (modGroup >= BaseModGroup.End)
{
Log.outError(LogFilter.Spells, $"Player.GetTotalBaseModValue: Invalid BaseModGroup ({modGroup}) for player '{GetName()}' ({GetGUID()})");
return 0.0f;
}
return m_auraBaseFlatMod[(int)modGroup] * m_auraBasePctMod[(int)modGroup];
}
public void AddComboPoints(sbyte count, Spell spell = null) public void AddComboPoints(sbyte count, Spell spell = null)
{ {
if (count == 0) if (count == 0)
@@ -6898,7 +6990,7 @@ namespace Game.Entities
if (WorldConfig.GetBoolValue(WorldCfg.InstantTaxi)) if (WorldConfig.GetBoolValue(WorldCfg.InstantTaxi))
{ {
var lastPathNode = CliDB.TaxiNodesStorage.LookupByKey(nodes[nodes.Count - 1]); var lastPathNode = CliDB.TaxiNodesStorage.LookupByKey(nodes[^1]);
m_taxi.ClearTaxiDestinations(); m_taxi.ClearTaxiDestinations();
ModifyMoney(-totalcost); ModifyMoney(-totalcost);
UpdateCriteria(CriteriaTypes.GoldSpentForTravelling, totalcost); UpdateCriteria(CriteriaTypes.GoldSpentForTravelling, totalcost);
@@ -6956,7 +7048,7 @@ namespace Game.Entities
var nodeList = CliDB.TaxiPathNodesByPath[path]; var nodeList = CliDB.TaxiPathNodesByPath[path];
float distPrev = MapConst.MapSize * MapConst.MapSize; float distPrev;
float distNext = GetExactDistSq(nodeList[0].Loc.X, nodeList[0].Loc.Y, nodeList[0].Loc.Z); float distNext = GetExactDistSq(nodeList[0].Loc.X, nodeList[0].Loc.Y, nodeList[0].Loc.Z);
for (int i = 1; i < nodeList.Length; ++i) for (int i = 1; i < nodeList.Length; ++i)
@@ -7277,7 +7369,7 @@ namespace Game.Entities
return null; return null;
} }
Item item = null; Item item;
if (useable) if (useable)
item = GetUseableItemByPos(InventorySlots.Bag0, slot); item = GetUseableItemByPos(InventorySlots.Bag0, slot);
else else
+188 -78
View File
@@ -27,35 +27,99 @@ namespace Game.Entities
{ {
public partial class Unit public partial class Unit
{ {
public bool HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, int amount, bool apply) public void HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply)
{ {
return HandleStatModifier(unitMod, modifierType, (float)amount, apply); if (unitMod >= UnitMods.End || modifierType >= UnitModifierFlatType.End)
}
public bool HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, float amount, bool apply)
{
if (unitMod >= UnitMods.End || modifierType >= UnitModifierType.End)
{ {
Log.outError(LogFilter.Unit, "ERROR in HandleStatModifier(): non-existing UnitMods or wrong UnitModifierType!"); Log.outError(LogFilter.Unit, "ERROR in HandleStatFlatModifier(): non-existing UnitMods or wrong UnitModifierFlatType!");
return false; return;
} }
if (amount == 0)
return;
switch (modifierType) switch (modifierType)
{ {
case UnitModifierType.BaseValue: case UnitModifierFlatType.Base:
case UnitModifierType.BasePCTExcludeCreate: case UnitModifierFlatType.BasePCTExcludeCreate:
case UnitModifierType.TotalValue: case UnitModifierFlatType.Total:
m_auraModifiersGroup[(int)unitMod][(int)modifierType] += apply ? amount : -amount; m_auraFlatModifiersGroup[(int)unitMod][(int)modifierType] += apply ? amount : -amount;
break;
case UnitModifierType.BasePCT:
case UnitModifierType.TotalPCT:
MathFunctions.ApplyPercentModFloatVar(ref m_auraModifiersGroup[(int)unitMod][(int)modifierType], amount, apply);
break; break;
default: default:
break; break;
} }
UpdateUnitMod(unitMod);
}
public void ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float pct)
{
if (unitMod >= UnitMods.End || modifierType >= UnitModifierPctType.End)
{
Log.outError(LogFilter.Unit, "ERROR in ApplyStatPctModifier(): non-existing UnitMods or wrong UnitModifierPctType!");
return;
}
if (pct == 0)
return;
switch (modifierType)
{
case UnitModifierPctType.Base:
case UnitModifierPctType.Total:
MathFunctions.AddPct(ref m_auraPctModifiersGroup[(int)unitMod][(int)modifierType], pct);
break;
default:
break;
}
UpdateUnitMod(unitMod);
}
public void SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val)
{
if (m_auraFlatModifiersGroup[(int)unitMod][(int)modifierType] == val)
return;
m_auraFlatModifiersGroup[(int)unitMod][(int)modifierType] = val;
UpdateUnitMod(unitMod);
}
public void SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val)
{
if (m_auraPctModifiersGroup[(int)unitMod][(int)modifierType] == val)
return;
m_auraPctModifiersGroup[(int)unitMod][(int)modifierType] = val;
UpdateUnitMod(unitMod);
}
public float GetFlatModifierValue(UnitMods unitMod, UnitModifierFlatType modifierType)
{
if (unitMod >= UnitMods.End || modifierType >= UnitModifierFlatType.End)
{
Log.outError(LogFilter.Unit, "attempt to access non-existing modifier value from UnitMods!");
return 0.0f;
}
return m_auraFlatModifiersGroup[(int)unitMod][(int)modifierType];
}
public float GetPctModifierValue(UnitMods unitMod, UnitModifierPctType modifierType)
{
if (unitMod >= UnitMods.End || modifierType >= UnitModifierPctType.End)
{
Log.outError(LogFilter.Unit, "attempt to access non-existing modifier value from UnitMods!");
return 0.0f;
}
return m_auraPctModifiersGroup[(int)unitMod][(int)modifierType];
}
void UpdateUnitMod(UnitMods unitMod)
{
if (!CanModifyStats()) if (!CanModifyStats())
return false; return;
switch (unitMod) switch (unitMod)
{ {
@@ -118,8 +182,6 @@ namespace Game.Entities
default: default:
break; break;
} }
return true;
} }
int GetMinPower(PowerType power) { return power == PowerType.LunarPower ? -100 : 0; } int GetMinPower(PowerType power) { return power == PowerType.LunarPower ? -100 : 0; }
@@ -181,16 +243,71 @@ namespace Game.Entities
return stat; return stat;
} }
public void ApplyStatBuffMod(Stats stat, float val, bool apply) public void UpdateStatBuffMod(Stats stat)
{ {
MathFunctions.ApplyPercentModFloatVar(ref (val > 0 ? ref m_floatStatPosBuff[(int)stat] : ref m_floatStatNegBuff[(int)stat]), val, apply); float modPos = 0.0f;
float modNeg = 0.0f;
float factor = 0.0f;
UnitMods unitMod = UnitMods.StatStart + (int)stat;
// includes value from items and enchantments
float modValue = GetFlatModifierValue(unitMod, UnitModifierFlatType.Base);
if (modValue > 0.0f)
modPos += modValue;
else
modNeg += modValue;
if (IsGuardian())
{
modValue = ((Guardian)this).GetBonusStatFromOwner(stat);
if (modValue > 0.0f)
modPos += modValue;
else
modNeg += modValue;
}
// SPELL_AURA_MOD_STAT_BONUS_PCT only affects BASE_VALUE
modPos = MathFunctions.CalculatePct(modPos, Math.Max(GetFlatModifierValue(unitMod, UnitModifierFlatType.BasePCTExcludeCreate), -100.0f));
modNeg = MathFunctions.CalculatePct(modPos, Math.Max(GetFlatModifierValue(unitMod, UnitModifierFlatType.BasePCTExcludeCreate), -100.0f));
modPos += GetTotalAuraModifier(AuraType.ModStat, aurEff =>
{
if ((aurEff.GetMiscValue() < 0 || aurEff.GetMiscValue() == (int)stat) && aurEff.GetAmount() > 0)
return true;
return false;
});
modNeg += GetTotalAuraModifier(AuraType.ModStat, aurEff =>
{
if ((aurEff.GetMiscValue() < 0 || aurEff.GetMiscValue() == (int)stat) && aurEff.GetAmount() < 0)
return true;
return false;
});
factor = GetTotalAuraMultiplier(AuraType.ModPercentStat, aurEff =>
{
if (aurEff.GetMiscValue() == -1 || aurEff.GetMiscValue() == (int)stat)
return true;
return false;
});
factor *= GetTotalAuraMultiplier(AuraType.ModTotalStatPercentage, aurEff =>
{
if (aurEff.GetMiscValue() == -1 || aurEff.GetMiscValue() == (int)stat)
return true;
return false;
});
modPos *= factor;
modNeg *= factor;
m_floatStatPosBuff[(int)stat] = modPos;
m_floatStatNegBuff[(int)stat] = modNeg;
UpdateStatBuffModForClient(stat); UpdateStatBuffModForClient(stat);
} }
public void ApplyStatPercentBuffMod(Stats stat, float val, bool apply)
{
MathFunctions.ApplyPercentModFloatVar(ref m_floatStatPosBuff[(int)stat], val, apply);
MathFunctions.ApplyPercentModFloatVar(ref m_floatStatNegBuff[(int)stat], val, apply);
}
void UpdateStatBuffModForClient(Stats stat) void UpdateStatBuffModForClient(Stats stat)
{ {
SetUpdateFieldValue(ref m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.StatPosBuff, (int)stat), (int)m_floatStatPosBuff[(int)stat]); SetUpdateFieldValue(ref m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.StatPosBuff, (int)stat), (int)m_floatStatPosBuff[(int)stat]);
@@ -204,7 +321,7 @@ namespace Game.Entities
if (school > SpellSchools.Normal) if (school > SpellSchools.Normal)
{ {
UnitMods unitMod = UnitMods.ResistanceStart + (int)school; UnitMods unitMod = UnitMods.ResistanceStart + (int)school;
SetResistance(school, (int)m_auraModifiersGroup[(int)unitMod][(int)UnitModifierType.BaseValue]); SetResistance(school, (int)GetFlatModifierValue(unitMod, UnitModifierFlatType.Base));
SetBonusResistanceMod(school, (int)(GetTotalAuraModValue(unitMod) - GetResistance(school))); SetBonusResistanceMod(school, (int)(GetTotalAuraModValue(unitMod) - GetResistance(school)));
} }
else else
@@ -216,10 +333,7 @@ namespace Game.Entities
public virtual void UpdateAttackPowerAndDamage(bool ranged = false) { } public virtual void UpdateAttackPowerAndDamage(bool ranged = false) { }
public virtual void UpdateDamagePhysical(WeaponAttackType attType) public virtual void UpdateDamagePhysical(WeaponAttackType attType)
{ {
float minDamage = 0.0f; CalculateMinMaxDamage(attType, false, true, out float minDamage, out float maxDamage);
float maxDamage = 0.0f;
CalculateMinMaxDamage(attType, false, true, out minDamage, out maxDamage);
switch (attType) switch (attType)
{ {
@@ -326,14 +440,11 @@ namespace Game.Entities
{ {
UnitMods unitMod = UnitMods.StatStart + (int)stat; UnitMods unitMod = UnitMods.StatStart + (int)stat;
if (m_auraModifiersGroup[(int)unitMod][(int)UnitModifierType.TotalPCT] <= 0.0f) float value = MathFunctions.CalculatePct(GetFlatModifierValue(unitMod, UnitModifierFlatType.Base), Math.Max(GetFlatModifierValue(unitMod, UnitModifierFlatType.BasePCTExcludeCreate), -100.0f));
return 0.0f;
float value = MathFunctions.CalculatePct(m_auraModifiersGroup[(int)unitMod][(int)UnitModifierType.BaseValue], Math.Max(m_auraModifiersGroup[(int)unitMod][(int)UnitModifierType.BasePCTExcludeCreate], -100.0f));
value += GetCreateStat(stat); value += GetCreateStat(stat);
value *= m_auraModifiersGroup[(int)unitMod][(int)UnitModifierType.BasePCT]; value *= GetPctModifierValue(unitMod, UnitModifierPctType.Base);
value += m_auraModifiersGroup[(int)unitMod][(int)UnitModifierType.TotalValue]; value += GetFlatModifierValue(unitMod, UnitModifierFlatType.Total);
value *= m_auraModifiersGroup[(int)unitMod][(int)UnitModifierType.TotalPCT]; value *= GetPctModifierValue(unitMod, UnitModifierPctType.Total);
return value; return value;
} }
@@ -940,6 +1051,7 @@ namespace Game.Entities
public void ApplyModDamageDonePos(SpellSchools school, int mod, bool apply) { ApplyModUpdateFieldValue(ref m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.ModDamageDonePos, (int)school), mod, apply); } public void ApplyModDamageDonePos(SpellSchools school, int mod, bool apply) { ApplyModUpdateFieldValue(ref m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.ModDamageDonePos, (int)school), mod, apply); }
public void ApplyModDamageDoneNeg(SpellSchools school, int mod, bool apply) { ApplyModUpdateFieldValue(ref m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.ModDamageDoneNeg, (int)school), mod, apply); } public void ApplyModDamageDoneNeg(SpellSchools school, int mod, bool apply) { ApplyModUpdateFieldValue(ref m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.ModDamageDoneNeg, (int)school), mod, apply); }
public void ApplyModDamageDonePercent(SpellSchools school, float pct, bool apply) { ApplyPercentModUpdateFieldValue(ref m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.ModDamageDonePercent, (int)school), pct, apply); } public void ApplyModDamageDonePercent(SpellSchools school, float pct, bool apply) { ApplyPercentModUpdateFieldValue(ref m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.ModDamageDonePercent, (int)school), pct, apply); }
public void SetModDamageDonePercent(SpellSchools school, float pct) { SetUpdateFieldValue(ref m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.ModDamageDonePercent, (int)school), pct); }
public void ApplyRatingMod(CombatRating combatRating, int value, bool apply) public void ApplyRatingMod(CombatRating combatRating, int value, bool apply)
{ {
@@ -968,10 +1080,10 @@ namespace Game.Entities
float attackPowerMod = Math.Max(GetAPMultiplier(attType, normalized), 0.25f); float attackPowerMod = Math.Max(GetAPMultiplier(attType, normalized), 0.25f);
float baseValue = GetModifierValue(unitMod, UnitModifierType.BaseValue) + GetTotalAttackPowerValue(attType) / 3.5f * attackPowerMod; float baseValue = GetFlatModifierValue(unitMod, UnitModifierFlatType.Base) + GetTotalAttackPowerValue(attType) / 3.5f * attackPowerMod;
float basePct = GetModifierValue(unitMod, UnitModifierType.BasePCT); float basePct = GetPctModifierValue(unitMod, UnitModifierPctType.Base);
float totalValue = GetModifierValue(unitMod, UnitModifierType.TotalValue); float totalValue = GetFlatModifierValue(unitMod, UnitModifierFlatType.Total);
float totalPct = addTotalPct ? GetModifierValue(unitMod, UnitModifierType.TotalPCT) : 1.0f; float totalPct = addTotalPct ? GetPctModifierValue(unitMod, UnitModifierPctType.Total) : 1.0f;
float weaponMinDamage = GetWeaponDamageRange(attType, WeaponDamageRange.MinDamage); float weaponMinDamage = GetWeaponDamageRange(attType, WeaponDamageRange.MinDamage);
float weaponMaxDamage = GetWeaponDamageRange(attType, WeaponDamageRange.MaxDamage); float weaponMaxDamage = GetWeaponDamageRange(attType, WeaponDamageRange.MaxDamage);
@@ -1007,9 +1119,9 @@ namespace Game.Entities
{ {
float value = 5.0f; float value = 5.0f;
SetBaseModValue(BaseModGroup.CritPercentage, BaseModType.PCTmod, value); SetBaseModPctValue(BaseModGroup.CritPercentage, value);
SetBaseModValue(BaseModGroup.OffhandCritPercentage, BaseModType.PCTmod, value); SetBaseModPctValue(BaseModGroup.OffhandCritPercentage, value);
SetBaseModValue(BaseModGroup.RangedCritPercentage, BaseModType.PCTmod, value); SetBaseModPctValue(BaseModGroup.RangedCritPercentage, value);
UpdateCritPercentage(WeaponAttackType.BaseAttack); UpdateCritPercentage(WeaponAttackType.BaseAttack);
UpdateCritPercentage(WeaponAttackType.OffAttack); UpdateCritPercentage(WeaponAttackType.OffAttack);
@@ -1101,11 +1213,11 @@ namespace Game.Entities
val2 = MathFunctions.CalculatePct(minSpellPower, m_activePlayerData.OverrideAPBySpellPowerPercent); val2 = MathFunctions.CalculatePct(minSpellPower, m_activePlayerData.OverrideAPBySpellPowerPercent);
} }
SetModifierValue(unitMod, UnitModifierType.BaseValue, val2); SetStatFlatModifier(unitMod, UnitModifierFlatType.Base, val2);
float base_attPower = GetModifierValue(unitMod, UnitModifierType.BaseValue) * GetModifierValue(unitMod, UnitModifierType.BasePCT); float base_attPower = GetFlatModifierValue(unitMod, UnitModifierFlatType.Base) * GetPctModifierValue(unitMod, UnitModifierPctType.Base);
float attPowerMod = GetModifierValue(unitMod, UnitModifierType.TotalValue); float attPowerMod = GetFlatModifierValue(unitMod, UnitModifierFlatType.Total);
float attPowerMultiplier = GetModifierValue(unitMod, UnitModifierType.TotalPCT) - 1.0f; float attPowerMultiplier = GetPctModifierValue(unitMod, UnitModifierPctType.Total) - 1.0f;
if (ranged) if (ranged)
{ {
@@ -1154,10 +1266,10 @@ namespace Game.Entities
{ {
UnitMods unitMod = UnitMods.Armor; UnitMods unitMod = UnitMods.Armor;
float value = GetModifierValue(unitMod, UnitModifierType.BaseValue); // base armor (from items) float value = GetFlatModifierValue(unitMod, UnitModifierFlatType.Base); // base armor (from items)
float baseValue = value; float baseValue = value;
value *= GetModifierValue(unitMod, UnitModifierType.BasePCT); // armor percent from items value *= GetPctModifierValue(unitMod, UnitModifierPctType.Base); // armor percent from items
value += GetModifierValue(unitMod, UnitModifierType.TotalValue); value += GetFlatModifierValue(unitMod, UnitModifierFlatType.Total);
//add dynamic flat mods //add dynamic flat mods
var mResbyIntellect = GetAuraEffectsByType(AuraType.ModResistanceOfStatPercent); var mResbyIntellect = GetAuraEffectsByType(AuraType.ModResistanceOfStatPercent);
@@ -1167,7 +1279,7 @@ namespace Game.Entities
value += MathFunctions.CalculatePct(GetStat((Stats)i.GetMiscValueB()), i.GetAmount()); value += MathFunctions.CalculatePct(GetStat((Stats)i.GetMiscValueB()), i.GetAmount());
} }
value *= GetModifierValue(unitMod, UnitModifierType.TotalPCT); value *= GetPctModifierValue(unitMod, UnitModifierPctType.Total);
SetArmor((int)baseValue, (int)(value - baseValue)); SetArmor((int)baseValue, (int)(value - baseValue));
@@ -1477,7 +1589,7 @@ namespace Game.Entities
public void UpdateCritPercentage(WeaponAttackType attType) public void UpdateCritPercentage(WeaponAttackType attType)
{ {
float applyCritLimit(float value) static float applyCritLimit(float value)
{ {
if (WorldConfig.GetBoolValue(WorldCfg.StatsLimitsEnable)) if (WorldConfig.GetBoolValue(WorldCfg.StatsLimitsEnable))
value = value > WorldConfig.GetFloatValue(WorldCfg.StatsLimitsCrit) ? WorldConfig.GetFloatValue(WorldCfg.StatsLimitsCrit) : value; value = value > WorldConfig.GetFloatValue(WorldCfg.StatsLimitsCrit) ? WorldConfig.GetFloatValue(WorldCfg.StatsLimitsCrit) : value;
@@ -1488,16 +1600,16 @@ namespace Game.Entities
{ {
case WeaponAttackType.OffAttack: case WeaponAttackType.OffAttack:
SetUpdateFieldStatValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.OffhandCritPercentage), SetUpdateFieldStatValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.OffhandCritPercentage),
applyCritLimit(GetTotalPercentageModValue(BaseModGroup.OffhandCritPercentage) + GetRatingBonusValue(CombatRating.CritMelee))); applyCritLimit(GetBaseModValue(BaseModGroup.OffhandCritPercentage, BaseModType.FlatMod) + GetBaseModValue(BaseModGroup.OffhandCritPercentage, BaseModType.PctMod) + GetRatingBonusValue(CombatRating.CritMelee)));
break; break;
case WeaponAttackType.RangedAttack: case WeaponAttackType.RangedAttack:
SetUpdateFieldStatValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.RangedCritPercentage), SetUpdateFieldStatValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.RangedCritPercentage),
applyCritLimit(GetTotalPercentageModValue(BaseModGroup.RangedCritPercentage) + GetRatingBonusValue(CombatRating.CritRanged))); applyCritLimit(GetBaseModValue(BaseModGroup.RangedCritPercentage, BaseModType.FlatMod) + GetBaseModValue(BaseModGroup.RangedCritPercentage, BaseModType.PctMod) + GetRatingBonusValue(CombatRating.CritRanged)));
break; break;
case WeaponAttackType.BaseAttack: case WeaponAttackType.BaseAttack:
default: default:
SetUpdateFieldStatValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.CritPercentage), SetUpdateFieldStatValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.CritPercentage),
applyCritLimit(GetTotalPercentageModValue(BaseModGroup.CritPercentage) + GetRatingBonusValue(CombatRating.CritMelee))); applyCritLimit(GetBaseModValue(BaseModGroup.CritPercentage, BaseModType.FlatMod) + GetBaseModValue(BaseModGroup.CritPercentage, BaseModType.PctMod) + GetRatingBonusValue(CombatRating.CritMelee)));
break; break;
} }
} }
@@ -1638,10 +1750,10 @@ namespace Game.Entities
{ {
UnitMods unitMod = UnitMods.Health; UnitMods unitMod = UnitMods.Health;
float value = GetModifierValue(unitMod, UnitModifierType.BaseValue) + GetCreateHealth(); float value = GetFlatModifierValue(unitMod, UnitModifierFlatType.Base) + GetCreateHealth();
value *= GetModifierValue(unitMod, UnitModifierType.BasePCT); value *= GetPctModifierValue(unitMod, UnitModifierPctType.Base);
value += GetModifierValue(unitMod, UnitModifierType.TotalValue) + GetHealthBonusFromStamina(); value += GetFlatModifierValue(unitMod, UnitModifierFlatType.Total) + GetHealthBonusFromStamina();
value *= GetModifierValue(unitMod, UnitModifierType.TotalPCT); value *= GetPctModifierValue(unitMod, UnitModifierPctType.Total);
SetMaxHealth((uint)value); SetMaxHealth((uint)value);
} }
@@ -1669,10 +1781,10 @@ namespace Game.Entities
UnitMods unitMod = UnitMods.PowerStart + (int)power; UnitMods unitMod = UnitMods.PowerStart + (int)power;
float value = GetModifierValue(unitMod, UnitModifierType.BaseValue) + GetCreatePowers(power); float value = GetFlatModifierValue(unitMod, UnitModifierFlatType.Base) + GetCreatePowers(power);
value *= GetModifierValue(unitMod, UnitModifierType.BasePCT); value *= GetPctModifierValue(unitMod, UnitModifierPctType.Base);
value += GetModifierValue(unitMod, UnitModifierType.TotalValue); value += GetFlatModifierValue(unitMod, UnitModifierFlatType.Total);
value *= GetModifierValue(unitMod, UnitModifierType.TotalPCT); value *= GetPctModifierValue(unitMod, UnitModifierPctType.Total);
SetMaxPower(power, (int)Math.Round(value)); SetMaxPower(power, (int)Math.Round(value));
} }
@@ -1748,8 +1860,6 @@ namespace Game.Entities
0.9720f, // Druid 0.9720f, // Druid
0.9830f // Demon Hunter 0.9830f // Demon Hunter
}; };
void SetBaseModValue(BaseModGroup modGroup, BaseModType modType, float value) { m_auraBaseMod[(int)modGroup][(int)modType] = value; }
} }
public partial class Creature public partial class Creature
@@ -1775,7 +1885,7 @@ namespace Game.Entities
public override void UpdateArmor() public override void UpdateArmor()
{ {
float baseValue = GetModifierValue(UnitMods.Armor, UnitModifierType.BaseValue); float baseValue = GetFlatModifierValue(UnitMods.Armor, UnitModifierFlatType.Base);
float value = GetTotalAuraModValue(UnitMods.Armor); float value = GetTotalAuraModValue(UnitMods.Armor);
SetArmor((int)baseValue, (int)(value - baseValue)); SetArmor((int)baseValue, (int)(value - baseValue));
} }
@@ -1805,10 +1915,10 @@ namespace Game.Entities
UnitMods unitMod = UnitMods.PowerStart + (int)power; UnitMods unitMod = UnitMods.PowerStart + (int)power;
float value = GetModifierValue(unitMod, UnitModifierType.BaseValue) + GetCreatePowers(power); float value = GetFlatModifierValue(unitMod, UnitModifierFlatType.Base) + GetCreatePowers(power);
value *= GetModifierValue(unitMod, UnitModifierType.BasePCT); value *= GetPctModifierValue(unitMod, UnitModifierPctType.Base);
value += GetModifierValue(unitMod, UnitModifierType.TotalValue); value += GetFlatModifierValue(unitMod, UnitModifierFlatType.Total);
value *= GetModifierValue(unitMod, UnitModifierType.TotalPCT); value *= GetPctModifierValue(unitMod, UnitModifierPctType.Total);
SetMaxPower(power, (int)Math.Round(value)); SetMaxPower(power, (int)Math.Round(value));
} }
@@ -1817,8 +1927,8 @@ namespace Game.Entities
{ {
UnitMods unitMod = ranged ? UnitMods.AttackPowerRanged : UnitMods.AttackPower; UnitMods unitMod = ranged ? UnitMods.AttackPowerRanged : UnitMods.AttackPower;
float baseAttackPower = GetModifierValue(unitMod, UnitModifierType.BaseValue) * GetModifierValue(unitMod, UnitModifierType.BasePCT); float baseAttackPower = GetFlatModifierValue(unitMod, UnitModifierFlatType.Base) * GetPctModifierValue(unitMod, UnitModifierPctType.Base);
float attackPowerMultiplier = GetModifierValue(unitMod, UnitModifierType.TotalPCT) - 1.0f; float attackPowerMultiplier = GetPctModifierValue(unitMod, UnitModifierPctType.Total) - 1.0f;
if (ranged) if (ranged)
{ {
@@ -1881,10 +1991,10 @@ namespace Game.Entities
float attackPower = GetTotalAttackPowerValue(attType); float attackPower = GetTotalAttackPowerValue(attType);
float attackSpeedMulti = Math.Max(GetAPMultiplier(attType, normalized), 0.25f); float attackSpeedMulti = Math.Max(GetAPMultiplier(attType, normalized), 0.25f);
float baseValue = GetModifierValue(unitMod, UnitModifierType.BaseValue) + (attackPower / 3.5f) * variance; float baseValue = GetFlatModifierValue(unitMod, UnitModifierFlatType.Base) + (attackPower / 3.5f) * variance;
float basePct = GetModifierValue(unitMod, UnitModifierType.BasePCT) * attackSpeedMulti; float basePct = GetPctModifierValue(unitMod, UnitModifierPctType.Base) * attackSpeedMulti;
float totalValue = GetModifierValue(unitMod, UnitModifierType.TotalValue); float totalValue = GetFlatModifierValue(unitMod, UnitModifierFlatType.Total);
float totalPct = addTotalPct ? GetModifierValue(unitMod, UnitModifierType.TotalPCT) : 1.0f; float totalPct = addTotalPct ? GetPctModifierValue(unitMod, UnitModifierPctType.Total) : 1.0f;
float dmgMultiplier = GetCreatureTemplate().ModDamage; // = ModDamage * _GetDamageMod(rank); float dmgMultiplier = GetCreatureTemplate().ModDamage; // = ModDamage * _GetDamageMod(rank);
minDamage = ((weaponMinDamage + baseValue) * dmgMultiplier * basePct + totalValue) * totalPct; minDamage = ((weaponMinDamage + baseValue) * dmgMultiplier * basePct + totalValue) * totalPct;
+29 -31
View File
@@ -441,7 +441,7 @@ namespace Game.Entities
SetMeleeDamageSchool((SpellSchools)cinfo.DmgSchool); SetMeleeDamageSchool((SpellSchools)cinfo.DmgSchool);
SetModifierValue(UnitMods.Armor, UnitModifierType.BaseValue, (float)petlevel * 50); SetStatFlatModifier(UnitMods.Armor, UnitModifierFlatType.Base, (float)petlevel * 50);
SetBaseAttackTime(WeaponAttackType.BaseAttack, SharedConst.BaseAttackTime); SetBaseAttackTime(WeaponAttackType.BaseAttack, SharedConst.BaseAttackTime);
SetBaseAttackTime(WeaponAttackType.OffAttack, SharedConst.BaseAttackTime); SetBaseAttackTime(WeaponAttackType.OffAttack, SharedConst.BaseAttackTime);
@@ -467,7 +467,7 @@ namespace Game.Entities
if (!IsHunterPet()) if (!IsHunterPet())
{ {
for (int i = (int)SpellSchools.Holy; i < (int)SpellSchools.Max; ++i) for (int i = (int)SpellSchools.Holy; i < (int)SpellSchools.Max; ++i)
SetModifierValue(UnitMods.ResistanceStart + i, UnitModifierType.BaseValue, cinfo.Resistance[i]); SetStatFlatModifier(UnitMods.ResistanceStart + i, UnitModifierFlatType.Base, cinfo.Resistance[i]);
} }
// Health, Mana or Power, Armor // Health, Mana or Power, Armor
@@ -478,7 +478,7 @@ namespace Game.Entities
SetCreateMana(pInfo.mana); SetCreateMana(pInfo.mana);
if (pInfo.armor > 0) if (pInfo.armor > 0)
SetModifierValue(UnitMods.Armor, UnitModifierType.BaseValue, pInfo.armor); SetStatFlatModifier(UnitMods.Armor, UnitModifierFlatType.Base, pInfo.armor);
for (byte stat = 0; stat < (int)Stats.Max; ++stat) for (byte stat = 0; stat < (int)Stats.Max; ++stat)
SetCreateStat((Stats)stat, pInfo.stats[stat]); SetCreateStat((Stats)stat, pInfo.stats[stat]);
@@ -584,7 +584,6 @@ namespace Game.Entities
int bonus_dmg = (int)(GetOwner().SpellBaseDamageBonusDone(SpellSchoolMask.Shadow) * 0.3f); int bonus_dmg = (int)(GetOwner().SpellBaseDamageBonusDone(SpellSchoolMask.Shadow) * 0.3f);
SetBaseWeaponDamage(WeaponAttackType.BaseAttack, WeaponDamageRange.MinDamage, (petlevel * 4 - petlevel) + bonus_dmg); SetBaseWeaponDamage(WeaponAttackType.BaseAttack, WeaponDamageRange.MinDamage, (petlevel * 4 - petlevel) + bonus_dmg);
SetBaseWeaponDamage(WeaponAttackType.BaseAttack, WeaponDamageRange.MaxDamage, (petlevel * 4 + petlevel) + bonus_dmg); SetBaseWeaponDamage(WeaponAttackType.BaseAttack, WeaponDamageRange.MaxDamage, (petlevel * 4 + petlevel) + bonus_dmg);
break; break;
} }
case 19833: //Snake Trap - Venomous Snake case 19833: //Snake Trap - Venomous Snake
@@ -610,8 +609,8 @@ namespace Game.Entities
SetBaseWeaponDamage(WeaponAttackType.BaseAttack, WeaponDamageRange.MinDamage, (petlevel * 4 - petlevel)); SetBaseWeaponDamage(WeaponAttackType.BaseAttack, WeaponDamageRange.MinDamage, (petlevel * 4 - petlevel));
SetBaseWeaponDamage(WeaponAttackType.BaseAttack, WeaponDamageRange.MaxDamage, (petlevel * 4 + petlevel)); SetBaseWeaponDamage(WeaponAttackType.BaseAttack, WeaponDamageRange.MaxDamage, (petlevel * 4 + petlevel));
SetModifierValue(UnitMods.Armor, UnitModifierType.BaseValue, GetOwner().GetArmor() * 0.35f); // Bonus Armor (35% of player armor) SetStatFlatModifier(UnitMods.Armor, UnitModifierFlatType.Base, GetOwner().GetArmor() * 0.35f); // Bonus Armor (35% of player armor)
SetModifierValue(UnitMods.StatStamina, UnitModifierType.BaseValue, GetOwner().GetStat(Stats.Stamina) * 0.3f); // Bonus Stamina (30% of player stamina) SetStatFlatModifier(UnitMods.StatStamina, UnitModifierFlatType.Base, GetOwner().GetStat(Stats.Stamina) * 0.3f); // Bonus Stamina (30% of player stamina)
if (!HasAura(58877))//prevent apply twice for the 2 wolves if (!HasAura(58877))//prevent apply twice for the 2 wolves
AddAura(58877, this);//Spirit Hunt, passive, Spirit Wolves' attacks heal them and their master for 150% of damage done. AddAura(58877, this);//Spirit Hunt, passive, Spirit Wolves' attacks heal them and their master for 150% of damage done.
break; break;
@@ -673,7 +672,7 @@ namespace Game.Entities
public override bool UpdateStats(Stats stat) public override bool UpdateStats(Stats stat)
{ {
float value = GetTotalStatValue(stat); float value = GetTotalStatValue(stat);
ApplyStatBuffMod(stat, m_statFromOwner[(int)stat], false); UpdateStatBuffMod(stat);
float ownersBonus = 0.0f; float ownersBonus = 0.0f;
Unit owner = GetOwner(); Unit owner = GetOwner();
@@ -712,7 +711,7 @@ namespace Game.Entities
SetStat(stat, (int)value); SetStat(stat, (int)value);
m_statFromOwner[(int)stat] = ownersBonus; m_statFromOwner[(int)stat] = ownersBonus;
ApplyStatBuffMod(stat, m_statFromOwner[(int)stat], true); UpdateStatBuffMod(stat);
switch (stat) switch (stat)
{ {
@@ -754,7 +753,7 @@ namespace Game.Entities
{ {
if (school > SpellSchools.Normal) if (school > SpellSchools.Normal)
{ {
float baseValue = GetModifierValue( UnitMods.ResistanceStart + (int)school, UnitModifierType.BaseValue); float baseValue = GetFlatModifierValue(UnitMods.ResistanceStart + (int)school, UnitModifierFlatType.Base);
float bonusValue = GetTotalAuraModValue(UnitMods.ResistanceStart + (int)school) - baseValue; float bonusValue = GetTotalAuraModValue(UnitMods.ResistanceStart + (int)school) - baseValue;
// hunter and warlock pets gain 40% of owner's resistance // hunter and warlock pets gain 40% of owner's resistance
@@ -773,8 +772,6 @@ namespace Game.Entities
public override void UpdateArmor() public override void UpdateArmor()
{ {
float baseValue = 0.0f;
float value = 0.0f;
float bonus_armor = 0.0f; float bonus_armor = 0.0f;
UnitMods unitMod = UnitMods.Armor; UnitMods unitMod = UnitMods.Armor;
@@ -784,11 +781,11 @@ namespace Game.Entities
else if (IsPet()) else if (IsPet())
bonus_armor = GetOwner().GetArmor(); bonus_armor = GetOwner().GetArmor();
value = GetModifierValue(unitMod, UnitModifierType.BaseValue); float value = GetFlatModifierValue(unitMod, UnitModifierFlatType.Base);
baseValue = value; float baseValue = value;
value *= GetModifierValue(unitMod, UnitModifierType.BasePCT); value *= GetPctModifierValue(unitMod, UnitModifierPctType.Base);
value += GetModifierValue(unitMod, UnitModifierType.TotalValue) + bonus_armor; value += GetFlatModifierValue(unitMod, UnitModifierFlatType.Total) + bonus_armor;
value *= GetModifierValue(unitMod, UnitModifierType.TotalPCT); value *= GetPctModifierValue(unitMod, UnitModifierPctType.Total);
SetArmor((int)baseValue, (int)(value - baseValue)); SetArmor((int)baseValue, (int)(value - baseValue));
} }
@@ -824,10 +821,10 @@ namespace Game.Entities
break; break;
} }
float value = GetModifierValue(unitMod, UnitModifierType.BaseValue) + GetCreateHealth(); float value = GetFlatModifierValue(unitMod, UnitModifierFlatType.Base) + GetCreateHealth();
value *= GetModifierValue(unitMod, UnitModifierType.BasePCT); value *= GetPctModifierValue(unitMod, UnitModifierPctType.Base);
value += GetModifierValue(unitMod, UnitModifierType.TotalValue) + stamina * multiplicator; value += GetFlatModifierValue(unitMod, UnitModifierFlatType.Total) + stamina * multiplicator;
value *= GetModifierValue(unitMod, UnitModifierType.TotalPCT); value *= GetPctModifierValue(unitMod, UnitModifierPctType.Total);
SetMaxHealth((uint)value); SetMaxHealth((uint)value);
} }
@@ -839,10 +836,10 @@ namespace Game.Entities
UnitMods unitMod = UnitMods.PowerStart + (int)power; UnitMods unitMod = UnitMods.PowerStart + (int)power;
float value = GetModifierValue(unitMod, UnitModifierType.BaseValue) + GetCreatePowers(power); float value = GetFlatModifierValue(unitMod, UnitModifierFlatType.Base) + GetCreatePowers(power);
value *= GetModifierValue(unitMod, UnitModifierType.BasePCT); value *= GetPctModifierValue(unitMod, UnitModifierPctType.Base);
value += GetModifierValue(unitMod, UnitModifierType.TotalValue); value += GetFlatModifierValue(unitMod, UnitModifierFlatType.Total);
value *= GetModifierValue(unitMod, UnitModifierType.TotalPCT); value *= GetPctModifierValue(unitMod, UnitModifierPctType.Total);
SetMaxPower(power, (int)value); SetMaxPower(power, (int)value);
} }
@@ -902,11 +899,11 @@ namespace Game.Entities
} }
} }
SetModifierValue(UnitMods.AttackPower, UnitModifierType.BaseValue, val + bonusAP); SetStatFlatModifier(UnitMods.AttackPower, UnitModifierFlatType.Base, val + bonusAP);
//in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB //in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB
float base_attPower = GetModifierValue(unitMod, UnitModifierType.BaseValue) * GetModifierValue(unitMod, UnitModifierType.BasePCT); float base_attPower = GetFlatModifierValue(unitMod, UnitModifierFlatType.Base) * GetPctModifierValue(unitMod, UnitModifierPctType.Base);
float attPowerMultiplier = GetModifierValue(unitMod, UnitModifierType.TotalPCT) - 1.0f; float attPowerMultiplier = GetPctModifierValue(unitMod, UnitModifierPctType.Total) - 1.0f;
SetAttackPower((int)base_attPower); SetAttackPower((int)base_attPower);
SetAttackPowerMultiplier(attPowerMultiplier); SetAttackPowerMultiplier(attPowerMultiplier);
@@ -944,10 +941,10 @@ namespace Game.Entities
float att_speed = GetBaseAttackTime(WeaponAttackType.BaseAttack) / 1000.0f; float att_speed = GetBaseAttackTime(WeaponAttackType.BaseAttack) / 1000.0f;
float base_value = GetModifierValue(unitMod, UnitModifierType.BaseValue) + GetTotalAttackPowerValue(attType) / 3.5f * att_speed + bonusDamage; float base_value = GetFlatModifierValue(unitMod, UnitModifierFlatType.Base) + GetTotalAttackPowerValue(attType) / 3.5f * att_speed + bonusDamage;
float base_pct = GetModifierValue(unitMod, UnitModifierType.BasePCT); float base_pct = GetPctModifierValue(unitMod, UnitModifierPctType.Base);
float total_value = GetModifierValue(unitMod, UnitModifierType.TotalValue); float total_value = GetFlatModifierValue(unitMod, UnitModifierFlatType.Total);
float total_pct = GetModifierValue(unitMod, UnitModifierType.TotalPCT); float total_pct = GetPctModifierValue(unitMod, UnitModifierPctType.Total);
float weapon_mindamage = GetWeaponDamageRange(WeaponAttackType.BaseAttack, WeaponDamageRange.MinDamage); float weapon_mindamage = GetWeaponDamageRange(WeaponAttackType.BaseAttack, WeaponDamageRange.MinDamage);
float weapon_maxdamage = GetWeaponDamageRange(WeaponAttackType.BaseAttack, WeaponDamageRange.MaxDamage); float weapon_maxdamage = GetWeaponDamageRange(WeaponAttackType.BaseAttack, WeaponDamageRange.MaxDamage);
@@ -968,6 +965,7 @@ namespace Game.Entities
} }
public int GetBonusDamage() { return m_bonusSpellDamage; } public int GetBonusDamage() { return m_bonusSpellDamage; }
public float GetBonusStatFromOwner(Stats stat) { return m_statFromOwner[(int)stat]; }
int m_bonusSpellDamage; int m_bonusSpellDamage;
float[] m_statFromOwner = new float[(int)Stats.Max]; float[] m_statFromOwner = new float[(int)Stats.Max];
+67 -23
View File
@@ -1351,7 +1351,7 @@ namespace Game.Entities
return; return;
if (PvP) if (PvP)
{ {
combatTimer = 5000; combatTimer = 5000;
Player me = ToPlayer(); Player me = ToPlayer();
if (me) if (me)
@@ -2146,17 +2146,16 @@ namespace Game.Entities
return MeleeHitOutcome.Normal; return MeleeHitOutcome.Normal;
} }
public uint CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct) public uint CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct)
{ {
float minDamage, maxDamage = 0.0f; float minDamage;
float maxDamage;
if (normalized || !addTotalPct) if (normalized || !addTotalPct)
{ {
CalculateMinMaxDamage(attType, normalized, addTotalPct, out minDamage, out maxDamage); CalculateMinMaxDamage(attType, normalized, addTotalPct, out minDamage, out maxDamage);
if (IsInFeralForm() && attType == WeaponAttackType.BaseAttack) if (IsInFeralForm() && attType == WeaponAttackType.BaseAttack)
{ {
float minOffhandDamage = 0.0f; CalculateMinMaxDamage(WeaponAttackType.OffAttack, normalized, addTotalPct, out float minOffhandDamage, out float maxOffhandDamage);
float maxOffhandDamage = 0.0f;
CalculateMinMaxDamage(WeaponAttackType.OffAttack, normalized, addTotalPct, out minOffhandDamage, out maxOffhandDamage);
minDamage += minOffhandDamage; minDamage += minOffhandDamage;
maxDamage += maxOffhandDamage; maxDamage += maxOffhandDamage;
} }
@@ -2266,19 +2265,6 @@ namespace Game.Entities
return ap * (1.0f + m_unitData.AttackPowerMultiplier); return ap * (1.0f + m_unitData.AttackPowerMultiplier);
} }
} }
public float GetModifierValue(UnitMods unitMod, UnitModifierType modifierType)
{
if (unitMod >= UnitMods.End || modifierType >= UnitModifierType.End)
{
Log.outError(LogFilter.Unit, "attempt to access non-existing modifier value from UnitMods!");
return 0.0f;
}
if (modifierType == UnitModifierType.TotalPCT && m_auraModifiersGroup[(int)unitMod][(int)modifierType] <= 0.0f)
return 0.0f;
return m_auraModifiersGroup[(int)unitMod][(int)modifierType];
}
public bool IsWithinMeleeRange(Unit obj) public bool IsWithinMeleeRange(Unit obj)
{ {
if (!obj || !IsInMap(obj) || !IsInPhase(obj)) if (!obj || !IsInMap(obj) || !IsInPhase(obj))
@@ -2449,7 +2435,7 @@ namespace Game.Entities
uint bossLevel = 83; uint bossLevel = 83;
float bossResistanceConstant = 510.0f; float bossResistanceConstant = 510.0f;
uint level = victim.GetLevelForTarget(this); uint level = victim.GetLevelForTarget(this);
float resistanceConstant = 0.0f; float resistanceConstant;
if (level == bossLevel) if (level == bossLevel)
resistanceConstant = bossResistanceConstant; resistanceConstant = bossResistanceConstant;
@@ -2492,7 +2478,7 @@ namespace Game.Entities
vSchoolAbsorbCopy.Sort(new AbsorbAuraOrderPred()); vSchoolAbsorbCopy.Sort(new AbsorbAuraOrderPred());
// absorb without mana cost // absorb without mana cost
for (var i = 0; i < vSchoolAbsorbCopy.Count; ++i ) for (var i = 0; i < vSchoolAbsorbCopy.Count; ++i)
{ {
var absorbAurEff = vSchoolAbsorbCopy[i]; var absorbAurEff = vSchoolAbsorbCopy[i];
if (damageInfo.GetDamage() == 0) if (damageInfo.GetDamage() == 0)
@@ -2758,7 +2744,7 @@ namespace Game.Entities
// no more than 100% // no more than 100%
MathFunctions.RoundToInterval(ref arpPct, 0.0f, 100.0f); MathFunctions.RoundToInterval(ref arpPct, 0.0f, 100.0f);
float maxArmorPen = 0.0f; float maxArmorPen;
if (victim.GetLevelForTarget(attacker) < 60) if (victim.GetLevelForTarget(attacker) < 60)
maxArmorPen = 400 + 85 * victim.GetLevelForTarget(attacker); maxArmorPen = 400 + 85 * victim.GetLevelForTarget(attacker);
else else
@@ -3014,10 +3000,15 @@ namespace Game.Entities
return (CastingTime / 3500.0f) * DotFactor; return (CastingTime / 3500.0f) * DotFactor;
} }
void ApplyPercentModFloatVar(ref float var, float val, bool apply)
{
var *= (apply ? (100.0f + val) / 100.0f : 100.0f / (100.0f + val));
}
public void ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply) public void ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply)
{ {
float remainingTimePct = m_attackTimer[(int)att] / (m_baseAttackSpeed[(int)att] * m_modAttackSpeedPct[(int)att]); float remainingTimePct = m_attackTimer[(int)att] / (m_baseAttackSpeed[(int)att] * m_modAttackSpeedPct[(int)att]);
if (val > 0) if (val > 0.0f)
{ {
MathFunctions.ApplyPercentModFloatVar(ref m_modAttackSpeedPct[(int)att], val, !apply); MathFunctions.ApplyPercentModFloatVar(ref m_modAttackSpeedPct[(int)att], val, !apply);
@@ -3265,5 +3256,58 @@ namespace Game.Entities
} }
return true; return true;
} }
public virtual bool CheckAttackFitToAuraRequirement(WeaponAttackType attackType, AuraEffect aurEff) { return true; }
public virtual void UpdateDamageDoneMods(WeaponAttackType attackType)
{
UnitMods unitMod = attackType switch
{
WeaponAttackType.BaseAttack => UnitMods.DamageMainHand,
WeaponAttackType.OffAttack => UnitMods.DamageOffHand,
WeaponAttackType.RangedAttack => UnitMods.DamageRanged,
_ => throw new NotImplementedException(),
};
float amount = GetTotalAuraModifier(AuraType.ModDamageDone, auratype => CheckAttackFitToAuraRequirement(attackType, auratype));
SetStatFlatModifier(unitMod, UnitModifierFlatType.Total, amount);
}
public void UpdateAllDamageDoneMods()
{
for (var attackType = WeaponAttackType.BaseAttack; attackType < WeaponAttackType.Max; ++attackType)
UpdateDamageDoneMods(attackType);
}
public void UpdateDamagePctDoneMods(WeaponAttackType attackType)
{
(UnitMods unitMod, float factor) = attackType switch
{
WeaponAttackType.BaseAttack => (UnitMods.DamageMainHand, 1.0f),
WeaponAttackType.OffAttack => (UnitMods.DamageOffHand, 0.5f),
WeaponAttackType.RangedAttack => (UnitMods.DamageRanged, 1.0f),
_ => throw new NotImplementedException(),
};
factor *= GetTotalAuraMultiplier(AuraType.ModDamagePercentDone, aurEff =>
{
if (!aurEff.GetMiscValue().HasAnyFlag((int)SpellSchoolMask.Normal))
return false;
return CheckAttackFitToAuraRequirement(attackType, aurEff);
});
if (attackType == WeaponAttackType.OffAttack)
factor *= GetTotalAuraMultiplier(AuraType.ModOffhandDamagePct, auraEffect => CheckAttackFitToAuraRequirement(attackType, auraEffect));
SetStatPctModifier(unitMod, UnitModifierPctType.Total, factor);
}
public void UpdateAllDamagePctDoneMods()
{
for (var attackType = WeaponAttackType.BaseAttack; attackType < WeaponAttackType.Max; ++attackType)
UpdateDamagePctDoneMods(attackType);
}
} }
} }
+2 -1
View File
@@ -103,7 +103,8 @@ namespace Game.Entities
MultiMap<uint, AuraApplication> m_appliedAuras = new MultiMap<uint, AuraApplication>(); MultiMap<uint, AuraApplication> m_appliedAuras = new MultiMap<uint, AuraApplication>();
MultiMap<uint, Aura> m_ownedAuras = new MultiMap<uint, Aura>(); MultiMap<uint, Aura> m_ownedAuras = new MultiMap<uint, Aura>();
List<Aura> m_scAuras = new List<Aura>(); List<Aura> m_scAuras = new List<Aura>();
protected float[][] m_auraModifiersGroup = new float[(int)UnitMods.End][]; protected float[][] m_auraFlatModifiersGroup = new float[(int)UnitMods.End][];
protected float[][] m_auraPctModifiersGroup = new float[(int)UnitMods.End][];
uint m_removedAurasCount; uint m_removedAurasCount;
//General //General
+6 -9
View File
@@ -951,7 +951,7 @@ namespace Game.Entities
int levelBasedHitDiff = leveldif; int levelBasedHitDiff = leveldif;
// Base hit chance from attacker and victim levels // Base hit chance from attacker and victim levels
int modHitChance = 100; int modHitChance;
if (levelBasedHitDiff >= 0) if (levelBasedHitDiff >= 0)
{ {
if (!victim.IsTypeId(TypeId.Player)) if (!victim.IsTypeId(TypeId.Player))
@@ -2294,7 +2294,7 @@ namespace Game.Entities
public void ApplyCastTimePercentMod(float val, bool apply) public void ApplyCastTimePercentMod(float val, bool apply)
{ {
if (val > 0) if (val > 0.0f)
{ {
ApplyPercentModUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.ModCastingSpeed), val, !apply); ApplyPercentModUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.ModCastingSpeed), val, !apply);
ApplyPercentModUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.ModSpellHaste), val, !apply); ApplyPercentModUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.ModSpellHaste), val, !apply);
@@ -4547,13 +4547,10 @@ namespace Game.Entities
return 0.0f; return 0.0f;
} }
if (m_auraModifiersGroup[(int)unitMod][(int)UnitModifierType.TotalPCT] <= 0.0f) float value = MathFunctions.CalculatePct(GetFlatModifierValue(unitMod, UnitModifierFlatType.Base), Math.Max(GetFlatModifierValue(unitMod, UnitModifierFlatType.BasePCTExcludeCreate), -100.0f));
return 0.0f; value *= GetPctModifierValue(unitMod, UnitModifierPctType.Base);
value += GetFlatModifierValue(unitMod, UnitModifierFlatType.Total);
float value = MathFunctions.CalculatePct(m_auraModifiersGroup[(int)unitMod][(int)UnitModifierType.BaseValue], Math.Max(m_auraModifiersGroup[(int)unitMod][(int)UnitModifierType.BasePCTExcludeCreate], -100.0f)); value *= GetPctModifierValue(unitMod, UnitModifierPctType.Total);
value *= m_auraModifiersGroup[(int)unitMod][(int)UnitModifierType.BasePCT];
value += m_auraModifiersGroup[(int)unitMod][(int)UnitModifierType.TotalValue];
value *= m_auraModifiersGroup[(int)unitMod][(int)UnitModifierType.TotalPCT];
return value; return value;
} }
+20 -19
View File
@@ -57,9 +57,18 @@ namespace Game.Entities
m_spellImmune[i] = new MultiMap<uint, uint>(); m_spellImmune[i] = new MultiMap<uint, uint>();
for (byte i = 0; i < (int)UnitMods.End; ++i) for (byte i = 0; i < (int)UnitMods.End; ++i)
m_auraModifiersGroup[i] = new float[] { 0.0f, 100.0f, 1.0f, 0.0f, 1.0f }; {
m_auraFlatModifiersGroup[i] = new float[(int)UnitModifierFlatType.End];
m_auraFlatModifiersGroup[i][(int)UnitModifierFlatType.Base] = 0.0f;
m_auraFlatModifiersGroup[i][(int)UnitModifierFlatType.BasePCTExcludeCreate] = 100.0f;
m_auraFlatModifiersGroup[i][(int)UnitModifierFlatType.Total] = 0.0f;
m_auraModifiersGroup[(int)UnitMods.DamageOffHand][(int)UnitModifierType.TotalPCT] = 0.5f; m_auraPctModifiersGroup[i] = new float[(int)UnitModifierPctType.End];
m_auraPctModifiersGroup[i][(int)UnitModifierPctType.Base] = 1.0f;
m_auraPctModifiersGroup[i][(int)UnitModifierPctType.Total] = 1.0f;
}
m_auraPctModifiersGroup[(int)UnitMods.DamageOffHand][(int)UnitModifierPctType.Total] = 0.5f;
foreach (AuraType auraType in Enum.GetValues(typeof(AuraType))) foreach (AuraType auraType in Enum.GetValues(typeof(AuraType)))
m_modAuras[auraType] = new List<AuraEffect>(); m_modAuras[auraType] = new List<AuraEffect>();
@@ -1239,7 +1248,7 @@ namespace Game.Entities
else if (GetRace() == Race.Worgen) else if (GetRace() == Race.Worgen)
{ {
if (HasAura(210333)) // Glyph of the Feral Chameleon if (HasAura(210333)) // Glyph of the Feral Chameleon
hairColor = (byte)RandomHelper.URand(0, 9); skinColor = (byte)RandomHelper.URand(0, 9);
// Male // Male
if (GetGender() == Gender.Male) if (GetGender() == Gender.Male)
@@ -1284,7 +1293,7 @@ namespace Game.Entities
else if (GetRace() == Race.Tauren) else if (GetRace() == Race.Tauren)
{ {
if (HasAura(210333)) // Glyph of the Feral Chameleon if (HasAura(210333)) // Glyph of the Feral Chameleon
hairColor = (byte)RandomHelper.URand(0, 20); skinColor = (byte)RandomHelper.URand(0, 20);
if (GetGender() == Gender.Male) if (GetGender() == Gender.Male)
{ {
@@ -1393,7 +1402,7 @@ namespace Game.Entities
else if (GetRace() == Race.Worgen) else if (GetRace() == Race.Worgen)
{ {
if (HasAura(210333)) // Glyph of the Feral Chameleon if (HasAura(210333)) // Glyph of the Feral Chameleon
hairColor = (byte)RandomHelper.URand(0, 8); skinColor = (byte)RandomHelper.URand(0, 8);
// Male // Male
if (GetGender() == Gender.Male) if (GetGender() == Gender.Male)
@@ -1438,7 +1447,7 @@ namespace Game.Entities
else if (GetRace() == Race.Tauren) else if (GetRace() == Race.Tauren)
{ {
if (HasAura(210333)) // Glyph of the Feral Chameleon if (HasAura(210333)) // Glyph of the Feral Chameleon
hairColor = (byte)RandomHelper.URand(0, 20); skinColor = (byte)RandomHelper.URand(0, 20);
if (GetGender() == Gender.Male) if (GetGender() == Gender.Male)
{ {
@@ -1679,10 +1688,6 @@ namespace Game.Entities
SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.ShapeshiftForm), (byte)form); SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.ShapeshiftForm), (byte)form);
} }
public void SetModifierValue(UnitMods unitMod, UnitModifierType modifierType, float value)
{
m_auraModifiersGroup[(int)unitMod][(int)modifierType] = value;
}
public int CalcSpellDuration(SpellInfo spellProto) public int CalcSpellDuration(SpellInfo spellProto)
{ {
sbyte comboPoints = (sbyte)(m_playerMovingMe != null ? m_playerMovingMe.GetComboPoints() : 0); sbyte comboPoints = (sbyte)(m_playerMovingMe != null ? m_playerMovingMe.GetComboPoints() : 0);
@@ -1932,20 +1937,16 @@ namespace Game.Entities
FactionTemplateRecord entry = CliDB.FactionTemplateStorage.LookupByKey(GetFaction()); FactionTemplateRecord entry = CliDB.FactionTemplateStorage.LookupByKey(GetFaction());
if (entry == null) if (entry == null)
{ {
ObjectGuid guid = ObjectGuid.Empty; // prevent repeating spam same faction problem Player player = ToPlayer();
if (player != null)
if (GetGUID() != guid) Log.outError(LogFilter.Unit, "Player {0} has invalid faction (faction template id) #{1}", player.GetName(), GetFaction());
else
{ {
Player player = ToPlayer();
Creature creature = ToCreature(); Creature creature = ToCreature();
if (player != null) if (creature != null)
Log.outError(LogFilter.Unit, "Player {0} has invalid faction (faction template id) #{1}", player.GetName(), GetFaction());
else if (creature != null)
Log.outError(LogFilter.Unit, "Creature (template id: {0}) has invalid faction (faction template id) #{1}", creature.GetCreatureTemplate().Entry, GetFaction()); Log.outError(LogFilter.Unit, "Creature (template id: {0}) has invalid faction (faction template id) #{1}", creature.GetCreatureTemplate().Entry, GetFaction());
else else
Log.outError(LogFilter.Unit, "Unit (name={0}, type={1}) has invalid faction (faction template id) #{2}", GetName(), GetTypeId(), GetFaction()); Log.outError(LogFilter.Unit, "Unit (name={0}, type={1}) has invalid faction (faction template id) #{2}", GetName(), GetTypeId(), GetFaction());
guid = GetGUID();
} }
} }
return entry; return entry;
+196 -110
View File
@@ -235,8 +235,7 @@ namespace Game.Spells
if (handleMask == 0) if (handleMask == 0)
return; return;
List<AuraApplication> effectApplications = new List<AuraApplication>(); GetApplicationList(out List<AuraApplication> effectApplications);
GetApplicationList(out effectApplications);
foreach (var aurApp in effectApplications) foreach (var aurApp in effectApplications)
{ {
@@ -408,8 +407,7 @@ namespace Game.Spells
m_periodicTimer += m_period - (int)diff; m_periodicTimer += m_period - (int)diff;
UpdatePeriodic(caster); UpdatePeriodic(caster);
List<AuraApplication> effectApplications = new List<AuraApplication>(); GetApplicationList(out List<AuraApplication> effectApplications);
GetApplicationList(out effectApplications);
// tick on targets of effects // tick on targets of effects
foreach (var appt in effectApplications) foreach (var appt in effectApplications)
if (appt.HasEffect(GetEffIndex())) if (appt.HasEffect(GetEffIndex()))
@@ -1658,7 +1656,7 @@ namespace Game.Spells
Unit target = aurApp.GetTarget(); Unit target = aurApp.GetTarget();
float scale = target.GetObjectScale(); float scale = target.GetObjectScale();
MathFunctions.ApplyPercentModFloatVar(ref scale, GetAmount(), apply); scale += MathFunctions.CalculatePct(1.0f, apply ? GetAmount() : -GetAmount());
target.SetObjectScale(scale); target.SetObjectScale(scale);
} }
@@ -1783,7 +1781,7 @@ namespace Game.Spells
AuraType type = GetAuraType(); AuraType type = GetAuraType();
//Prevent handling aura twice //Prevent handling aura twice
if ((apply) ? target.GetAuraEffectsByType(type).Count > 1 : target.HasAuraType(type)) if (apply ? target.GetAuraEffectsByType(type).Count > 1 : target.HasAuraType(type))
return; return;
Action<Unit> flagAddFn = null; Action<Unit> flagAddFn = null;
@@ -1831,11 +1829,15 @@ namespace Game.Spells
Item item = player.GetItemByPos(InventorySlots.Bag0, (byte)slot); Item item = player.GetItemByPos(InventorySlots.Bag0, (byte)slot);
if (item != null) if (item != null)
{ {
WeaponAttackType attacktype = Player.GetAttackBySlot((byte)slot, item.GetTemplate().GetInventoryType()); WeaponAttackType attackType = Player.GetAttackBySlot((byte)slot, item.GetTemplate().GetInventoryType());
player.ApplyItemDependentAuras(item, !apply); player.ApplyItemDependentAuras(item, !apply);
if (attacktype < WeaponAttackType.Max) if (attackType < WeaponAttackType.Max)
{
player._ApplyWeaponDamage(slot, item, !apply); player._ApplyWeaponDamage(slot, item, !apply);
if (!apply) // apply case already handled on item dependent aura removal (if any)
player.UpdateWeaponDependentAuras(attackType);
}
} }
} }
@@ -2359,7 +2361,15 @@ namespace Game.Spells
Unit target = aurApp.GetTarget(); Unit target = aurApp.GetTarget();
for (byte i = 0; i < (int)SpellSchools.Max; ++i) for (byte i = 0; i < (int)SpellSchools.Max; ++i)
if (Convert.ToBoolean(GetMiscValue() & (1 << i))) if (Convert.ToBoolean(GetMiscValue() & (1 << i)))
MathFunctions.ApplyPercentModFloatVar(ref target.m_threatModifier[i], GetAmount(), apply); {
if (apply)
MathFunctions.AddPct(ref target.m_threatModifier[i], GetAmount());
else
{
float amount = target.GetTotalAuraMultiplierByMiscMask(AuraType.ModThreat, 1u << i);
target.m_threatModifier[i] = amount;
}
}
} }
[AuraEffectHandler(AuraType.ModTotalThreat)] [AuraEffectHandler(AuraType.ModTotalThreat)]
@@ -2882,7 +2892,7 @@ namespace Game.Spells
for (byte x = (byte)SpellSchools.Normal; x < (byte)SpellSchools.Max; x++) for (byte x = (byte)SpellSchools.Normal; x < (byte)SpellSchools.Max; x++)
if (Convert.ToBoolean(GetMiscValue() & (1 << x))) if (Convert.ToBoolean(GetMiscValue() & (1 << x)))
target.HandleStatModifier(UnitMods.ResistanceStart + x, UnitModifierType.TotalValue, GetAmount(), apply); target.HandleStatFlatModifier(UnitMods.ResistanceStart + x, UnitModifierFlatType.Total, GetAmount(), apply);
} }
[AuraEffectHandler(AuraType.ModBaseResistancePct)] [AuraEffectHandler(AuraType.ModBaseResistancePct)]
@@ -2898,14 +2908,30 @@ namespace Game.Spells
{ {
//pets only have base armor //pets only have base armor
if (target.IsPet() && Convert.ToBoolean(GetMiscValue() & (int)SpellSchoolMask.Normal)) if (target.IsPet() && Convert.ToBoolean(GetMiscValue() & (int)SpellSchoolMask.Normal))
target.HandleStatModifier(UnitMods.Armor, UnitModifierType.BasePCT, GetAmount(), apply); {
if (apply)
target.ApplyStatPctModifier(UnitMods.Armor, UnitModifierPctType.Base, GetAmount());
else
{
float amount = target.GetTotalAuraMultiplierByMiscMask(AuraType.ModBaseResistancePct, (uint)SpellSchoolMask.Normal);
target.SetStatPctModifier(UnitMods.Armor, UnitModifierPctType.Base, amount);
}
}
} }
else else
{ {
for (byte x = (byte)SpellSchools.Normal; x < (byte)SpellSchools.Max; x++) for (byte x = (byte)SpellSchools.Normal; x < (byte)SpellSchools.Max; x++)
{ {
if (Convert.ToBoolean(GetMiscValue() & (1 << x))) if (Convert.ToBoolean(GetMiscValue() & (1 << x)))
target.HandleStatModifier(UnitMods.ResistanceStart + x, UnitModifierType.BasePCT, GetAmount(), apply); {
if (apply)
target.ApplyStatPctModifier(UnitMods.ResistanceStart + x, UnitModifierPctType.Base, GetAmount());
else
{
float amount = target.GetTotalAuraMultiplierByMiscMask(AuraType.ModBaseResistancePct, 1u << x);
target.SetStatPctModifier(UnitMods.ResistanceStart + x, UnitModifierPctType.Base, amount);
}
}
} }
} }
} }
@@ -2917,18 +2943,16 @@ namespace Game.Spells
return; return;
Unit target = aurApp.GetTarget(); Unit target = aurApp.GetTarget();
int spellGroupVal = target.GetHighestExclusiveSameEffectSpellGroupValue(this, AuraType.ModResistancePct);
if (Math.Abs(spellGroupVal) >= Math.Abs(GetAmount()))
return;
for (byte i = (byte)SpellSchools.Normal; i < (byte)SpellSchools.Max; i++) for (byte i = (byte)SpellSchools.Normal; i < (byte)SpellSchools.Max; i++)
{ {
if (Convert.ToBoolean(GetMiscValue() & (1 << i))) if (Convert.ToBoolean(GetMiscValue() & (1 << i)))
{ {
if (spellGroupVal != 0) float amount = target.GetTotalAuraMultiplierByMiscMask(AuraType.ModResistancePct, 1u << i);
target.HandleStatModifier(UnitMods.ResistanceStart + i, UnitModifierType.TotalPCT, (float)spellGroupVal, !apply); if (target.GetPctModifierValue(UnitMods.ResistanceStart + i, UnitModifierPctType.Total) == amount)
continue;
target.HandleStatModifier(UnitMods.ResistanceStart + i, UnitModifierType.TotalPCT, GetAmount(), apply); target.SetStatPctModifier(UnitMods.ResistanceStart + i, UnitModifierPctType.Total, amount);
} }
} }
} }
@@ -2946,13 +2970,13 @@ namespace Game.Spells
{ {
//only pets have base stats //only pets have base stats
if (target.IsPet() && Convert.ToBoolean(GetMiscValue() & (int)SpellSchoolMask.Normal)) if (target.IsPet() && Convert.ToBoolean(GetMiscValue() & (int)SpellSchoolMask.Normal))
target.HandleStatModifier(UnitMods.Armor, UnitModifierType.TotalValue, GetAmount(), apply); target.HandleStatFlatModifier(UnitMods.Armor, UnitModifierFlatType.Total, GetAmount(), apply);
} }
else else
{ {
for (byte i = (byte)SpellSchools.Normal; i < (byte)SpellSchools.Max; i++) for (byte i = (byte)SpellSchools.Normal; i < (byte)SpellSchools.Max; i++)
if (Convert.ToBoolean(GetMiscValue() & (1 << i))) if (Convert.ToBoolean(GetMiscValue() & (1 << i)))
target.HandleStatModifier(UnitMods.ResistanceStart + i, UnitModifierType.TotalValue, GetAmount(), apply); target.HandleStatFlatModifier(UnitMods.ResistanceStart + i, UnitModifierFlatType.Total, GetAmount(), apply);
} }
} }
@@ -3004,14 +3028,14 @@ namespace Game.Spells
{ {
if (spellGroupVal != 0) if (spellGroupVal != 0)
{ {
target.HandleStatModifier((UnitMods.StatStart + (int)i), UnitModifierType.TotalValue, (float)spellGroupVal, !apply); target.HandleStatFlatModifier((UnitMods.StatStart + (int)i), UnitModifierFlatType.Total, (float)spellGroupVal, !apply);
if (target.IsTypeId(TypeId.Player) || target.IsPet()) if (target.IsTypeId(TypeId.Player) || target.IsPet())
target.ApplyStatBuffMod(i, spellGroupVal, !apply); target.UpdateStatBuffMod(i);
} }
target.HandleStatModifier(UnitMods.StatStart + (int)i, UnitModifierType.TotalValue, GetAmount(), apply); target.HandleStatFlatModifier(UnitMods.StatStart + (int)i, UnitModifierFlatType.Total, GetAmount(), apply);
if (target.IsTypeId(TypeId.Player) || target.IsPet()) if (target.IsTypeId(TypeId.Player) || target.IsPet())
target.ApplyStatBuffMod(i, GetAmount(), apply); target.UpdateStatBuffMod(i);
} }
} }
} }
@@ -3037,7 +3061,20 @@ namespace Game.Spells
for (int i = (int)Stats.Strength; i < (int)Stats.Max; ++i) for (int i = (int)Stats.Strength; i < (int)Stats.Max; ++i)
{ {
if (GetMiscValue() == i || GetMiscValue() == -1) if (GetMiscValue() == i || GetMiscValue() == -1)
target.HandleStatModifier(UnitMods.StatStart + i, UnitModifierType.BasePCT, (float)m_amount, apply); {
if (apply)
target.ApplyStatPctModifier(UnitMods.StatStart + i, UnitModifierPctType.Base, m_amount);
else
{
float amount = target.GetTotalAuraMultiplier(AuraType.ModPercentStat, aurEff =>
{
if (aurEff.GetMiscValue() == i || aurEff.GetMiscValue() == -1)
return true;
return false;
});
target.SetStatPctModifier(UnitMods.StatStart + i, UnitModifierPctType.Base, amount);
}
}
} }
} }
@@ -3138,22 +3175,6 @@ namespace Game.Spells
return; return;
Unit target = aurApp.GetTarget(); Unit target = aurApp.GetTarget();
int spellGroupVal = target.GetHighestExclusiveSameEffectSpellGroupValue(this, AuraType.ModTotalStatPercentage, true, -1);
if (Math.Abs(spellGroupVal) >= Math.Abs(GetAmount()))
return;
if (spellGroupVal != 0)
{
for (int i = (int)Stats.Strength; i < (int)Stats.Max; i++)
{
if (GetMiscValue() == i || GetMiscValue() == -1) // affect the same stats
{
target.HandleStatModifier((UnitMods.StatStart + i), UnitModifierType.TotalPCT, spellGroupVal, !apply);
if (target.IsTypeId(TypeId.Player) || target.IsPet())
target.ApplyStatPercentBuffMod((Stats)i, spellGroupVal, !apply);
}
}
}
// save current health state // save current health state
float healthPct = target.GetHealthPct(); float healthPct = target.GetHealthPct();
@@ -3169,26 +3190,25 @@ namespace Game.Spells
{ {
if (Convert.ToBoolean(GetMiscValueB() & 1 << i) || GetMiscValueB() == 0) // 0 is also used for all stats if (Convert.ToBoolean(GetMiscValueB() & 1 << i) || GetMiscValueB() == 0) // 0 is also used for all stats
{ {
int spellGroupVal2 = target.GetHighestExclusiveSameEffectSpellGroupValue(this, AuraType.ModTotalStatPercentage, true, i); float amount = target.GetTotalAuraMultiplier(AuraType.ModTotalStatPercentage, aurEff =>
if (Math.Abs(spellGroupVal2) >= Math.Abs(GetAmount())) {
if ((aurEff.GetMiscValueB() & 1 << i) != 0 || aurEff.GetMiscValueB() == 0)
return true;
return false;
});
if (target.GetPctModifierValue(UnitMods.StatStart + i, UnitModifierPctType.Total) == amount)
continue; continue;
if (spellGroupVal2 != 0) target.SetStatPctModifier(UnitMods.StatStart + i, UnitModifierPctType.Total, amount);
{
target.HandleStatModifier(UnitMods.StatStart + i, UnitModifierType.TotalPCT, spellGroupVal2, !apply);
if (target.IsTypeId(TypeId.Player) || target.IsPet())
target.ApplyStatPercentBuffMod((Stats)i, spellGroupVal2, !apply);
}
target.HandleStatModifier(UnitMods.StatStart + i, UnitModifierType.TotalPCT, GetAmount(), apply);
if (target.IsTypeId(TypeId.Player) || target.IsPet()) if (target.IsTypeId(TypeId.Player) || target.IsPet())
target.ApplyStatPercentBuffMod((Stats)i, GetAmount(), apply); target.UpdateStatBuffMod((Stats)i);
} }
} }
// recalculate current HP/MP after applying aura modifications (only for spells with SPELL_ATTR0_UNK4 0x00000010 flag) // recalculate current HP/MP after applying aura modifications (only for spells with SPELL_ATTR0_ABILITY 0x00000010 flag)
// this check is total bullshit i think // this check is total bullshit i think
if (Convert.ToBoolean(GetMiscValueB() & 1 << (int)Stats.Stamina) && m_spellInfo.HasAttribute(SpellAttr0.Ability)) if ((Convert.ToBoolean(GetMiscValueB() & 1 << (int)Stats.Stamina) || GetMiscValueB() == 0) && m_spellInfo.HasAttribute(SpellAttr0.Ability))
target.SetHealth(Math.Max(MathFunctions.CalculatePct(target.GetMaxHealth(), healthPct), (zeroHealth ? 0 : 1ul))); target.SetHealth(Math.Max(MathFunctions.CalculatePct(target.GetMaxHealth(), healthPct), (zeroHealth ? 0 : 1ul)));
} }
@@ -3252,8 +3272,8 @@ namespace Game.Spells
{ {
if (GetMiscValue() == (int)stat || GetMiscValue() == -1) if (GetMiscValue() == (int)stat || GetMiscValue() == -1)
{ {
target.HandleStatModifier(UnitMods.StatStart + (int)stat, UnitModifierType.BasePCTExcludeCreate, m_amount, apply); target.HandleStatFlatModifier(UnitMods.StatStart + (int)stat, UnitModifierFlatType.BasePCTExcludeCreate, m_amount, apply);
target.ApplyStatPercentBuffMod(stat, m_amount, apply); target.UpdateStatBuffMod(stat);
} }
} }
} }
@@ -3313,7 +3333,7 @@ namespace Game.Spells
PowerType power = (PowerType)GetMiscValue(); PowerType power = (PowerType)GetMiscValue();
UnitMods unitMod = (UnitMods)(UnitMods.PowerStart + (int)power); UnitMods unitMod = (UnitMods)(UnitMods.PowerStart + (int)power);
target.HandleStatModifier(unitMod, UnitModifierType.TotalValue, GetAmount(), apply); target.HandleStatFlatModifier(unitMod, UnitModifierFlatType.Total, GetAmount(), apply);
} }
/********************************/ /********************************/
@@ -3385,7 +3405,7 @@ namespace Game.Spells
if (apply) if (apply)
{ {
target.HandleStatModifier(UnitMods.Health, UnitModifierType.TotalValue, GetAmount(), apply); target.HandleStatFlatModifier(UnitMods.Health, UnitModifierFlatType.Total, GetAmount(), apply);
target.ModifyHealth(GetAmount()); target.ModifyHealth(GetAmount());
} }
else else
@@ -3396,7 +3416,7 @@ namespace Game.Spells
target.ModifyHealth(-value); target.ModifyHealth(-value);
} }
target.HandleStatModifier(UnitMods.Health, UnitModifierType.TotalValue, GetAmount(), apply); target.HandleStatFlatModifier(UnitMods.Health, UnitModifierFlatType.Total, GetAmount(), apply);
} }
} }
@@ -3409,7 +3429,7 @@ namespace Game.Spells
float percent = target.GetHealthPct(); float percent = target.GetHealthPct();
target.HandleStatModifier(UnitMods.Health, UnitModifierType.TotalValue, GetAmount(), apply); target.HandleStatFlatModifier(UnitMods.Health, UnitModifierFlatType.Total, GetAmount(), apply);
// refresh percentage // refresh percentage
if (target.GetHealth() > 0) if (target.GetHealth() > 0)
@@ -3429,7 +3449,7 @@ namespace Game.Spells
PowerType powerType = (PowerType)GetMiscValue(); PowerType powerType = (PowerType)GetMiscValue();
UnitMods unitMod = (UnitMods.PowerStart + (int)powerType); UnitMods unitMod = (UnitMods.PowerStart + (int)powerType);
target.HandleStatModifier(unitMod, UnitModifierType.TotalValue, GetAmount(), apply); target.HandleStatFlatModifier(unitMod, UnitModifierFlatType.Total, GetAmount(), apply);
} }
[AuraEffectHandler(AuraType.ModIncreaseEnergyPercent)] [AuraEffectHandler(AuraType.ModIncreaseEnergyPercent)]
@@ -3448,7 +3468,26 @@ namespace Game.Spells
int oldMaxPower = target.GetMaxPower(powerType); int oldMaxPower = target.GetMaxPower(powerType);
// Handle aura effect for max power // Handle aura effect for max power
target.HandleStatModifier(unitMod, UnitModifierType.TotalPCT, GetAmount(), apply); if (apply)
target.ApplyStatPctModifier(unitMod, UnitModifierPctType.Total, GetAmount());
else
{
float amount = target.GetTotalAuraMultiplier(AuraType.ModIncreaseEnergyPercent, aurEff =>
{
if (aurEff.GetMiscValue() == (int)powerType)
return true;
return false;
});
amount *= target.GetTotalAuraMultiplier(AuraType.ModMaxPowerPct, aurEff =>
{
if (aurEff.GetMiscValue() == (int)powerType)
return true;
return false;
});
target.SetStatPctModifier(unitMod, UnitModifierPctType.Total, amount);
}
// Calculate the current power change // Calculate the current power change
int change = target.GetMaxPower(powerType) - oldMaxPower; int change = target.GetMaxPower(powerType) - oldMaxPower;
@@ -3465,11 +3504,17 @@ namespace Game.Spells
// Unit will keep hp% after MaxHealth being modified if unit is alive. // Unit will keep hp% after MaxHealth being modified if unit is alive.
float percent = target.GetHealthPct(); float percent = target.GetHealthPct();
target.HandleStatModifier(UnitMods.Health, UnitModifierType.TotalPCT, GetAmount(), apply); if (apply)
target.ApplyStatPctModifier(UnitMods.Health, UnitModifierPctType.Total, GetAmount());
else
{
float amount = target.GetTotalAuraMultiplier(AuraType.ModIncreaseHealthPercent);
target.SetStatPctModifier(UnitMods.Health, UnitModifierPctType.Total, amount);
}
if (target.GetHealth() > 0) if (target.GetHealth() > 0)
{ {
uint newHealth = (uint)Math.Max(target.CountPctFromMaxHealth((int)percent), 1); uint newHealth = (uint)Math.Max(MathFunctions.CalculatePct(target.GetMaxHealth(), (int)percent), 1);
target.SetHealth(newHealth); target.SetHealth(newHealth);
} }
} }
@@ -3482,7 +3527,13 @@ namespace Game.Spells
Unit target = aurApp.GetTarget(); Unit target = aurApp.GetTarget();
target.HandleStatModifier(UnitMods.Health, UnitModifierType.BasePCT, GetAmount(), apply); if (apply)
target.ApplyStatPctModifier(UnitMods.Health, UnitModifierPctType.Base, GetAmount());
else
{
float amount = target.GetTotalAuraMultiplier(AuraType.ModBaseHealthPct);
target.SetStatPctModifier(UnitMods.Health, UnitModifierPctType.Base, amount);
}
} }
[AuraEffectHandler(AuraType.ModBaseManaPct)] [AuraEffectHandler(AuraType.ModBaseManaPct)]
@@ -3491,7 +3542,15 @@ namespace Game.Spells
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)) if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
return; return;
aurApp.GetTarget().HandleStatModifier(UnitMods.Mana, UnitModifierType.BasePCT, GetAmount(), apply); Unit target = aurApp.GetTarget();
if (apply)
target.ApplyStatPctModifier(UnitMods.Mana, UnitModifierPctType.Base, GetAmount());
else
{
float amount = target.GetTotalAuraMultiplier(AuraType.ModBaseManaPct);
target.SetStatPctModifier(UnitMods.Mana, UnitModifierPctType.Base, amount);
}
} }
[AuraEffectHandler(AuraType.ModPowerDisplay)] [AuraEffectHandler(AuraType.ModPowerDisplay)]
@@ -3550,7 +3609,26 @@ namespace Game.Spells
int oldMaxPower = target.GetMaxPower(powerType); int oldMaxPower = target.GetMaxPower(powerType);
// Handle aura effect for max power // Handle aura effect for max power
target.HandleStatModifier(unitMod, UnitModifierType.TotalPCT, (float)GetAmount(), apply); if (apply)
target.ApplyStatPctModifier(unitMod, UnitModifierPctType.Total, GetAmount());
else
{
float amount = target.GetTotalAuraMultiplier(AuraType.ModMaxPowerPct, aurEff =>
{
if (aurEff.GetMiscValue() == (int)powerType)
return true;
return false;
});
amount *= target.GetTotalAuraMultiplier(AuraType.ModIncreaseEnergyPercent, aurEff =>
{
if (aurEff.GetMiscValue() == (int)powerType)
return true;
return false;
});
target.SetStatPctModifier(unitMod, UnitModifierPctType.Total, amount);
}
// Calculate the current power change // Calculate the current power change
int change = target.GetMaxPower(powerType) - oldMaxPower; int change = target.GetMaxPower(powerType) - oldMaxPower;
@@ -3616,13 +3694,10 @@ namespace Game.Spells
return; return;
Player target = aurApp.GetTarget().ToPlayer(); Player target = aurApp.GetTarget().ToPlayer();
if (!target) if (!target)
return; return;
target.HandleBaseModValue(BaseModGroup.CritPercentage, BaseModType.FlatMod, GetAmount(), apply); target.UpdateAllWeaponDependentCritAuras();
target.HandleBaseModValue(BaseModGroup.OffhandCritPercentage, BaseModType.FlatMod, GetAmount(), apply);
target.HandleBaseModValue(BaseModGroup.RangedCritPercentage, BaseModType.FlatMod, GetAmount(), apply);
} }
[AuraEffectHandler(AuraType.ModHitChance)] [AuraEffectHandler(AuraType.ModHitChance)]
@@ -3687,9 +3762,7 @@ namespace Game.Spells
return; return;
} }
target.ToPlayer().HandleBaseModValue(BaseModGroup.CritPercentage, BaseModType.FlatMod, GetAmount(), apply); target.ToPlayer().UpdateAllWeaponDependentCritAuras();
target.ToPlayer().HandleBaseModValue(BaseModGroup.OffhandCritPercentage, BaseModType.FlatMod, GetAmount(), apply);
target.ToPlayer().HandleBaseModValue(BaseModGroup.RangedCritPercentage, BaseModType.FlatMod, GetAmount(), apply);
// included in Player.UpdateSpellCritChance calculation // included in Player.UpdateSpellCritChance calculation
target.ToPlayer().UpdateSpellCritChance(); target.ToPlayer().UpdateSpellCritChance();
@@ -3863,7 +3936,7 @@ namespace Game.Spells
Unit target = aurApp.GetTarget(); Unit target = aurApp.GetTarget();
target.HandleStatModifier(UnitMods.AttackPower, UnitModifierType.TotalValue, GetAmount(), apply); target.HandleStatFlatModifier(UnitMods.AttackPower, UnitModifierFlatType.Total, GetAmount(), apply);
} }
[AuraEffectHandler(AuraType.ModRangedAttackPower)] [AuraEffectHandler(AuraType.ModRangedAttackPower)]
@@ -3877,7 +3950,7 @@ namespace Game.Spells
if ((target.GetClassMask() & (uint)Class.ClassMaskWandUsers) != 0) if ((target.GetClassMask() & (uint)Class.ClassMaskWandUsers) != 0)
return; return;
target.HandleStatModifier(UnitMods.AttackPowerRanged, UnitModifierType.TotalValue, GetAmount(), apply); target.HandleStatFlatModifier(UnitMods.AttackPowerRanged, UnitModifierFlatType.Total, GetAmount(), apply);
} }
[AuraEffectHandler(AuraType.ModAttackPowerPct)] [AuraEffectHandler(AuraType.ModAttackPowerPct)]
@@ -3889,7 +3962,13 @@ namespace Game.Spells
Unit target = aurApp.GetTarget(); Unit target = aurApp.GetTarget();
//UNIT_FIELD_ATTACK_POWER_MULTIPLIER = multiplier - 1 //UNIT_FIELD_ATTACK_POWER_MULTIPLIER = multiplier - 1
target.HandleStatModifier(UnitMods.AttackPower, UnitModifierType.TotalPCT, GetAmount(), apply); if (apply)
target.ApplyStatPctModifier(UnitMods.AttackPower, UnitModifierPctType.Total, GetAmount());
else
{
float amount = target.GetTotalAuraMultiplier(AuraType.ModAttackPowerPct);
target.SetStatPctModifier(UnitMods.AttackPower, UnitModifierPctType.Total, amount);
}
} }
[AuraEffectHandler(AuraType.ModRangedAttackPowerPct)] [AuraEffectHandler(AuraType.ModRangedAttackPowerPct)]
@@ -3904,7 +3983,13 @@ namespace Game.Spells
return; return;
//UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = multiplier - 1 //UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = multiplier - 1
target.HandleStatModifier(UnitMods.AttackPowerRanged, UnitModifierType.TotalPCT, GetAmount(), apply); if (apply)
target.ApplyStatPctModifier(UnitMods.AttackPowerRanged, UnitModifierPctType.Total, GetAmount());
else
{
float amount = target.GetTotalAuraMultiplier(AuraType.ModRangedAttackPowerPct);
target.SetStatPctModifier(UnitMods.AttackPowerRanged, UnitModifierPctType.Total, amount);
}
} }
/********************************/ /********************************/
@@ -3919,11 +4004,7 @@ namespace Game.Spells
Unit target = aurApp.GetTarget(); Unit target = aurApp.GetTarget();
if ((GetMiscValue() & (int)SpellSchoolMask.Normal) != 0) if ((GetMiscValue() & (int)SpellSchoolMask.Normal) != 0)
{ target.UpdateAllDamageDoneMods();
target.HandleStatModifier(UnitMods.DamageMainHand, UnitModifierType.TotalValue, GetAmount(), apply);
target.HandleStatModifier(UnitMods.DamageOffHand, UnitModifierType.TotalValue, GetAmount(), apply);
target.HandleStatModifier(UnitMods.DamageRanged, UnitModifierType.TotalValue, GetAmount(), apply);
}
// Magic damage modifiers implemented in Unit::SpellBaseDamageBonusDone // Magic damage modifiers implemented in Unit::SpellBaseDamageBonusDone
// This information for client side use only // This information for client side use only
@@ -3954,35 +4035,21 @@ namespace Game.Spells
return; return;
Unit target = aurApp.GetTarget(); Unit target = aurApp.GetTarget();
int spellGroupVal = target.GetHighestExclusiveSameEffectSpellGroupValue(this, AuraType.ModDamagePercentDone);
if (Math.Abs(spellGroupVal) >= Math.Abs(GetAmount()))
return;
// also handles spell group stacks
if (Convert.ToBoolean(GetMiscValue() & (int)SpellSchoolMask.Normal)) if (Convert.ToBoolean(GetMiscValue() & (int)SpellSchoolMask.Normal))
{ target.UpdateAllDamagePctDoneMods();
if (spellGroupVal != 0)
{
target.HandleStatModifier(UnitMods.DamageMainHand, UnitModifierType.TotalPCT, spellGroupVal, !apply);
target.HandleStatModifier(UnitMods.DamageOffHand, UnitModifierType.TotalPCT, spellGroupVal, !apply);
target.HandleStatModifier(UnitMods.DamageRanged, UnitModifierType.TotalPCT, spellGroupVal, !apply);
}
target.HandleStatModifier(UnitMods.DamageMainHand, UnitModifierType.TotalPCT, GetAmount(), apply);
target.HandleStatModifier(UnitMods.DamageOffHand, UnitModifierType.TotalPCT, GetAmount(), apply);
target.HandleStatModifier(UnitMods.DamageRanged, UnitModifierType.TotalPCT, GetAmount(), apply);
}
Player thisPlayer = target.ToPlayer(); Player thisPlayer = target.ToPlayer();
if (thisPlayer != null) if (thisPlayer != null)
{ {
for (int i = 0; i < (int)SpellSchools.Max; ++i) for (var i = SpellSchools.Normal; i < SpellSchools.Max; ++i)
{ {
if (Convert.ToBoolean(GetMiscValue() & (1 << i))) if (Convert.ToBoolean(GetMiscValue() & (1 << (int)i)))
{ {
if (spellGroupVal != 0) // only aura type modifying PLAYER_FIELD_MOD_DAMAGE_DONE_PCT
thisPlayer.ApplyModDamageDonePercent((SpellSchools)i, spellGroupVal, !apply); float amount = thisPlayer.GetTotalAuraMultiplierByMiscMask(AuraType.ModDamagePercentDone, 1u << (int)i);
thisPlayer.SetModDamageDonePercent(i, amount);
thisPlayer.ApplyModDamageDonePercent((SpellSchools)i, GetAmount(), apply);
} }
} }
} }
@@ -3996,18 +4063,37 @@ namespace Game.Spells
Unit target = aurApp.GetTarget(); Unit target = aurApp.GetTarget();
target.HandleStatModifier(UnitMods.DamageOffHand, UnitModifierType.TotalPCT, GetAmount(), apply); // also handles spell group stacks
target.UpdateDamagePctDoneMods(WeaponAttackType.OffAttack);
}
void HandleShieldBlockValue(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
{
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))
return;
Player player = aurApp.GetTarget().ToPlayer();
if (player != null)
player.HandleBaseModFlatValue(BaseModGroup.ShieldBlockValue, GetAmount(), apply);
} }
[AuraEffectHandler(AuraType.ModShieldBlockvaluePct)] [AuraEffectHandler(AuraType.ModShieldBlockvaluePct)]
void HandleShieldBlockValue(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply) void HandleShieldBlockValuePercent(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
{ {
if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat))) if (!mode.HasAnyFlag((AuraEffectHandleModes.ChangeAmountMask | AuraEffectHandleModes.Stat)))
return; return;
Player player = aurApp.GetTarget().ToPlayer(); Player target = aurApp.GetTarget().ToPlayer();
if (player) if (!target)
player.HandleBaseModValue(BaseModGroup.ShieldBlockValue, BaseModType.PCTmod, GetAmount(), apply); return;
if (apply)
target.ApplyBaseModPctValue(BaseModGroup.ShieldBlockValue, GetAmount());
else
{
float amount = target.GetTotalAuraMultiplier(AuraType.ModShieldBlockvaluePct);
target.SetBaseModPctValue(BaseModGroup.ShieldBlockValue, amount);
}
} }
/********************************/ /********************************/
@@ -4478,7 +4564,7 @@ namespace Game.Spells
} }
//Adding items //Adding items
uint noSpaceForCount = 0; uint noSpaceForCount;
uint count = (uint)m_amount; uint count = (uint)m_amount;
List<ItemPosCount> dest = new List<ItemPosCount>(); List<ItemPosCount> dest = new List<ItemPosCount>();
+10 -10
View File
@@ -1388,8 +1388,8 @@ namespace Game.Spells
Player player = m_caster.ToPlayer(); Player player = m_caster.ToPlayer();
uint lockId = 0; uint lockId;
ObjectGuid guid = ObjectGuid.Empty; ObjectGuid guid;
// Get lockId // Get lockId
if (gameObjTarget != null) if (gameObjTarget != null)
@@ -1741,7 +1741,7 @@ namespace Game.Spells
for (uint count = 0; count < numSummons; ++count) for (uint count = 0; count < numSummons; ++count)
{ {
Position pos = new Position(); Position pos;
if (count == 0) if (count == 0)
pos = destTarget; pos = destTarget;
else else
@@ -2657,7 +2657,7 @@ namespace Game.Spells
break; break;
} }
float weapon_total_pct = m_caster.GetModifierValue(unitMod, UnitModifierType.TotalPCT); float weapon_total_pct = m_caster.GetPctModifierValue(unitMod, UnitModifierPctType.Total);
if (fixed_bonus != 0) if (fixed_bonus != 0)
fixed_bonus = (int)(fixed_bonus * weapon_total_pct); fixed_bonus = (int)(fixed_bonus * weapon_total_pct);
if (spell_bonus != 0) if (spell_bonus != 0)
@@ -2725,7 +2725,7 @@ namespace Game.Spells
if (unitTarget == null || !unitTarget.IsAlive()) if (unitTarget == null || !unitTarget.IsAlive())
return; return;
int addhealth = 0; int addhealth;
// damage == 0 - heal for caster max health // damage == 0 - heal for caster max health
if (damage == 0) if (damage == 0)
@@ -2951,7 +2951,7 @@ namespace Game.Spells
byte bag = 19; byte bag = 19;
byte slot = 0; byte slot = 0;
Item item = null; Item item;
while (bag != 0) // 256 = 0 due to var type while (bag != 0) // 256 = 0 due to var type
{ {
@@ -3020,7 +3020,7 @@ namespace Game.Spells
if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Unit)) if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Unit))
return; return;
uint iTmpSpellId = 0; uint iTmpSpellId;
switch (unitTarget.GetDisplayId()) switch (unitTarget.GetDisplayId())
{ {
case 25369: iTmpSpellId = 51552; break; // bloodelf female case 25369: iTmpSpellId = 51552; break; // bloodelf female
@@ -3304,7 +3304,7 @@ namespace Game.Spells
{ {
if (unitTarget == null || !unitTarget.IsAlive()) if (unitTarget == null || !unitTarget.IsAlive())
return; return;
uint spellId1 = 0; uint spellId1;
uint spellId2 = 0; uint spellId2 = 0;
// Judgement self add switch // Judgement self add switch
@@ -3985,7 +3985,7 @@ namespace Game.Spells
if (!m_caster.IsInWorld) if (!m_caster.IsInWorld)
return; return;
uint health = 0; uint health;
int mana = 0; int mana = 0;
// flat case // flat case
@@ -5065,7 +5065,7 @@ namespace Game.Spells
for (uint count = 0; count < numGuardians; ++count) for (uint count = 0; count < numGuardians; ++count)
{ {
Position pos = new Position(); Position pos;
if (count == 0) if (count == 0)
pos = destTarget; pos = destTarget;
else else