Core/Auras: Implemented SPELL_AURA_ADD_PCT_MODIFIER_BY_SPELL_LABEL and SPELL_AURA_ADD_FLAT_MODIFIER_BY_SPELL_LABEL
Port From (https://github.com/TrinityCore/TrinityCore/commit/ba4fa060d765a35507f1a73287504c3f2e440fdb)
This commit is contained in:
@@ -239,8 +239,8 @@ namespace Framework.Constants
|
|||||||
ArenaPreparation = 215,
|
ArenaPreparation = 215,
|
||||||
HasteSpells = 216,
|
HasteSpells = 216,
|
||||||
ModMeleeHaste2 = 217,
|
ModMeleeHaste2 = 217,
|
||||||
AddPctModifierBySpellLabel = 218, //NYI
|
AddPctModifierBySpellLabel = 218,
|
||||||
AddFlatModifierBySpellLabel = 219, //NYI
|
AddFlatModifierBySpellLabel = 219,
|
||||||
ModAbilitySchoolMask = 220, //NYI
|
ModAbilitySchoolMask = 220, //NYI
|
||||||
ModDetaunt = 221,
|
ModDetaunt = 221,
|
||||||
RemoveTransmogCost = 222,
|
RemoveTransmogCost = 222,
|
||||||
|
|||||||
@@ -400,6 +400,8 @@ namespace Framework.Constants
|
|||||||
{
|
{
|
||||||
Flat = 0, // SPELL_AURA_ADD_FLAT_MODIFIER
|
Flat = 0, // SPELL_AURA_ADD_FLAT_MODIFIER
|
||||||
Pct = 1, // SPELL_AURA_ADD_PCT_MODIFIER
|
Pct = 1, // SPELL_AURA_ADD_PCT_MODIFIER
|
||||||
|
LabelFlat = 2, // SPELL_AURA_ADD_FLAT_MODIFIER_BY_SPELL_LABEL
|
||||||
|
LabelPct = 3, // SPELL_AURA_ADD_PCT_MODIFIER_BY_SPELL_LABEL
|
||||||
End
|
End
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ 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;
|
||||||
|
|
||||||
return skillInfo.SkillStep[skillStatusData.Pos];
|
return skillInfo.SkillStep[skillStatusData.Pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
public ushort GetPureMaxSkillValue(SkillType skill)
|
public ushort GetPureMaxSkillValue(SkillType skill)
|
||||||
@@ -576,12 +576,12 @@ namespace Game.Entities
|
|||||||
// processed in Player.CastItemCombatSpell
|
// processed in Player.CastItemCombatSpell
|
||||||
break;
|
break;
|
||||||
case ItemEnchantmentType.Damage:
|
case ItemEnchantmentType.Damage:
|
||||||
{
|
{
|
||||||
WeaponAttackType attackType = Player.GetAttackBySlot(item.GetSlot(), item.GetTemplate().GetInventoryType());
|
WeaponAttackType attackType = Player.GetAttackBySlot(item.GetSlot(), item.GetTemplate().GetInventoryType());
|
||||||
if (attackType != WeaponAttackType.Max)
|
if (attackType != WeaponAttackType.Max)
|
||||||
UpdateDamageDoneMods(attackType);
|
UpdateDamageDoneMods(attackType);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ItemEnchantmentType.EquipSpell:
|
case ItemEnchantmentType.EquipSpell:
|
||||||
if (enchant_spell_id != 0)
|
if (enchant_spell_id != 0)
|
||||||
{
|
{
|
||||||
@@ -616,189 +616,189 @@ namespace Game.Entities
|
|||||||
HandleStatFlatModifier((UnitMods)((uint)UnitMods.ResistanceStart + enchant_spell_id), UnitModifierFlatType.Total, enchant_amount, apply);
|
HandleStatFlatModifier((UnitMods)((uint)UnitMods.ResistanceStart + enchant_spell_id), UnitModifierFlatType.Total, enchant_amount, apply);
|
||||||
break;
|
break;
|
||||||
case ItemEnchantmentType.Stat:
|
case ItemEnchantmentType.Stat:
|
||||||
|
{
|
||||||
|
if (pEnchant.ScalingClass != 0)
|
||||||
{
|
{
|
||||||
if (pEnchant.ScalingClass != 0)
|
int scalingClass = pEnchant.ScalingClass;
|
||||||
{
|
if ((m_unitData.MinItemLevel != 0 || m_unitData.MaxItemLevel != 0) && pEnchant.ScalingClassRestricted != 0)
|
||||||
int scalingClass = pEnchant.ScalingClass;
|
scalingClass = pEnchant.ScalingClassRestricted;
|
||||||
if ((m_unitData.MinItemLevel != 0 || m_unitData.MaxItemLevel != 0) && pEnchant.ScalingClassRestricted != 0)
|
|
||||||
scalingClass = pEnchant.ScalingClassRestricted;
|
|
||||||
|
|
||||||
uint minLevel = ((uint)(pEnchant.Flags)).HasAnyFlag(0x20u) ? 1 : 60u;
|
uint minLevel = ((uint)(pEnchant.Flags)).HasAnyFlag(0x20u) ? 1 : 60u;
|
||||||
uint scalingLevel = GetLevel();
|
uint scalingLevel = GetLevel();
|
||||||
byte maxLevel = (byte)(pEnchant.MaxLevel != 0 ? pEnchant.MaxLevel : CliDB.SpellScalingGameTable.GetTableRowCount() - 1);
|
byte maxLevel = (byte)(pEnchant.MaxLevel != 0 ? pEnchant.MaxLevel : CliDB.SpellScalingGameTable.GetTableRowCount() - 1);
|
||||||
|
|
||||||
if (minLevel > GetLevel())
|
if (minLevel > GetLevel())
|
||||||
scalingLevel = minLevel;
|
scalingLevel = minLevel;
|
||||||
else if (maxLevel < GetLevel())
|
else if (maxLevel < GetLevel())
|
||||||
scalingLevel = maxLevel;
|
scalingLevel = maxLevel;
|
||||||
|
|
||||||
GtSpellScalingRecord spellScaling = CliDB.SpellScalingGameTable.GetRow(scalingLevel);
|
GtSpellScalingRecord spellScaling = CliDB.SpellScalingGameTable.GetRow(scalingLevel);
|
||||||
if (spellScaling != null)
|
if (spellScaling != null)
|
||||||
enchant_amount = (uint)(pEnchant.EffectScalingPoints[s] * CliDB.GetSpellScalingColumnForClass(spellScaling, scalingClass));
|
enchant_amount = (uint)(pEnchant.EffectScalingPoints[s] * CliDB.GetSpellScalingColumnForClass(spellScaling, scalingClass));
|
||||||
}
|
|
||||||
|
|
||||||
enchant_amount = Math.Max(enchant_amount, 1u);
|
|
||||||
|
|
||||||
Log.outDebug(LogFilter.Player, "Adding {0} to stat nb {1}", enchant_amount, enchant_spell_id);
|
|
||||||
switch ((ItemModType)enchant_spell_id)
|
|
||||||
{
|
|
||||||
case ItemModType.Mana:
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} MANA", enchant_amount);
|
|
||||||
HandleStatFlatModifier(UnitMods.Mana, UnitModifierFlatType.Base, enchant_amount, apply);
|
|
||||||
break;
|
|
||||||
case ItemModType.Health:
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} HEALTH", enchant_amount);
|
|
||||||
HandleStatFlatModifier(UnitMods.Health, UnitModifierFlatType.Base, enchant_amount, apply);
|
|
||||||
break;
|
|
||||||
case ItemModType.Agility:
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} AGILITY", enchant_amount);
|
|
||||||
HandleStatFlatModifier(UnitMods.StatAgility, UnitModifierFlatType.Total, enchant_amount, apply);
|
|
||||||
UpdateStatBuffMod(Stats.Agility);
|
|
||||||
break;
|
|
||||||
case ItemModType.Strength:
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} STRENGTH", enchant_amount);
|
|
||||||
HandleStatFlatModifier(UnitMods.StatStrength, UnitModifierFlatType.Total, enchant_amount, apply);
|
|
||||||
UpdateStatBuffMod(Stats.Strength);
|
|
||||||
break;
|
|
||||||
case ItemModType.Intellect:
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} INTELLECT", enchant_amount);
|
|
||||||
HandleStatFlatModifier(UnitMods.StatIntellect, UnitModifierFlatType.Total, enchant_amount, apply);
|
|
||||||
UpdateStatBuffMod(Stats.Intellect);
|
|
||||||
break;
|
|
||||||
//case ItemModType.Spirit:
|
|
||||||
//Log.outDebug(LogFilter.Player, "+ {0} SPIRIT", enchant_amount);
|
|
||||||
//HandleStatModifier(UnitMods.StatSpirit, UnitModifierType.TotalValue, enchant_amount, apply);
|
|
||||||
//ApplyStatBuffMod(Stats.Spirit, enchant_amount, apply);
|
|
||||||
//break;
|
|
||||||
case ItemModType.Stamina:
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} STAMINA", enchant_amount);
|
|
||||||
HandleStatFlatModifier(UnitMods.StatStamina, UnitModifierFlatType.Total, enchant_amount, apply);
|
|
||||||
UpdateStatBuffMod(Stats.Stamina);
|
|
||||||
break;
|
|
||||||
case ItemModType.DefenseSkillRating:
|
|
||||||
ApplyRatingMod(CombatRating.DefenseSkill, (int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} DEFENSE", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.DodgeRating:
|
|
||||||
ApplyRatingMod(CombatRating.Dodge, (int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} DODGE", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.ParryRating:
|
|
||||||
ApplyRatingMod(CombatRating.Parry, (int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} PARRY", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.BlockRating:
|
|
||||||
ApplyRatingMod(CombatRating.Block, (int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} SHIELD_BLOCK", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.HitMeleeRating:
|
|
||||||
ApplyRatingMod(CombatRating.HitMelee, (int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} MELEE_HIT", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.HitRangedRating:
|
|
||||||
ApplyRatingMod(CombatRating.HitRanged, (int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} RANGED_HIT", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.HitSpellRating:
|
|
||||||
ApplyRatingMod(CombatRating.HitSpell, (int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} SPELL_HIT", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.CritMeleeRating:
|
|
||||||
ApplyRatingMod(CombatRating.CritMelee, (int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} MELEE_CRIT", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.CritRangedRating:
|
|
||||||
ApplyRatingMod(CombatRating.CritRanged, (int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} RANGED_CRIT", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.CritSpellRating:
|
|
||||||
ApplyRatingMod(CombatRating.CritSpell, (int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} SPELL_CRIT", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.HasteSpellRating:
|
|
||||||
ApplyRatingMod(CombatRating.HasteSpell, (int)enchant_amount, apply);
|
|
||||||
break;
|
|
||||||
case ItemModType.HitRating:
|
|
||||||
ApplyRatingMod(CombatRating.HitMelee, (int)enchant_amount, apply);
|
|
||||||
ApplyRatingMod(CombatRating.HitRanged, (int)enchant_amount, apply);
|
|
||||||
ApplyRatingMod(CombatRating.HitSpell, (int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} HIT", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.CritRating:
|
|
||||||
ApplyRatingMod(CombatRating.CritMelee, (int)enchant_amount, apply);
|
|
||||||
ApplyRatingMod(CombatRating.CritRanged, (int)enchant_amount, apply);
|
|
||||||
ApplyRatingMod(CombatRating.CritSpell, (int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} CRITICAL", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.ResilienceRating:
|
|
||||||
ApplyRatingMod(CombatRating.ResiliencePlayerDamage, (int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} RESILIENCE", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.HasteRating:
|
|
||||||
ApplyRatingMod(CombatRating.HasteMelee, (int)enchant_amount, apply);
|
|
||||||
ApplyRatingMod(CombatRating.HasteRanged, (int)enchant_amount, apply);
|
|
||||||
ApplyRatingMod(CombatRating.HasteSpell, (int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} HASTE", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.ExpertiseRating:
|
|
||||||
ApplyRatingMod(CombatRating.Expertise, (int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} EXPERTISE", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.AttackPower:
|
|
||||||
HandleStatFlatModifier(UnitMods.AttackPower, UnitModifierFlatType.Total, enchant_amount, apply);
|
|
||||||
HandleStatFlatModifier(UnitMods.AttackPowerRanged, UnitModifierFlatType.Total, enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} ATTACK_POWER", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.RangedAttackPower:
|
|
||||||
HandleStatFlatModifier(UnitMods.AttackPowerRanged, UnitModifierFlatType.Total, enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} RANGED_ATTACK_POWER", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.ManaRegeneration:
|
|
||||||
ApplyManaRegenBonus((int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} MANA_REGENERATION", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.ArmorPenetrationRating:
|
|
||||||
ApplyRatingMod(CombatRating.ArmorPenetration, (int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} ARMOR PENETRATION", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.SpellPower:
|
|
||||||
ApplySpellPowerBonus((int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} SPELL_POWER", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.HealthRegen:
|
|
||||||
ApplyHealthRegenBonus((int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} HEALTH_REGENERATION", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.SpellPenetration:
|
|
||||||
ApplySpellPenetrationBonus((int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} SPELL_PENETRATION", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.BlockValue:
|
|
||||||
HandleBaseModFlatValue(BaseModGroup.ShieldBlockValue, enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} BLOCK_VALUE", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.MasteryRating:
|
|
||||||
ApplyRatingMod(CombatRating.Mastery, (int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} MASTERY", enchant_amount);
|
|
||||||
break;
|
|
||||||
case ItemModType.Versatility:
|
|
||||||
ApplyRatingMod(CombatRating.VersatilityDamageDone, (int)enchant_amount, apply);
|
|
||||||
ApplyRatingMod(CombatRating.VersatilityHealingDone, (int)enchant_amount, apply);
|
|
||||||
ApplyRatingMod(CombatRating.VersatilityDamageTaken, (int)enchant_amount, apply);
|
|
||||||
Log.outDebug(LogFilter.Player, "+ {0} VERSATILITY", enchant_amount);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enchant_amount = Math.Max(enchant_amount, 1u);
|
||||||
|
|
||||||
|
Log.outDebug(LogFilter.Player, "Adding {0} to stat nb {1}", enchant_amount, enchant_spell_id);
|
||||||
|
switch ((ItemModType)enchant_spell_id)
|
||||||
|
{
|
||||||
|
case ItemModType.Mana:
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} MANA", enchant_amount);
|
||||||
|
HandleStatFlatModifier(UnitMods.Mana, UnitModifierFlatType.Base, enchant_amount, apply);
|
||||||
|
break;
|
||||||
|
case ItemModType.Health:
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} HEALTH", enchant_amount);
|
||||||
|
HandleStatFlatModifier(UnitMods.Health, UnitModifierFlatType.Base, enchant_amount, apply);
|
||||||
|
break;
|
||||||
|
case ItemModType.Agility:
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} AGILITY", enchant_amount);
|
||||||
|
HandleStatFlatModifier(UnitMods.StatAgility, UnitModifierFlatType.Total, enchant_amount, apply);
|
||||||
|
UpdateStatBuffMod(Stats.Agility);
|
||||||
|
break;
|
||||||
|
case ItemModType.Strength:
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} STRENGTH", enchant_amount);
|
||||||
|
HandleStatFlatModifier(UnitMods.StatStrength, UnitModifierFlatType.Total, enchant_amount, apply);
|
||||||
|
UpdateStatBuffMod(Stats.Strength);
|
||||||
|
break;
|
||||||
|
case ItemModType.Intellect:
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} INTELLECT", enchant_amount);
|
||||||
|
HandleStatFlatModifier(UnitMods.StatIntellect, UnitModifierFlatType.Total, enchant_amount, apply);
|
||||||
|
UpdateStatBuffMod(Stats.Intellect);
|
||||||
|
break;
|
||||||
|
//case ItemModType.Spirit:
|
||||||
|
//Log.outDebug(LogFilter.Player, "+ {0} SPIRIT", enchant_amount);
|
||||||
|
//HandleStatModifier(UnitMods.StatSpirit, UnitModifierType.TotalValue, enchant_amount, apply);
|
||||||
|
//ApplyStatBuffMod(Stats.Spirit, enchant_amount, apply);
|
||||||
|
//break;
|
||||||
|
case ItemModType.Stamina:
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} STAMINA", enchant_amount);
|
||||||
|
HandleStatFlatModifier(UnitMods.StatStamina, UnitModifierFlatType.Total, enchant_amount, apply);
|
||||||
|
UpdateStatBuffMod(Stats.Stamina);
|
||||||
|
break;
|
||||||
|
case ItemModType.DefenseSkillRating:
|
||||||
|
ApplyRatingMod(CombatRating.DefenseSkill, (int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} DEFENSE", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.DodgeRating:
|
||||||
|
ApplyRatingMod(CombatRating.Dodge, (int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} DODGE", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.ParryRating:
|
||||||
|
ApplyRatingMod(CombatRating.Parry, (int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} PARRY", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.BlockRating:
|
||||||
|
ApplyRatingMod(CombatRating.Block, (int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} SHIELD_BLOCK", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.HitMeleeRating:
|
||||||
|
ApplyRatingMod(CombatRating.HitMelee, (int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} MELEE_HIT", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.HitRangedRating:
|
||||||
|
ApplyRatingMod(CombatRating.HitRanged, (int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} RANGED_HIT", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.HitSpellRating:
|
||||||
|
ApplyRatingMod(CombatRating.HitSpell, (int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} SPELL_HIT", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.CritMeleeRating:
|
||||||
|
ApplyRatingMod(CombatRating.CritMelee, (int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} MELEE_CRIT", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.CritRangedRating:
|
||||||
|
ApplyRatingMod(CombatRating.CritRanged, (int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} RANGED_CRIT", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.CritSpellRating:
|
||||||
|
ApplyRatingMod(CombatRating.CritSpell, (int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} SPELL_CRIT", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.HasteSpellRating:
|
||||||
|
ApplyRatingMod(CombatRating.HasteSpell, (int)enchant_amount, apply);
|
||||||
|
break;
|
||||||
|
case ItemModType.HitRating:
|
||||||
|
ApplyRatingMod(CombatRating.HitMelee, (int)enchant_amount, apply);
|
||||||
|
ApplyRatingMod(CombatRating.HitRanged, (int)enchant_amount, apply);
|
||||||
|
ApplyRatingMod(CombatRating.HitSpell, (int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} HIT", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.CritRating:
|
||||||
|
ApplyRatingMod(CombatRating.CritMelee, (int)enchant_amount, apply);
|
||||||
|
ApplyRatingMod(CombatRating.CritRanged, (int)enchant_amount, apply);
|
||||||
|
ApplyRatingMod(CombatRating.CritSpell, (int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} CRITICAL", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.ResilienceRating:
|
||||||
|
ApplyRatingMod(CombatRating.ResiliencePlayerDamage, (int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} RESILIENCE", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.HasteRating:
|
||||||
|
ApplyRatingMod(CombatRating.HasteMelee, (int)enchant_amount, apply);
|
||||||
|
ApplyRatingMod(CombatRating.HasteRanged, (int)enchant_amount, apply);
|
||||||
|
ApplyRatingMod(CombatRating.HasteSpell, (int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} HASTE", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.ExpertiseRating:
|
||||||
|
ApplyRatingMod(CombatRating.Expertise, (int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} EXPERTISE", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.AttackPower:
|
||||||
|
HandleStatFlatModifier(UnitMods.AttackPower, UnitModifierFlatType.Total, enchant_amount, apply);
|
||||||
|
HandleStatFlatModifier(UnitMods.AttackPowerRanged, UnitModifierFlatType.Total, enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} ATTACK_POWER", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.RangedAttackPower:
|
||||||
|
HandleStatFlatModifier(UnitMods.AttackPowerRanged, UnitModifierFlatType.Total, enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} RANGED_ATTACK_POWER", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.ManaRegeneration:
|
||||||
|
ApplyManaRegenBonus((int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} MANA_REGENERATION", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.ArmorPenetrationRating:
|
||||||
|
ApplyRatingMod(CombatRating.ArmorPenetration, (int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} ARMOR PENETRATION", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.SpellPower:
|
||||||
|
ApplySpellPowerBonus((int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} SPELL_POWER", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.HealthRegen:
|
||||||
|
ApplyHealthRegenBonus((int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} HEALTH_REGENERATION", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.SpellPenetration:
|
||||||
|
ApplySpellPenetrationBonus((int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} SPELL_PENETRATION", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.BlockValue:
|
||||||
|
HandleBaseModFlatValue(BaseModGroup.ShieldBlockValue, enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} BLOCK_VALUE", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.MasteryRating:
|
||||||
|
ApplyRatingMod(CombatRating.Mastery, (int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} MASTERY", enchant_amount);
|
||||||
|
break;
|
||||||
|
case ItemModType.Versatility:
|
||||||
|
ApplyRatingMod(CombatRating.VersatilityDamageDone, (int)enchant_amount, apply);
|
||||||
|
ApplyRatingMod(CombatRating.VersatilityHealingDone, (int)enchant_amount, apply);
|
||||||
|
ApplyRatingMod(CombatRating.VersatilityDamageTaken, (int)enchant_amount, apply);
|
||||||
|
Log.outDebug(LogFilter.Player, "+ {0} VERSATILITY", enchant_amount);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case ItemEnchantmentType.Totem: // Shaman Rockbiter Weapon
|
case ItemEnchantmentType.Totem: // Shaman Rockbiter Weapon
|
||||||
{
|
{
|
||||||
WeaponAttackType attackType = Player.GetAttackBySlot(item.GetSlot(), item.GetTemplate().GetInventoryType());
|
WeaponAttackType attackType = Player.GetAttackBySlot(item.GetSlot(), item.GetTemplate().GetInventoryType());
|
||||||
if (attackType != WeaponAttackType.Max)
|
if (attackType != WeaponAttackType.Max)
|
||||||
UpdateDamageDoneMods(attackType);
|
UpdateDamageDoneMods(attackType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ItemEnchantmentType.UseSpell:
|
case ItemEnchantmentType.UseSpell:
|
||||||
// processed in Player.CastItemUseSpell
|
// processed in Player.CastItemUseSpell
|
||||||
break;
|
break;
|
||||||
@@ -909,7 +909,7 @@ namespace Game.Entities
|
|||||||
{
|
{
|
||||||
for (var i = 0; i < m_enchantDuration.Count; ++i)
|
for (var i = 0; i < m_enchantDuration.Count; ++i)
|
||||||
{
|
{
|
||||||
var enchantDuration = m_enchantDuration[i];
|
var enchantDuration = m_enchantDuration[i];
|
||||||
if (enchantDuration.item == item)
|
if (enchantDuration.item == item)
|
||||||
{
|
{
|
||||||
// save duration in item
|
// save duration in item
|
||||||
@@ -1083,7 +1083,7 @@ namespace Game.Entities
|
|||||||
skillStatusData.State = SkillState.Changed;
|
skillStatusData.State = SkillState.Changed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(currVal != 0 && newVal == 0) // Deactivate skill line
|
else if (currVal != 0 && newVal == 0) // Deactivate skill line
|
||||||
{
|
{
|
||||||
//remove enchantments needing this skill
|
//remove enchantments needing this skill
|
||||||
UpdateSkillEnchantments(id, currVal, 0);
|
UpdateSkillEnchantments(id, currVal, 0);
|
||||||
@@ -1197,7 +1197,7 @@ namespace Game.Entities
|
|||||||
SetSkillPermBonus(skillSlot, 0);
|
SetSkillPermBonus(skillSlot, 0);
|
||||||
|
|
||||||
UpdateSkillEnchantments(id, 0, (ushort)newVal);
|
UpdateSkillEnchantments(id, 0, (ushort)newVal);
|
||||||
|
|
||||||
mSkillStatus.Add(id, new SkillStatusData(skillSlot, SkillState.New));
|
mSkillStatus.Add(id, new SkillStatusData(skillSlot, SkillState.New));
|
||||||
|
|
||||||
if (newVal != 0)
|
if (newVal != 0)
|
||||||
@@ -1535,7 +1535,7 @@ namespace Game.Entities
|
|||||||
spell.Prepare(targets);
|
spell.Prepare(targets);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint GetLastPotionId() { return m_lastPotionId; }
|
public uint GetLastPotionId() { return m_lastPotionId; }
|
||||||
@@ -1656,62 +1656,62 @@ namespace Game.Entities
|
|||||||
switch (spellInfo.EquippedItemClass)
|
switch (spellInfo.EquippedItemClass)
|
||||||
{
|
{
|
||||||
case ItemClass.Weapon:
|
case ItemClass.Weapon:
|
||||||
{
|
{
|
||||||
Item item = GetUseableItemByPos(InventorySlots.Bag0, EquipmentSlot.MainHand);
|
Item item = GetUseableItemByPos(InventorySlots.Bag0, EquipmentSlot.MainHand);
|
||||||
if (item)
|
if (item)
|
||||||
if (item != ignoreItem && item.IsFitToSpellRequirements(spellInfo))
|
if (item != ignoreItem && item.IsFitToSpellRequirements(spellInfo))
|
||||||
return true;
|
|
||||||
|
|
||||||
item = GetUseableItemByPos(InventorySlots.Bag0, EquipmentSlot.OffHand);
|
|
||||||
if (item)
|
|
||||||
if (item != ignoreItem && item.IsFitToSpellRequirements(spellInfo))
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ItemClass.Armor:
|
|
||||||
{
|
|
||||||
if (!spellInfo.HasAttribute(SpellAttr8.ArmorSpecialization))
|
|
||||||
{
|
|
||||||
// most used check: shield only
|
|
||||||
if ((spellInfo.EquippedItemSubClassMask & (1 << (int)ItemSubClassArmor.Shield)) != 0)
|
|
||||||
{
|
|
||||||
Item item = GetUseableItemByPos(InventorySlots.Bag0, EquipmentSlot.OffHand);
|
|
||||||
if (item != null)
|
|
||||||
if (item != ignoreItem && item.IsFitToSpellRequirements(spellInfo))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// special check to filter things like Shield Wall, the aura is not permanent and must stay even without required item
|
|
||||||
if (!spellInfo.IsPassive())
|
|
||||||
{
|
|
||||||
foreach (var spellEffectInfo in spellInfo.GetEffects())
|
|
||||||
if (spellEffectInfo.IsAura())
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// tabard not have dependent spells
|
|
||||||
for (byte i = EquipmentSlot.Start; i < EquipmentSlot.MainHand; ++i)
|
|
||||||
{
|
|
||||||
Item item = GetUseableItemByPos(InventorySlots.Bag0, i);
|
|
||||||
if (item)
|
|
||||||
if (item != ignoreItem && item.IsFitToSpellRequirements(spellInfo))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// requires item equipped in all armor slots
|
|
||||||
foreach (byte i in new[] { EquipmentSlot.Head, EquipmentSlot.Shoulders, EquipmentSlot.Chest, EquipmentSlot.Waist, EquipmentSlot.Legs, EquipmentSlot.Feet, EquipmentSlot.Wrist, EquipmentSlot.Hands })
|
|
||||||
{
|
|
||||||
Item item = GetUseableItemByPos(InventorySlots.Bag0, i);
|
|
||||||
if (!item || item == ignoreItem || !item.IsFitToSpellRequirements(spellInfo))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
item = GetUseableItemByPos(InventorySlots.Bag0, EquipmentSlot.OffHand);
|
||||||
|
if (item)
|
||||||
|
if (item != ignoreItem && item.IsFitToSpellRequirements(spellInfo))
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ItemClass.Armor:
|
||||||
|
{
|
||||||
|
if (!spellInfo.HasAttribute(SpellAttr8.ArmorSpecialization))
|
||||||
|
{
|
||||||
|
// most used check: shield only
|
||||||
|
if ((spellInfo.EquippedItemSubClassMask & (1 << (int)ItemSubClassArmor.Shield)) != 0)
|
||||||
|
{
|
||||||
|
Item item = GetUseableItemByPos(InventorySlots.Bag0, EquipmentSlot.OffHand);
|
||||||
|
if (item != null)
|
||||||
|
if (item != ignoreItem && item.IsFitToSpellRequirements(spellInfo))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// special check to filter things like Shield Wall, the aura is not permanent and must stay even without required item
|
||||||
|
if (!spellInfo.IsPassive())
|
||||||
|
{
|
||||||
|
foreach (var spellEffectInfo in spellInfo.GetEffects())
|
||||||
|
if (spellEffectInfo.IsAura())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tabard not have dependent spells
|
||||||
|
for (byte i = EquipmentSlot.Start; i < EquipmentSlot.MainHand; ++i)
|
||||||
|
{
|
||||||
|
Item item = GetUseableItemByPos(InventorySlots.Bag0, i);
|
||||||
|
if (item)
|
||||||
|
if (item != ignoreItem && item.IsFitToSpellRequirements(spellInfo))
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// requires item equipped in all armor slots
|
||||||
|
foreach (byte i in new[] { EquipmentSlot.Head, EquipmentSlot.Shoulders, EquipmentSlot.Chest, EquipmentSlot.Waist, EquipmentSlot.Legs, EquipmentSlot.Feet, EquipmentSlot.Wrist, EquipmentSlot.Hands })
|
||||||
|
{
|
||||||
|
Item item = GetUseableItemByPos(InventorySlots.Bag0, i);
|
||||||
|
if (!item || item == ignoreItem || !item.IsFitToSpellRequirements(spellInfo))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
Log.outError(LogFilter.Player, "HasItemFitToSpellRequirements: Not handled spell requirement for item class {0}", spellInfo.EquippedItemClass);
|
Log.outError(LogFilter.Player, "HasItemFitToSpellRequirements: Not handled spell requirement for item class {0}", spellInfo.EquippedItemClass);
|
||||||
break;
|
break;
|
||||||
@@ -1730,7 +1730,7 @@ namespace Game.Entities
|
|||||||
|
|
||||||
return SpellSchoolMask.Normal;
|
return SpellSchoolMask.Normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CastAllObtainSpells()
|
void CastAllObtainSpells()
|
||||||
{
|
{
|
||||||
int inventoryEnd = InventorySlots.ItemStart + GetInventorySlotCount();
|
int inventoryEnd = InventorySlots.ItemStart + GetInventorySlotCount();
|
||||||
@@ -1856,7 +1856,7 @@ namespace Game.Entities
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddTemporarySpell(uint spellId)
|
public void AddTemporarySpell(uint spellId)
|
||||||
{
|
{
|
||||||
var spell = m_spells.LookupByKey(spellId);
|
var spell = m_spells.LookupByKey(spellId);
|
||||||
@@ -1969,33 +1969,33 @@ namespace Game.Entities
|
|||||||
SetSkill(skillId, 0, 300, 300);
|
SetSkill(skillId, 0, 300, 300);
|
||||||
break;
|
break;
|
||||||
case SkillRangeType.Level:
|
case SkillRangeType.Level:
|
||||||
{
|
{
|
||||||
ushort skillValue = 1;
|
ushort skillValue = 1;
|
||||||
ushort maxValue = GetMaxSkillValueForLevel();
|
ushort maxValue = GetMaxSkillValueForLevel();
|
||||||
if (rcInfo.Flags.HasAnyFlag(SkillRaceClassInfoFlags.AlwaysMaxValue))
|
if (rcInfo.Flags.HasAnyFlag(SkillRaceClassInfoFlags.AlwaysMaxValue))
|
||||||
skillValue = maxValue;
|
skillValue = maxValue;
|
||||||
else if (GetClass() == Class.Deathknight)
|
else if (GetClass() == Class.Deathknight)
|
||||||
skillValue = (ushort)Math.Min(Math.Max(1, (GetLevel() - 1) * 5), maxValue);
|
skillValue = (ushort)Math.Min(Math.Max(1, (GetLevel() - 1) * 5), maxValue);
|
||||||
|
|
||||||
SetSkill(skillId, 0, skillValue, maxValue);
|
SetSkill(skillId, 0, skillValue, maxValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SkillRangeType.Mono:
|
case SkillRangeType.Mono:
|
||||||
SetSkill(skillId, 0, 1, 1);
|
SetSkill(skillId, 0, 1, 1);
|
||||||
break;
|
break;
|
||||||
case SkillRangeType.Rank:
|
case SkillRangeType.Rank:
|
||||||
{
|
{
|
||||||
SkillTiersEntry tier = Global.ObjectMgr.GetSkillTier(rcInfo.SkillTierID);
|
SkillTiersEntry tier = Global.ObjectMgr.GetSkillTier(rcInfo.SkillTierID);
|
||||||
ushort maxValue = (ushort)tier.Value[0];
|
ushort maxValue = (ushort)tier.Value[0];
|
||||||
ushort skillValue = 1;
|
ushort skillValue = 1;
|
||||||
if (rcInfo.Flags.HasAnyFlag(SkillRaceClassInfoFlags.AlwaysMaxValue))
|
if (rcInfo.Flags.HasAnyFlag(SkillRaceClassInfoFlags.AlwaysMaxValue))
|
||||||
skillValue = maxValue;
|
skillValue = maxValue;
|
||||||
else if (GetClass() == Class.Deathknight)
|
else if (GetClass() == Class.Deathknight)
|
||||||
skillValue = (ushort)Math.Min(Math.Max(1, (GetLevel() - 1) * 5), maxValue);
|
skillValue = (ushort)Math.Min(Math.Max(1, (GetLevel() - 1) * 5), maxValue);
|
||||||
|
|
||||||
SetSkill(skillId, 1, skillValue, maxValue);
|
SetSkill(skillId, 1, skillValue, maxValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2307,7 +2307,7 @@ namespace Game.Entities
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AddSpell(uint spellId, bool active, bool learning, bool dependent, bool disabled, bool loading = false, uint fromSkill = 0)
|
bool AddSpell(uint spellId, bool active, bool learning, bool dependent, bool disabled, bool loading = false, uint fromSkill = 0)
|
||||||
{
|
{
|
||||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, Difficulty.None);
|
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, Difficulty.None);
|
||||||
@@ -2435,18 +2435,18 @@ namespace Game.Entities
|
|||||||
case PlayerSpellState.Unchanged:
|
case PlayerSpellState.Unchanged:
|
||||||
return false;
|
return false;
|
||||||
case PlayerSpellState.Removed:
|
case PlayerSpellState.Removed:
|
||||||
{
|
{
|
||||||
m_spells.Remove(spellId);
|
m_spells.Remove(spellId);
|
||||||
state = PlayerSpellState.Changed;
|
state = PlayerSpellState.Changed;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// can be in case spell loading but learned at some previous spell loading
|
// can be in case spell loading but learned at some previous spell loading
|
||||||
if (!IsInWorld && !learning && !dependent_set)
|
if (!IsInWorld && !learning && !dependent_set)
|
||||||
spell.State = PlayerSpellState.Unchanged;
|
spell.State = PlayerSpellState.Unchanged;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2665,45 +2665,75 @@ namespace Game.Entities
|
|||||||
m_spellMods[(int)mod.op][(int)mod.type].Remove(mod);
|
m_spellMods[(int)mod.op][(int)mod.type].Remove(mod);
|
||||||
|
|
||||||
// Now, send spellmodifier packet
|
// Now, send spellmodifier packet
|
||||||
if (!IsLoading())
|
switch (mod.type)
|
||||||
{
|
{
|
||||||
ServerOpcodes opcode = (mod.type == SpellModType.Flat ? ServerOpcodes.SetFlatSpellModifier : ServerOpcodes.SetPctSpellModifier);
|
case SpellModType.Flat:
|
||||||
SetSpellModifier packet = new(opcode);
|
case SpellModType.Pct:
|
||||||
|
if (!IsLoading())
|
||||||
// @todo Implement sending of bulk modifiers instead of single
|
|
||||||
SpellModifierInfo spellMod = new();
|
|
||||||
|
|
||||||
spellMod.ModIndex = (byte)mod.op;
|
|
||||||
for (int eff = 0; eff < 128; ++eff)
|
|
||||||
{
|
|
||||||
FlagArray128 mask = new();
|
|
||||||
mask[eff / 32] = 1u << (eff %32);
|
|
||||||
if (mod.mask & mask)
|
|
||||||
{
|
{
|
||||||
SpellModifierData modData = new();
|
ServerOpcodes opcode = (mod.type == SpellModType.Flat ? ServerOpcodes.SetFlatSpellModifier : ServerOpcodes.SetPctSpellModifier);
|
||||||
if (mod.type == SpellModType.Flat)
|
SetSpellModifier packet = new(opcode);
|
||||||
{
|
|
||||||
modData.ModifierValue = 0.0f;
|
|
||||||
foreach (var spell in m_spellMods[(int)mod.op][(int)SpellModType.Flat])
|
|
||||||
if (spell.mask & mask)
|
|
||||||
modData.ModifierValue += spell.value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
modData.ModifierValue = 1.0f;
|
|
||||||
foreach (var spell in m_spellMods[(int)mod.op][(int)SpellModType.Pct])
|
|
||||||
if (spell.mask & mask)
|
|
||||||
modData.ModifierValue *= 1.0f + MathFunctions.CalculatePct(1.0f, spell.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
modData.ClassIndex = (byte)eff;
|
// @todo Implement sending of bulk modifiers instead of single
|
||||||
|
SpellModifierInfo spellMod = new();
|
||||||
|
|
||||||
spellMod.ModifierData.Add(modData);
|
spellMod.ModIndex = (byte)mod.op;
|
||||||
|
for (int eff = 0; eff < 128; ++eff)
|
||||||
|
{
|
||||||
|
FlagArray128 mask = new();
|
||||||
|
mask[eff / 32] = 1u << (eff % 32);
|
||||||
|
if ((mod as SpellModifierByClassMask).mask & mask)
|
||||||
|
{
|
||||||
|
SpellModifierData modData = new();
|
||||||
|
if (mod.type == SpellModType.Flat)
|
||||||
|
{
|
||||||
|
modData.ModifierValue = 0.0f;
|
||||||
|
foreach (SpellModifierByClassMask spell in m_spellMods[(int)mod.op][(int)SpellModType.Flat])
|
||||||
|
if (spell.mask & mask)
|
||||||
|
modData.ModifierValue += spell.value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
modData.ModifierValue = 1.0f;
|
||||||
|
foreach (SpellModifierByClassMask spell in m_spellMods[(int)mod.op][(int)SpellModType.Pct])
|
||||||
|
if (spell.mask & mask)
|
||||||
|
modData.ModifierValue *= 1.0f + MathFunctions.CalculatePct(1.0f, spell.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
modData.ClassIndex = (byte)eff;
|
||||||
|
|
||||||
|
spellMod.ModifierData.Add(modData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
packet.Modifiers.Add(spellMod);
|
||||||
|
|
||||||
|
SendPacket(packet);
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
packet.Modifiers.Add(spellMod);
|
case SpellModType.LabelFlat:
|
||||||
|
if (apply)
|
||||||
SendPacket(packet);
|
{
|
||||||
|
AddDynamicUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.SpellFlatModByLabel), (mod as SpellFlatModifierByLabel).value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int firstIndex = m_activePlayerData.SpellFlatModByLabel.FindIndex((mod as SpellFlatModifierByLabel).value);
|
||||||
|
if (firstIndex >= 0)
|
||||||
|
RemoveDynamicUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.SpellFlatModByLabel), firstIndex);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SpellModType.LabelPct:
|
||||||
|
if (apply)
|
||||||
|
{
|
||||||
|
AddDynamicUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.SpellPctModByLabel), (mod as SpellPctModifierByLabel).value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int firstIndex = m_activePlayerData.SpellPctModByLabel.FindIndex((mod as SpellPctModifierByLabel).value);
|
||||||
|
if (firstIndex >= 0)
|
||||||
|
RemoveDynamicUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.SpellPctModByLabel), firstIndex);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2736,7 +2766,7 @@ namespace Game.Entities
|
|||||||
|
|
||||||
basevalue = (float)(basevalue + totalflat) * totalmul;
|
basevalue = (float)(basevalue + totalflat) * totalmul;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GetSpellModValues<T>(SpellInfo spellInfo, SpellModOp op, Spell spell, T baseValue, ref int flat, ref float pct) where T : IComparable
|
public void GetSpellModValues<T>(SpellInfo spellInfo, SpellModOp op, Spell spell, T baseValue, ref int flat, ref float pct) where T : IComparable
|
||||||
{
|
{
|
||||||
flat = 0;
|
flat = 0;
|
||||||
@@ -2750,57 +2780,87 @@ namespace Game.Entities
|
|||||||
{
|
{
|
||||||
// special case, if a mod makes spell instant, only consume that mod
|
// special case, if a mod makes spell instant, only consume that mod
|
||||||
case SpellModOp.ChangeCastTime:
|
case SpellModOp.ChangeCastTime:
|
||||||
|
{
|
||||||
|
SpellModifier modInstantSpell = null;
|
||||||
|
foreach (SpellModifierByClassMask mod in m_spellMods[(int)op][(int)SpellModType.Pct])
|
||||||
{
|
{
|
||||||
SpellModifier modInstantSpell = null;
|
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
||||||
foreach (SpellModifier mod in m_spellMods[(int)op][(int)SpellModType.Pct])
|
continue;
|
||||||
|
|
||||||
|
if (baseValue.CompareTo(10000) < 0 && mod.value <= -100)
|
||||||
|
{
|
||||||
|
modInstantSpell = mod;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modInstantSpell == null)
|
||||||
|
{
|
||||||
|
foreach (SpellPctModifierByLabel mod in m_spellMods[(int)op][(int)SpellModType.LabelPct])
|
||||||
{
|
{
|
||||||
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (baseValue.CompareTo(10000) < 0 && mod.value <= -100)
|
if (baseValue.CompareTo(10000) < 0 && mod.value.ModifierValue <= -1.0f)
|
||||||
{
|
{
|
||||||
modInstantSpell = mod;
|
modInstantSpell = mod;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modInstantSpell != null)
|
|
||||||
{
|
|
||||||
ApplyModToSpell(modInstantSpell, spell);
|
|
||||||
pct = 0.0f;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (modInstantSpell != null)
|
||||||
|
{
|
||||||
|
ApplyModToSpell(modInstantSpell, spell);
|
||||||
|
pct = 0.0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
// special case if two mods apply 100% critical chance, only consume one
|
// special case if two mods apply 100% critical chance, only consume one
|
||||||
case SpellModOp.CritChance:
|
case SpellModOp.CritChance:
|
||||||
|
{
|
||||||
|
SpellModifier modCritical = null;
|
||||||
|
foreach (SpellModifierByClassMask mod in m_spellMods[(int)op][(int)SpellModType.Flat])
|
||||||
{
|
{
|
||||||
SpellModifier modCritical = null;
|
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
||||||
foreach (SpellModifier mod in m_spellMods[(int)op][(int)SpellModType.Flat])
|
continue;
|
||||||
|
|
||||||
|
if (mod.value >= 100)
|
||||||
|
{
|
||||||
|
modCritical = mod;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modCritical == null)
|
||||||
|
{
|
||||||
|
foreach (SpellFlatModifierByLabel mod in m_spellMods[(int)op][(int)SpellModType.LabelFlat])
|
||||||
{
|
{
|
||||||
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (mod.value >= 100)
|
if (mod.value.ModifierValue >= 100)
|
||||||
{
|
{
|
||||||
modCritical = mod;
|
modCritical = mod;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modCritical != null)
|
|
||||||
{
|
|
||||||
ApplyModToSpell(modCritical, spell);
|
|
||||||
flat = 100;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (modCritical != null)
|
||||||
|
{
|
||||||
|
ApplyModToSpell(modCritical, spell);
|
||||||
|
flat = 100;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (SpellModifier mod in m_spellMods[(int)op][(int)SpellModType.Flat])
|
foreach (SpellModifierByClassMask mod in m_spellMods[(int)op][(int)SpellModType.Flat])
|
||||||
{
|
{
|
||||||
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
||||||
continue;
|
continue;
|
||||||
@@ -2809,7 +2869,16 @@ namespace Game.Entities
|
|||||||
ApplyModToSpell(mod, spell);
|
ApplyModToSpell(mod, spell);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (SpellModifier mod in m_spellMods[(int)op][(int)SpellModType.Pct])
|
foreach (SpellFlatModifierByLabel mod in m_spellMods[(int)op][(int)SpellModType.LabelFlat])
|
||||||
|
{
|
||||||
|
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
flat += mod.value.ModifierValue;
|
||||||
|
ApplyModToSpell(mod, spell);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (SpellModifierByClassMask mod in m_spellMods[(int)op][(int)SpellModType.Pct])
|
||||||
{
|
{
|
||||||
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
||||||
continue;
|
continue;
|
||||||
@@ -2828,6 +2897,26 @@ namespace Game.Entities
|
|||||||
pct *= 1.0f + MathFunctions.CalculatePct(1.0f, mod.value);
|
pct *= 1.0f + MathFunctions.CalculatePct(1.0f, mod.value);
|
||||||
ApplyModToSpell(mod, spell);
|
ApplyModToSpell(mod, spell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (SpellPctModifierByLabel mod in m_spellMods[(int)op][(int)SpellModType.LabelPct])
|
||||||
|
{
|
||||||
|
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// skip percent mods for null basevalue (most important for spell mods with charges)
|
||||||
|
if (baseValue + (dynamic)flat == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// special case (skip > 10sec spell casts for instant cast setting)
|
||||||
|
if (op == SpellModOp.ChangeCastTime)
|
||||||
|
{
|
||||||
|
if (baseValue.CompareTo(10000) > 0 && mod.value.ModifierValue <= -1.0f)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pct *= mod.value.ModifierValue;
|
||||||
|
ApplyModToSpell(mod, spell);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsAffectedBySpellmod(SpellInfo spellInfo, SpellModifier mod, Spell spell)
|
bool IsAffectedBySpellmod(SpellInfo spellInfo, SpellModifier mod, Spell spell)
|
||||||
@@ -2883,13 +2972,13 @@ namespace Game.Entities
|
|||||||
pctData.ClassIndex = j;
|
pctData.ClassIndex = j;
|
||||||
pctData.ModifierValue = 1.0f;
|
pctData.ModifierValue = 1.0f;
|
||||||
|
|
||||||
foreach (SpellModifier mod in m_spellMods[i][(int)SpellModType.Flat])
|
foreach (SpellModifierByClassMask mod in m_spellMods[i][(int)SpellModType.Flat])
|
||||||
{
|
{
|
||||||
if (mod.mask & mask)
|
if (mod.mask & mask)
|
||||||
flatData.ModifierValue += mod.value;
|
flatData.ModifierValue += mod.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (SpellModifier mod in m_spellMods[i][(int)SpellModType.Pct])
|
foreach (SpellModifierByClassMask mod in m_spellMods[i][(int)SpellModType.Pct])
|
||||||
{
|
{
|
||||||
if (mod.mask & mask)
|
if (mod.mask & mask)
|
||||||
pctData.ModifierValue *= 1.0f + MathFunctions.CalculatePct(1.0f, mod.value);
|
pctData.ModifierValue *= 1.0f + MathFunctions.CalculatePct(1.0f, mod.value);
|
||||||
@@ -2938,7 +3027,7 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UpdateItemSetAuras(bool formChange = false)
|
void UpdateItemSetAuras(bool formChange = false)
|
||||||
{
|
{
|
||||||
// item set bonuses not dependent from item broken state
|
// item set bonuses not dependent from item broken state
|
||||||
for (int setindex = 0; setindex < ItemSetEff.Count; ++setindex)
|
for (int setindex = 0; setindex < ItemSetEff.Count; ++setindex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -259,14 +259,43 @@ namespace Game.Spells
|
|||||||
case AuraType.AddPctModifier:
|
case AuraType.AddPctModifier:
|
||||||
if (m_spellmod == null)
|
if (m_spellmod == null)
|
||||||
{
|
{
|
||||||
m_spellmod = new SpellModifier(GetBase());
|
SpellModifierByClassMask spellmod = new SpellModifierByClassMask(GetBase());
|
||||||
m_spellmod.op = (SpellModOp)GetMiscValue();
|
spellmod.op = (SpellModOp)GetMiscValue();
|
||||||
|
|
||||||
m_spellmod.type = GetAuraType() == AuraType.AddPctModifier ? SpellModType.Pct : SpellModType.Flat;
|
spellmod.type = GetAuraType() == AuraType.AddPctModifier ? SpellModType.Pct : SpellModType.Flat;
|
||||||
m_spellmod.spellId = GetId();
|
spellmod.spellId = GetId();
|
||||||
m_spellmod.mask = GetSpellEffectInfo().SpellClassMask;
|
spellmod.mask = GetSpellEffectInfo().SpellClassMask;
|
||||||
|
m_spellmod = spellmod;
|
||||||
}
|
}
|
||||||
m_spellmod.value = GetAmount();
|
(m_spellmod as SpellModifierByClassMask).value = GetAmount();
|
||||||
|
break;
|
||||||
|
case AuraType.AddFlatModifierBySpellLabel:
|
||||||
|
if (m_spellmod == null)
|
||||||
|
{
|
||||||
|
SpellFlatModifierByLabel spellmod = new SpellFlatModifierByLabel(GetBase());
|
||||||
|
spellmod.op = (SpellModOp)GetMiscValue();
|
||||||
|
|
||||||
|
spellmod.type = SpellModType.LabelFlat;
|
||||||
|
spellmod.spellId = GetId();
|
||||||
|
spellmod.value.ModIndex = GetMiscValue();
|
||||||
|
spellmod.value.LabelID = GetMiscValueB();
|
||||||
|
m_spellmod = spellmod;
|
||||||
|
}
|
||||||
|
(m_spellmod as SpellFlatModifierByLabel).value.ModifierValue = GetAmount();
|
||||||
|
break;
|
||||||
|
case AuraType.AddPctModifierBySpellLabel:
|
||||||
|
if (m_spellmod == null)
|
||||||
|
{
|
||||||
|
SpellPctModifierByLabel spellmod = new SpellPctModifierByLabel(GetBase());
|
||||||
|
spellmod.op = (SpellModOp)GetMiscValue();
|
||||||
|
|
||||||
|
spellmod.type = SpellModType.LabelPct;
|
||||||
|
spellmod.spellId = GetId();
|
||||||
|
spellmod.value.ModIndex = GetMiscValue();
|
||||||
|
spellmod.value.LabelID = GetMiscValueB();
|
||||||
|
m_spellmod = spellmod;
|
||||||
|
}
|
||||||
|
(m_spellmod as SpellPctModifierByLabel).value.ModifierValue = 1.0f + MathFunctions.CalculatePct(1.0f, GetAmount());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -8129,20 +8129,42 @@ namespace Game.Spells
|
|||||||
{
|
{
|
||||||
op = SpellModOp.HealingAndDamage;
|
op = SpellModOp.HealingAndDamage;
|
||||||
type = SpellModType.Flat;
|
type = SpellModType.Flat;
|
||||||
value = 0;
|
|
||||||
mask = new FlagArray128();
|
|
||||||
spellId = 0;
|
spellId = 0;
|
||||||
ownerAura = _ownerAura;
|
ownerAura = _ownerAura;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpellModOp op { get; set; }
|
public SpellModOp op { get; set; }
|
||||||
public SpellModType type { get; set; }
|
public SpellModType type { get; set; }
|
||||||
public int value { get; set; }
|
|
||||||
public FlagArray128 mask { get; set; }
|
|
||||||
public uint spellId { get; set; }
|
public uint spellId { get; set; }
|
||||||
public Aura ownerAura { get; set; }
|
public Aura ownerAura { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class SpellModifierByClassMask : SpellModifier
|
||||||
|
{
|
||||||
|
public SpellModifierByClassMask(Aura _ownerAura) : base(_ownerAura)
|
||||||
|
{
|
||||||
|
value = 0;
|
||||||
|
mask = new FlagArray128();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int value;
|
||||||
|
public FlagArray128 mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SpellFlatModifierByLabel : SpellModifier
|
||||||
|
{
|
||||||
|
public SpellFlatModByLabel value = new();
|
||||||
|
|
||||||
|
public SpellFlatModifierByLabel(Aura _ownerAura) : base(_ownerAura) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
class SpellPctModifierByLabel : SpellModifier
|
||||||
|
{
|
||||||
|
public SpellPctModByLabel value = new();
|
||||||
|
|
||||||
|
public SpellPctModifierByLabel(Aura _ownerAura) : base(_ownerAura) { }
|
||||||
|
}
|
||||||
|
|
||||||
public class WorldObjectSpellTargetCheck : ICheck<WorldObject>
|
public class WorldObjectSpellTargetCheck : ICheck<WorldObject>
|
||||||
{
|
{
|
||||||
internal WorldObject _caster;
|
internal WorldObject _caster;
|
||||||
|
|||||||
@@ -660,9 +660,22 @@ namespace Game.Spells
|
|||||||
if (affectSpell == null)
|
if (affectSpell == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// TEMP: dont use IsAffected - !familyName and !familyFlags are not valid options for spell mods
|
switch (mod.type)
|
||||||
// TODO: investigate if the !familyName and !familyFlags conditions are even valid for all other (nonmod) uses of SpellInfo::IsAffected
|
{
|
||||||
return affectSpell.SpellFamilyName == SpellFamilyName && mod.mask & SpellFamilyFlags;
|
case SpellModType.Flat:
|
||||||
|
case SpellModType.Pct:
|
||||||
|
// TEMP: dont use IsAffected - !familyName and !familyFlags are not valid options for spell mods
|
||||||
|
// TODO: investigate if the !familyName and !familyFlags conditions are even valid for all other (nonmod) uses of SpellInfo::IsAffected
|
||||||
|
return affectSpell.SpellFamilyName == SpellFamilyName && (mod as SpellModifierByClassMask).mask & SpellFamilyFlags;
|
||||||
|
case SpellModType.LabelFlat:
|
||||||
|
return HasLabel((uint)(mod as SpellFlatModifierByLabel).value.LabelID);
|
||||||
|
case SpellModType.LabelPct:
|
||||||
|
return HasLabel((uint)(mod as SpellPctModifierByLabel).value.LabelID);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanPierceImmuneAura(SpellInfo auraSpellInfo)
|
public bool CanPierceImmuneAura(SpellInfo auraSpellInfo)
|
||||||
|
|||||||
@@ -1421,7 +1421,8 @@ namespace Game.Entities
|
|||||||
if (!spellEffectInfo.IsAura())
|
if (!spellEffectInfo.IsAura())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (spellEffectInfo.ApplyAuraName == AuraType.AddPctModifier || spellEffectInfo.ApplyAuraName == AuraType.AddFlatModifier)
|
if (spellEffectInfo.ApplyAuraName == AuraType.AddPctModifier || spellEffectInfo.ApplyAuraName == AuraType.AddFlatModifier
|
||||||
|
|| spellEffectInfo.ApplyAuraName == AuraType.AddPctModifierBySpellLabel || spellEffectInfo.ApplyAuraName == AuraType.AddFlatModifierBySpellLabel)
|
||||||
{
|
{
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -598,13 +598,14 @@ namespace Scripts.Spells.Druid
|
|||||||
{
|
{
|
||||||
if (spellMod == null)
|
if (spellMod == null)
|
||||||
{
|
{
|
||||||
spellMod = new SpellModifier(GetAura());
|
SpellModifierByClassMask mod = new(GetAura());
|
||||||
spellMod.op = SpellModOp.PeriodicHealingAndDamage;
|
mod.op = SpellModOp.PeriodicHealingAndDamage;
|
||||||
spellMod.type = SpellModType.Flat;
|
mod.type = SpellModType.Flat;
|
||||||
spellMod.spellId = GetId();
|
mod.spellId = GetId();
|
||||||
spellMod.mask = aurEff.GetSpellEffectInfo().SpellClassMask;
|
mod.mask = aurEff.GetSpellEffectInfo().SpellClassMask;
|
||||||
|
spellMod = mod;
|
||||||
}
|
}
|
||||||
spellMod.value = aurEff.GetAmount() / 7;
|
(spellMod as SpellModifierByClassMask).value = aurEff.GetAmount() / 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Register()
|
public override void Register()
|
||||||
|
|||||||
Reference in New Issue
Block a user