Core/Spells: rework part 5: GameObject casting

Port From (https://github.com/TrinityCore/TrinityCore/commit/962f6d7988b9003e550f6745be7cff812e9d8efa)
This commit is contained in:
hondacrx
2021-08-29 18:27:08 -04:00
parent e97ffa304d
commit 949d4806c5
39 changed files with 5236 additions and 4781 deletions
+5 -4
View File
@@ -399,10 +399,12 @@ namespace Game.AI
public virtual void JustUnregisteredAreaTrigger(AreaTrigger areaTrigger) { }
// Called when hit by a spell
public virtual void SpellHit(Unit caster, SpellInfo spell) { }
public virtual void SpellHit(Unit caster, SpellInfo spellInfo) { }
public virtual void SpellHit(GameObject caster, SpellInfo spellInfo) { }
// Called when spell hits a target
public virtual void SpellHitTarget(Unit target, SpellInfo spell) { }
public virtual void SpellHitTarget(Unit target, SpellInfo spellInfo) { }
public virtual void SpellHitTarget(GameObject target, SpellInfo spellInfo) { }
public virtual bool IsEscorted() { return false; }
@@ -459,7 +461,7 @@ namespace Game.AI
public virtual void QuestReward(Player player, Quest quest, LootItemType type, uint opt) { }
/// == Waypoints system =============================
///
public virtual void WaypointPathStarted(uint pathId) { }
public virtual void WaypointStarted(uint nodeId, uint pathId) { }
@@ -479,7 +481,6 @@ namespace Game.AI
// Object destruction is handled by Unit::RemoveCharmedBy
public virtual PlayerAI GetAIForCharmedPlayer(Player who) { return null; }
/// <summary>
/// Should return true if the NPC is target of an escort quest
/// If onlyIfActive is set, should return true only if the escort quest is currently active
+10 -3
View File
@@ -81,8 +81,8 @@ namespace Game.AI
// prevents achievement tracking if returning true
public virtual bool OnReportUse(Player player) { return false; }
public virtual void Destroyed(Player player, uint eventId) { }
public virtual void Damaged(Player player, uint eventId) { }
public virtual void Destroyed(WorldObject attacker, uint eventId) { }
public virtual void Damaged(WorldObject attacker, uint eventId) { }
public virtual void SetData64(uint id, ulong value) { }
public virtual ulong GetData64(uint id) { return 0; }
@@ -93,6 +93,13 @@ namespace Game.AI
public virtual void OnLootStateChanged(uint state, Unit unit) { }
public virtual void OnStateChanged(GameObjectState state) { }
public virtual void EventInform(uint eventId) { }
public virtual void SpellHit(Unit unit, SpellInfo spellInfo) { }
// Called when hit by a spell
public virtual void SpellHit(Unit caster, SpellInfo spellInfo) { }
public virtual void SpellHit(GameObject caster, SpellInfo spellInfo) { }
// Called when spell hits a target
public virtual void SpellHitTarget(Unit target, SpellInfo spellInfo) { }
public virtual void SpellHitTarget(GameObject target, SpellInfo spellInfo) { }
}
}
-30
View File
@@ -373,30 +373,6 @@ namespace Game.AI
_isCombatMovementAllowed = allowMovement;
}
// Called at any Damage from any attacker (before damage apply)
public override void DamageTaken(Unit attacker, ref uint damage) { }
//Called at creature death
public override void JustDied(Unit killer) { }
//Called at creature killing another unit
public override void KilledUnit(Unit victim) { }
// Called when the creature summon successfully other creature
public override void JustSummoned(Creature summon) { }
// Called when a summoned creature is despawned
public override void SummonedCreatureDespawn(Creature summon) { }
// Called when hit by a spell
public override void SpellHit(Unit caster, SpellInfo spell) { }
// Called when spell hits a target
public override void SpellHitTarget(Unit target, SpellInfo spell) { }
// Called when AI is temporarily replaced or put back when possess is applied or removed
public virtual void OnPossess(bool apply) { }
public static Creature GetClosestCreatureWithEntry(WorldObject source, uint entry, float maxSearchRange, bool alive = true)
{
return source.FindNearestCreature(entry, maxSearchRange, alive);
@@ -407,12 +383,6 @@ namespace Game.AI
return source.FindNearestGameObject(entry, maxSearchRange);
}
//Called at creature reset either by death or evade
public override void Reset() { }
//Called at creature aggro either by MoveInLOS or Attack Start
public override void JustEngagedWith(Unit victim) { }
public bool HealthBelowPct(int pct) { return me.HealthBelowPct(pct); }
public bool HealthAbovePct(int pct) { return me.HealthAbovePct(pct); }
+2 -2
View File
@@ -1118,9 +1118,9 @@ namespace Game.AI
GetScript().ProcessEventsFor(SmartEvents.RewardQuest, player, quest.Id, opt, false, null, me);
}
public override void Destroyed(Player player, uint eventId)
public override void Destroyed(WorldObject attacker, uint eventId)
{
GetScript().ProcessEventsFor(SmartEvents.Death, player, eventId, 0, false, null, me);
GetScript().ProcessEventsFor(SmartEvents.Death, attacker != null ? attacker.ToUnit() : null, eventId, 0, false, null, me);
}
public override void SetData(uint id, uint value) { SetData(id, value, null); }
+1 -1
View File
@@ -490,7 +490,7 @@ namespace Game.AI
_me.CastSpell(target.ToUnit(), e.Action.cast.spell, new CastSpellExtraArgs(triggerFlag));
}
else if (_go)
_go.CastSpell(target.ToUnit(), e.Action.cast.spell, triggerFlag);
_go.CastSpell(target.ToUnit(), e.Action.cast.spell, new CastSpellExtraArgs(triggerFlag));
}
else
Log.outDebug(LogFilter.ScriptsAi, "Spell {0} not casted because it has flag SMARTCAST_AURA_NOT_PRESENT and the target (Guid: {1} Entry: {2} Type: {3}) already has the aura",
+94 -70
View File
@@ -55,9 +55,9 @@ namespace Game.Achievements
/// <param name="miscValue1"></param>
/// <param name="miscValue2"></param>
/// <param name="miscValue3"></param>
/// <param name="unit"></param>
/// <param name="refe"></param>
/// <param name="referencePlayer"></param>
public void UpdateCriteria(CriteriaTypes type, ulong miscValue1 = 0, ulong miscValue2 = 0, ulong miscValue3 = 0, Unit unit = null, Player referencePlayer = null)
public void UpdateCriteria(CriteriaTypes type, ulong miscValue1 = 0, ulong miscValue2 = 0, ulong miscValue3 = 0, WorldObject refe = null, Player referencePlayer = null)
{
if (type >= CriteriaTypes.TotalTypes)
{
@@ -84,13 +84,13 @@ namespace Game.Achievements
foreach (Criteria criteria in criteriaList)
{
List<CriteriaTree> trees = Global.CriteriaMgr.GetCriteriaTreesByCriteria(criteria.Id);
if (!CanUpdateCriteria(criteria, trees, miscValue1, miscValue2, miscValue3, unit, referencePlayer))
if (!CanUpdateCriteria(criteria, trees, miscValue1, miscValue2, miscValue3, refe, referencePlayer))
continue;
// requirements not found in the dbc
CriteriaDataSet data = Global.CriteriaMgr.GetCriteriaDataSet(criteria);
if (data != null)
if (!data.Meets(referencePlayer, unit, (uint)miscValue1, (uint)miscValue2))
if (!data.Meets(referencePlayer, refe, (uint)miscValue1, (uint)miscValue2))
continue;
switch (type)
@@ -859,7 +859,7 @@ namespace Game.Achievements
return false;
}
bool CanUpdateCriteria(Criteria criteria, List<CriteriaTree> trees, ulong miscValue1, ulong miscValue2, ulong miscValue3, Unit unit, Player referencePlayer)
bool CanUpdateCriteria(Criteria criteria, List<CriteriaTree> trees, ulong miscValue1, ulong miscValue2, ulong miscValue3, WorldObject refe, Player referencePlayer)
{
if (Global.DisableMgr.IsDisabledFor(DisableType.Criteria, criteria.Id, null))
{
@@ -880,13 +880,13 @@ namespace Game.Achievements
if (!treeRequirementPassed)
return false;
if (!RequirementsSatisfied(criteria, miscValue1, miscValue2, miscValue3, unit, referencePlayer))
if (!RequirementsSatisfied(criteria, miscValue1, miscValue2, miscValue3, refe, referencePlayer))
{
Log.outTrace(LogFilter.Achievement, "CanUpdateCriteria: (Id: {0} Type {1}) Requirements not satisfied", criteria.Id, criteria.Entry.Type);
return false;
}
if (criteria.Modifier != null && !ModifierTreeSatisfied(criteria.Modifier, miscValue1, miscValue2, unit, referencePlayer))
if (criteria.Modifier != null && !ModifierTreeSatisfied(criteria.Modifier, miscValue1, miscValue2, refe, referencePlayer))
{
Log.outTrace(LogFilter.Achievement, "CanUpdateCriteria: (Id: {0} Type {1}) Requirements have not been satisfied", criteria.Id, criteria.Entry.Type);
return false;
@@ -923,7 +923,7 @@ namespace Game.Achievements
return true;
}
bool RequirementsSatisfied(Criteria criteria, ulong miscValue1, ulong miscValue2, ulong miscValue3, Unit unit, Player referencePlayer)
bool RequirementsSatisfied(Criteria criteria, ulong miscValue1, ulong miscValue2, ulong miscValue3, WorldObject refe, Player referencePlayer)
{
switch (criteria.Entry.Type)
{
@@ -1034,7 +1034,7 @@ namespace Game.Achievements
break;
}
case CriteriaTypes.KilledByPlayer:
if (miscValue1 == 0 || !unit || !unit.IsTypeId(TypeId.Player))
if (miscValue1 == 0 || !refe || !refe.IsTypeId(TypeId.Player))
return false;
break;
case CriteriaTypes.DeathsFrom:
@@ -1057,7 +1057,7 @@ namespace Game.Achievements
}
CriteriaDataSet data = Global.CriteriaMgr.GetCriteriaDataSet(criteria);
if (data != null)
if (!data.Meets(referencePlayer, unit))
if (!data.Meets(referencePlayer, refe))
return false;
break;
}
@@ -1160,7 +1160,7 @@ namespace Game.Achievements
return false;
// map specific case (BG in fact) expected player targeted damage/heal
if (!unit || !unit.IsTypeId(TypeId.Player))
if (!refe || !refe.IsTypeId(TypeId.Player))
return false;
}
break;
@@ -1225,24 +1225,24 @@ namespace Game.Achievements
return true;
}
public bool ModifierTreeSatisfied(ModifierTreeNode tree, ulong miscValue1, ulong miscValue2, Unit unit, Player referencePlayer)
public bool ModifierTreeSatisfied(ModifierTreeNode tree, ulong miscValue1, ulong miscValue2, WorldObject refe, Player referencePlayer)
{
switch ((ModifierTreeOperator)tree.Entry.Operator)
{
case ModifierTreeOperator.SingleTrue:
return tree.Entry.Type != 0 && ModifierSatisfied(tree.Entry, miscValue1, miscValue2, unit, referencePlayer);
return tree.Entry.Type != 0 && ModifierSatisfied(tree.Entry, miscValue1, miscValue2, refe, referencePlayer);
case ModifierTreeOperator.SingleFalse:
return tree.Entry.Type != 0 && !ModifierSatisfied(tree.Entry, miscValue1, miscValue2, unit, referencePlayer);
return tree.Entry.Type != 0 && !ModifierSatisfied(tree.Entry, miscValue1, miscValue2, refe, referencePlayer);
case ModifierTreeOperator.All:
foreach (ModifierTreeNode node in tree.Children)
if (!ModifierTreeSatisfied(node, miscValue1, miscValue2, unit, referencePlayer))
if (!ModifierTreeSatisfied(node, miscValue1, miscValue2, refe, referencePlayer))
return false;
return true;
case ModifierTreeOperator.Some:
{
sbyte requiredAmount = Math.Max(tree.Entry.Amount, (sbyte)1);
foreach (ModifierTreeNode node in tree.Children)
if (ModifierTreeSatisfied(node, miscValue1, miscValue2, unit, referencePlayer))
if (ModifierTreeSatisfied(node, miscValue1, miscValue2, refe, referencePlayer))
if (--requiredAmount == 0)
return true;
@@ -1255,7 +1255,7 @@ namespace Game.Achievements
return false;
}
bool ModifierSatisfied(ModifierTreeRecord modifier, ulong miscValue1, ulong miscValue2, Unit unit, Player referencePlayer)
bool ModifierSatisfied(ModifierTreeRecord modifier, ulong miscValue1, ulong miscValue2, WorldObject refe, Player referencePlayer)
{
uint reqValue = modifier.Asset;
int secondaryAsset = modifier.SecondaryAsset;
@@ -1286,19 +1286,19 @@ namespace Game.Achievements
break;
}
case ModifierTreeType.TargetCreatureId: // 4
if (unit == null || unit.GetEntry() != reqValue)
if (refe == null || refe.GetEntry() != reqValue)
return false;
break;
case ModifierTreeType.TargetIsPlayer: // 5
if (unit == null || !unit.IsTypeId(TypeId.Player))
if (refe == null || !refe.IsTypeId(TypeId.Player))
return false;
break;
case ModifierTreeType.TargetIsDead: // 6
if (unit == null || unit.IsAlive())
if (refe == null || !refe.IsUnit() || refe.ToUnit().IsAlive())
return false;
break;
case ModifierTreeType.TargetIsOppositeFaction: // 7
if (unit == null || !referencePlayer.IsHostileTo(unit))
if (refe == null || !referencePlayer.IsHostileTo(refe))
return false;
break;
case ModifierTreeType.PlayerHasAura: // 8
@@ -1310,15 +1310,15 @@ namespace Game.Achievements
return false;
break;
case ModifierTreeType.TargetHasAura: // 10
if (unit == null || !unit.HasAura(reqValue))
if (refe == null || !refe.IsUnit() || !refe.ToUnit().HasAura(reqValue))
return false;
break;
case ModifierTreeType.TargetHasAuraEffect: // 11
if (unit == null || !unit.HasAuraType((AuraType)reqValue))
if (refe == null || !refe.IsUnit() || !refe.ToUnit().HasAuraType((AuraType)reqValue))
return false;
break;
case ModifierTreeType.TargetHasAuraState: // 12
if (unit == null || !unit.HasAuraState((AuraStateType)reqValue))
if (refe == null || !refe.IsUnit() || !refe.ToUnit().HasAuraState((AuraStateType)reqValue))
return false;
break;
case ModifierTreeType.PlayerHasAuraState: // 13
@@ -1355,10 +1355,10 @@ namespace Game.Achievements
}
case ModifierTreeType.TargetIsInArea: // 18
{
if (unit == null)
if (refe == null)
return false;
uint zoneId, areaId;
unit.GetZoneAndAreaId(out zoneId, out areaId);
refe.GetZoneAndAreaId(out zoneId, out areaId);
if (zoneId != reqValue && areaId != reqValue)
return false;
break;
@@ -1375,15 +1375,15 @@ namespace Game.Achievements
break;
}
case ModifierTreeType.PlayerToTargetLevelDeltaGreaterThan: // 21
if (unit == null || referencePlayer.GetLevel() < unit.GetLevel() + reqValue)
if (refe == null || !refe.IsUnit() || referencePlayer.GetLevel() < refe.ToUnit().GetLevel() + reqValue)
return false;
break;
case ModifierTreeType.TargetToPlayerLevelDeltaGreaterThan: // 22
if (!unit || referencePlayer.GetLevel() + reqValue < unit.GetLevel())
if (!refe || !refe.IsUnit() || referencePlayer.GetLevel() + reqValue < refe.ToUnit().GetLevel())
return false;
break;
case ModifierTreeType.PlayerLevelEqualTargetLevel: // 23
if (!unit || referencePlayer.GetLevel() != unit.GetLevel())
if (!refe || !refe.IsUnit() || referencePlayer.GetLevel() != refe.ToUnit().GetLevel())
return false;
break;
case ModifierTreeType.PlayerInArenaWithTeamSize: // 24
@@ -1402,11 +1402,11 @@ namespace Game.Achievements
return false;
break;
case ModifierTreeType.TargetRace: // 27
if (unit == null || !unit.IsTypeId(TypeId.Player) || (uint)unit.GetRace() != reqValue)
if (refe == null || !refe.IsUnit() || refe.ToUnit().GetRace() != (Race)reqValue)
return false;
break;
case ModifierTreeType.TargetClass: // 28
if (unit == null || !unit.IsTypeId(TypeId.Player) || (uint)unit.GetClass() != reqValue)
if (refe == null || !refe.IsUnit() || refe.ToUnit().GetClass() != (Class)reqValue)
return false;
break;
case ModifierTreeType.LessThanTappers: // 29
@@ -1415,18 +1415,18 @@ namespace Game.Achievements
break;
case ModifierTreeType.CreatureType: // 30
{
if (unit == null)
if (refe == null)
return false;
if (!unit.IsTypeId(TypeId.Unit) || (uint)unit.GetCreatureType() != reqValue)
if (!refe.IsUnit() || refe.ToUnit().GetCreatureType() != (CreatureType)reqValue)
return false;
break;
}
case ModifierTreeType.CreatureFamily: // 31
{
if (!unit)
if (!refe)
return false;
if (unit.GetTypeId() != TypeId.Unit || unit.ToCreature().GetCreatureTemplate().Family != (CreatureFamily)reqValue)
if (!refe.IsCreature() || refe.ToCreature().GetCreatureTemplate().Family != (CreatureFamily)reqValue)
return false;
break;
}
@@ -1464,7 +1464,7 @@ namespace Game.Achievements
return false;
break;
case ModifierTreeType.TargetLevelEqual: // 40
if (unit == null || unit.GetLevelForTarget(referencePlayer) != reqValue)
if (refe == null || refe.GetLevelForTarget(referencePlayer) != reqValue)
return false;
break;
case ModifierTreeType.PlayerIsInZone: // 41
@@ -1480,9 +1480,9 @@ namespace Game.Achievements
}
case ModifierTreeType.TargetIsInZone: // 42
{
if (!unit)
if (!refe)
return false;
uint zoneId = unit.GetAreaId();
uint zoneId = refe.GetAreaId();
AreaTableRecord areaEntry = CliDB.AreaTableStorage.LookupByKey(zoneId);
if (areaEntry != null)
if (areaEntry.Flags.HasFlag(AreaFlags.Unk9))
@@ -1504,15 +1504,15 @@ namespace Game.Achievements
return false;
break;
case ModifierTreeType.TargetHealthBelowPercent: // 46
if (unit == null || unit.GetHealthPct() >= (float)reqValue)
if (refe == null || !refe.IsUnit() || refe.ToUnit().GetHealthPct() > reqValue)
return false;
break;
case ModifierTreeType.TargetHealthAbovePercent: // 47
if (!unit || unit.GetHealthPct() < (float)reqValue)
if (!refe || !refe.IsUnit() || refe.ToUnit().GetHealthPct() < reqValue)
return false;
break;
case ModifierTreeType.TargetHealthEqualsPercent: // 48
if (!unit || unit.GetHealthPct() != (float)reqValue)
if (!refe || !refe.IsUnit() || refe.ToUnit().GetHealthPct() != reqValue)
return false;
break;
case ModifierTreeType.PlayerHealthBelowValue: // 49
@@ -1528,24 +1528,24 @@ namespace Game.Achievements
return false;
break;
case ModifierTreeType.TargetHealthBelowValue: // 52
if (!unit || unit.GetHealth() > reqValue)
if (!refe || !refe.IsUnit() || refe.ToUnit().GetHealth() > reqValue)
return false;
break;
case ModifierTreeType.TargetHealthAboveValue: // 53
if (!unit || unit.GetHealth() < reqValue)
if (!refe || !refe.IsUnit() || refe.ToUnit().GetHealth() < reqValue)
return false;
break;
case ModifierTreeType.TargetHealthEqualsValue: // 54
if (!unit || unit.GetHealth() != reqValue)
if (!refe || !refe.IsUnit() || refe.ToUnit().GetHealth() != reqValue)
return false;
break;
case ModifierTreeType.TargetIsPlayerAndMeetsCondition: // 55
{
if (unit == null || !unit.IsPlayer())
if (refe == null || !refe.IsPlayer())
return false;
PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(reqValue);
if (playerCondition == null || !ConditionManager.IsPlayerMeetingCondition(unit.ToPlayer(), playerCondition))
if (playerCondition == null || !ConditionManager.IsPlayerMeetingCondition(refe.ToPlayer(), playerCondition))
return false;
break;
}
@@ -1606,7 +1606,7 @@ namespace Game.Achievements
return false;
break;
case ModifierTreeType.TargetLevelEqualOrGreaterThan: // 70
if (!unit || unit.GetLevel() < reqValue)
if (!refe || !refe.IsUnit() || refe.ToUnit().GetLevel() < reqValue)
return false;
break;
case ModifierTreeType.PlayerLevelEqualOrLessThan: // 71
@@ -1614,13 +1614,13 @@ namespace Game.Achievements
return false;
break;
case ModifierTreeType.TargetLevelEqualOrLessThan: // 72
if (!unit || unit.GetLevel() > reqValue)
if (!refe || !refe.IsUnit() || refe.ToUnit().GetLevel() > reqValue)
return false;
break;
case ModifierTreeType.ModifierTree: // 73
ModifierTreeNode nextModifierTree = Global.CriteriaMgr.GetModifierTree(reqValue);
if (nextModifierTree != null)
return ModifierTreeSatisfied(nextModifierTree, miscValue1, miscValue2, unit, referencePlayer);
return ModifierTreeSatisfied(nextModifierTree, miscValue1, miscValue2, refe, referencePlayer);
return false;
case ModifierTreeType.PlayerScenario: // 74
{
@@ -1905,9 +1905,12 @@ namespace Game.Achievements
break;
case ModifierTreeType.TargetThreatListSizeLessThan: // 120
{
if (!unit || !unit.CanHaveThreatList())
if (refe == null)
return false;
if (unit.GetThreatManager().GetThreatListSize() >= reqValue)
Unit unitRef = refe.ToUnit();
if (unitRef == null || !unitRef.CanHaveThreatList())
return false;
if (unitRef.GetThreatManager().GetThreatListSize() >= reqValue)
return false;
break;
}
@@ -3018,9 +3021,9 @@ namespace Game.Achievements
}
case ModifierTreeType.TargetVisibleRace: // 253
{
if (!unit)
if (refe == null || !refe.IsUnit())
return false;
CreatureDisplayInfoRecord creatureDisplayInfo = CliDB.CreatureDisplayInfoStorage.LookupByKey(unit.GetDisplayId());
CreatureDisplayInfoRecord creatureDisplayInfo = CliDB.CreatureDisplayInfoStorage.LookupByKey(refe.ToUnit().GetDisplayId());
if (creatureDisplayInfo == null)
return false;
@@ -3059,7 +3062,7 @@ namespace Game.Achievements
return false;
break;
case ModifierTreeType.TargetAuraStackCountEqual: // 256
if (!unit || unit.GetAuraCount((uint)secondaryAsset) != reqValue)
if (!refe || !refe.IsUnit() || refe.ToUnit().GetAuraCount((uint)secondaryAsset) != reqValue)
return false;
break;
case ModifierTreeType.PlayerAuraStackCountEqualOrGreaterThan: // 257
@@ -3067,7 +3070,7 @@ namespace Game.Achievements
return false;
break;
case ModifierTreeType.TargetAuraStackCountEqualOrGreaterThan: // 258
if (!unit || unit.GetAuraCount((uint)secondaryAsset) < reqValue)
if (!refe || !refe.IsUnit() || refe.ToUnit().GetAuraCount((uint)secondaryAsset) < reqValue)
return false;
break;
case ModifierTreeType.PlayerHasAzeriteEssenceRankLessThan: // 259
@@ -3192,10 +3195,10 @@ namespace Game.Achievements
}
case ModifierTreeType.TargetLevelWithinContentTuning: // 269
{
if (!unit)
if (!refe || !refe.IsUnit())
return false;
uint level = unit.GetLevel();
uint level = refe.ToUnit().GetLevel();
var levels = Global.DB2Mgr.GetContentTuningData(reqValue, 0);
if (levels.HasValue)
{
@@ -3224,10 +3227,10 @@ namespace Game.Achievements
}
case ModifierTreeType.TargetLevelWithinOrAboveContentTuning: // 273
{
if (!unit)
if (!refe || !refe.IsUnit())
return false;
uint level = unit.GetLevel();
uint level = refe.ToUnit().GetLevel();
var levels = Global.DB2Mgr.GetContentTuningData(reqValue, 0);
if (levels.HasValue)
return secondaryAsset != 0 ? level >= levels.Value.MinLevelWithDelta : level >= levels.Value.MinLevel;
@@ -3343,11 +3346,11 @@ namespace Game.Achievements
}
case ModifierTreeType.TargetIsInAreaGroup: // 299
{
if (!unit)
if (!refe)
return false;
var areas = Global.DB2Mgr.GetAreasForGroup(reqValue);
var area = CliDB.AreaTableStorage.LookupByKey(unit.GetAreaId());
var area = CliDB.AreaTableStorage.LookupByKey(refe.GetAreaId());
if (area != null)
foreach (uint areaInGroup in areas)
if (areaInGroup == area.Id || areaInGroup == area.ParentAreaID)
@@ -3436,9 +3439,9 @@ namespace Game.Achievements
return false;
break;
case ModifierTreeType.TargetCovenant: // 314
if (!unit || !unit.IsPlayer())
if (!refe || !refe.IsPlayer())
return false;
if (unit.ToPlayer().m_playerData.CovenantID != reqValue)
if (refe.ToPlayer().m_playerData.CovenantID != reqValue)
return false;
break;
case ModifierTreeType.PlayerHasTBCCollectorsEdition: // 315
@@ -4322,7 +4325,7 @@ namespace Game.Achievements
}
}
public bool Meets(uint criteriaId, Player source, Unit target, uint miscValue1 = 0, uint miscValue2 = 0)
public bool Meets(uint criteriaId, Player source, WorldObject target, uint miscValue1 = 0, uint miscValue2 = 0)
{
switch (DataType)
{
@@ -4351,11 +4354,18 @@ namespace Game.Achievements
case CriteriaDataType.TPlayerLessHealth:
if (target == null || !target.IsTypeId(TypeId.Player))
return false;
return !target.HealthAbovePct((int)Health.Percent);
return !target.ToPlayer().HealthAbovePct((int)Health.Percent);
case CriteriaDataType.SAura:
return source.HasAuraEffect(Aura.SpellId, (byte)Aura.EffectIndex);
case CriteriaDataType.TAura:
return target != null && target.HasAuraEffect(Aura.SpellId, (byte)Aura.EffectIndex);
{
if (target == null)
return false;
Unit unitTarget = target.ToUnit();
if (unitTarget == null)
return false;
return unitTarget.HasAuraEffect(Aura.SpellId, Aura.EffectIndex);
}
case CriteriaDataType.Value:
return MathFunctions.CompareValues((ComparisionType)Value.ComparisonType, miscValue1, Value.Value);
case CriteriaDataType.TLevel:
@@ -4363,11 +4373,21 @@ namespace Game.Achievements
return false;
return target.GetLevelForTarget(source) >= Level.Min;
case CriteriaDataType.TGender:
{
if (target == null)
return false;
return (uint)target.GetGender() == Gender.Gender;
Unit unitTarget = target.ToUnit();
if (unitTarget == null)
return false;
return unitTarget.GetGender() == (Gender)Gender.Gender;
}
case CriteriaDataType.Script:
return Global.ScriptMgr.OnCriteriaCheck(ScriptId, source, target);
{
Unit unitTarget = null;
if (target)
unitTarget = target.ToUnit();
return Global.ScriptMgr.OnCriteriaCheck(ScriptId, source.ToPlayer(), unitTarget.ToUnit());
}
case CriteriaDataType.MapPlayerCount:
return source.GetMap().GetPlayersCountExceptGMs() <= MapPlayers.MaxCount;
case CriteriaDataType.TTeam:
@@ -4407,7 +4427,11 @@ namespace Game.Achievements
CriteriaDataType.InstanceScript, criteriaId, map.GetId());
return false;
}
return instance.CheckAchievementCriteriaMeet(criteriaId, source, target, miscValue1);
Unit unitTarget = null;
if (target != null)
unitTarget = target.ToUnit();
return instance.CheckAchievementCriteriaMeet(criteriaId, source, unitTarget, miscValue1);
}
case CriteriaDataType.SEquippedItem:
{
@@ -4554,7 +4578,7 @@ namespace Game.Achievements
public void Add(CriteriaData data) { _storage.Add(data); }
public bool Meets(Player source, Unit target, uint miscValue = 0, uint miscValue2 = 0)
public bool Meets(Player source, WorldObject target, uint miscValue = 0, uint miscValue2 = 0)
{
foreach (var data in _storage)
if (!data.Meets(_criteriaId, source, target, miscValue, miscValue2))
@@ -143,7 +143,7 @@ namespace Game.Collision
public bool IsInLineOfSight(uint mapId, float x1, float y1, float z1, float x2, float y2, float z2, ModelIgnoreFlags ignoreFlags)
{
if (!IsLineOfSightCalcEnabled() || Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, DisableFlags.VmapLOS))
if (!IsLineOfSightCalcEnabled() || Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, (byte)DisableFlags.VmapLOS))
return true;
var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
@@ -160,7 +160,7 @@ namespace Game.Collision
public bool GetObjectHitPos(uint mapId, float x1, float y1, float z1, float x2, float y2, float z2, out float rx, out float ry, out float rz, float modifyDist)
{
if (IsLineOfSightCalcEnabled() && !Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, DisableFlags.VmapLOS))
if (IsLineOfSightCalcEnabled() && !Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, (byte)DisableFlags.VmapLOS))
{
var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
if (instanceTree != null)
@@ -186,7 +186,7 @@ namespace Game.Collision
public float GetHeight(uint mapId, float x, float y, float z, float maxSearchDist)
{
if (IsHeightCalcEnabled() && !Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, DisableFlags.VmapHeight))
if (IsHeightCalcEnabled() && !Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, (byte)DisableFlags.VmapHeight))
{
var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
if (instanceTree != null)
@@ -209,7 +209,7 @@ namespace Game.Collision
adtId = 0;
rootId = 0;
groupId = 0;
if (!Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, DisableFlags.VmapAreaFlag))
if (!Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, (byte)DisableFlags.VmapAreaFlag))
{
var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
if (instanceTree != null)
@@ -227,7 +227,7 @@ namespace Game.Collision
public bool GetLiquidLevel(uint mapId, float x, float y, float z, uint reqLiquidType, ref float level, ref float floor, ref uint type)
{
if (!Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, DisableFlags.VmapLiquidStatus))
if (!Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, (byte)DisableFlags.VmapLiquidStatus))
{
var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
if (instanceTree != null)
@@ -253,7 +253,7 @@ namespace Game.Collision
{
var data = new AreaAndLiquidData();
if (!Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, DisableFlags.VmapLiquidStatus))
if (!Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, (byte)DisableFlags.VmapLiquidStatus))
{
data.floorZ = z;
int adtId, rootId, groupId;
@@ -276,7 +276,7 @@ namespace Game.Collision
if (info.hitInstance.GetLiquidLevel(pos, info, ref liquidLevel))
data.liquidInfo.Set(new AreaAndLiquidData.LiquidInfo(liquidType, liquidLevel));
if (!Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, DisableFlags.VmapLiquidStatus))
if (!Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, (byte)DisableFlags.VmapLiquidStatus))
data.areaInfo.Set(new AreaAndLiquidData.AreaInfo(info.hitInstance.adtId, info.rootId, (int)info.hitModel.GetWmoID(), info.hitModel.GetMogpFlags()));
}
}
+63 -61
View File
@@ -63,17 +63,17 @@ namespace Game
}
uint entry = result.Read<uint>(1);
byte flags = result.Read<byte>(2);
DisableFlags flags = (DisableFlags)result.Read<byte>(2);
string params_0 = result.Read<string>(3);
string params_1 = result.Read<string>(4);
DisableData data = new();
data.flags = flags;
data.flags = (byte)flags;
switch (type)
{
case DisableType.Spell:
if (!(Global.SpellMgr.HasSpellInfo(entry, Difficulty.None) || flags.HasAnyFlag<byte>(DisableFlags.SpellDeprecatedSpell)))
if (!(Global.SpellMgr.HasSpellInfo(entry, Difficulty.None) || flags.HasFlag(DisableFlags.SpellDeprecatedSpell)))
{
Log.outError(LogFilter.Sql, "Spell entry {0} from `disables` doesn't exist in dbc, skipped.", entry);
continue;
@@ -85,7 +85,7 @@ namespace Game
continue;
}
if (flags.HasAnyFlag(DisableFlags.SpellMap))
if (flags.HasFlag(DisableFlags.SpellMap))
{
var array = new StringArray(params_0, ',');
for (byte i = 0; i < array.Length;)
@@ -95,7 +95,7 @@ namespace Game
}
}
if (flags.HasAnyFlag(DisableFlags.SpellArea))
if (flags.HasFlag(DisableFlags.SpellArea))
{
var array = new StringArray(params_1, ',');
for (byte i = 0; i < array.Length;)
@@ -127,12 +127,12 @@ namespace Game
break;
case MapTypes.Instance:
case MapTypes.Raid:
if (flags.HasAnyFlag(DisableFlags.DungeonStatusHeroic) && Global.DB2Mgr.GetMapDifficultyData(entry, Difficulty.Heroic) == null)
flags -= DisableFlags.DungeonStatusHeroic;
if (flags.HasAnyFlag(DisableFlags.DungeonStatusHeroic10Man) && Global.DB2Mgr.GetMapDifficultyData(entry, Difficulty.Raid10HC) == null)
flags -= DisableFlags.DungeonStatusHeroic10Man;
if (flags.HasAnyFlag(DisableFlags.DungeonStatusHeroic25Man) && Global.DB2Mgr.GetMapDifficultyData(entry, Difficulty.Raid25HC) == null)
flags -= DisableFlags.DungeonStatusHeroic25Man;
if (flags.HasFlag(DisableFlags.DungeonStatusHeroic) && Global.DB2Mgr.GetMapDifficultyData(entry, Difficulty.Heroic) == null)
flags &= ~DisableFlags.DungeonStatusHeroic;
if (flags.HasFlag(DisableFlags.DungeonStatusHeroic10Man) && Global.DB2Mgr.GetMapDifficultyData(entry, Difficulty.Raid10HC) == null)
flags &= ~DisableFlags.DungeonStatusHeroic10Man;
if (flags.HasFlag(DisableFlags.DungeonStatusHeroic25Man) && Global.DB2Mgr.GetMapDifficultyData(entry, Difficulty.Raid25HC) == null)
flags &= ~DisableFlags.DungeonStatusHeroic25Man;
if (flags == 0)
isFlagInvalid = true;
break;
@@ -186,28 +186,28 @@ namespace Game
switch (mapEntry.InstanceType)
{
case MapTypes.Common:
if (flags.HasAnyFlag(DisableFlags.VmapAreaFlag))
if (flags.HasFlag(DisableFlags.VmapAreaFlag))
Log.outInfo(LogFilter.Server, "Areaflag disabled for world map {0}.", entry);
if (flags.HasAnyFlag(DisableFlags.VmapLiquidStatus))
if (flags.HasFlag(DisableFlags.VmapLiquidStatus))
Log.outInfo(LogFilter.Server, "Liquid status disabled for world map {0}.", entry);
break;
case MapTypes.Instance:
case MapTypes.Raid:
if (flags.HasAnyFlag(DisableFlags.VmapHeight))
if (flags.HasFlag(DisableFlags.VmapHeight))
Log.outInfo(LogFilter.Server, "Height disabled for instance map {0}.", entry);
if (flags.HasAnyFlag(DisableFlags.VmapLOS))
if (flags.HasFlag(DisableFlags.VmapLOS))
Log.outInfo(LogFilter.Server, "LoS disabled for instance map {0}.", entry);
break;
case MapTypes.Battleground:
if (flags.HasAnyFlag(DisableFlags.VmapHeight))
if (flags.HasFlag(DisableFlags.VmapHeight))
Log.outInfo(LogFilter.Server, "Height disabled for Battlegroundmap {0}.", entry);
if (flags.HasAnyFlag(DisableFlags.VmapLOS))
if (flags.HasFlag(DisableFlags.VmapLOS))
Log.outInfo(LogFilter.Server, "LoS disabled for Battlegroundmap {0}.", entry);
break;
case MapTypes.Arena:
if (flags.HasAnyFlag(DisableFlags.VmapHeight))
if (flags.HasFlag(DisableFlags.VmapHeight))
Log.outInfo(LogFilter.Server, "Height disabled for arena map {0}.", entry);
if (flags.HasAnyFlag(DisableFlags.VmapLOS))
if (flags.HasFlag(DisableFlags.VmapLOS))
Log.outInfo(LogFilter.Server, "LoS disabled for arena map {0}.", entry);
break;
default:
@@ -284,7 +284,7 @@ namespace Game
Log.outInfo(LogFilter.ServerLoading, "Checked {0} quest disables in {1} ms", m_DisableMap[DisableType.Quest].Count, Time.GetMSTimeDiffToNow(oldMSTime));
}
public bool IsDisabledFor(DisableType type, uint entry, Unit unit, byte flags = 0)
public bool IsDisabledFor(DisableType type, uint entry, WorldObject refe, byte flags = 0)
{
Cypher.Assert(type < DisableType.Max);
if (!m_DisableMap.ContainsKey(type) || m_DisableMap[type].Empty())
@@ -298,28 +298,29 @@ namespace Game
{
case DisableType.Spell:
{
byte spellFlags = data.flags;
if (unit != null)
DisableFlags spellFlags = (DisableFlags)data.flags;
if (refe != null)
{
if ((spellFlags.HasAnyFlag(DisableFlags.SpellPlayer) && unit.IsTypeId(TypeId.Player)) ||
(unit.IsTypeId(TypeId.Unit) && ((unit.IsPet() && spellFlags.HasAnyFlag(DisableFlags.SpellPet)) || spellFlags.HasAnyFlag(DisableFlags.SpellCreature))))
if ((refe.IsPlayer() && spellFlags.HasFlag(DisableFlags.SpellPlayer)) ||
(refe.IsCreature() && (spellFlags.HasFlag(DisableFlags.SpellCreature) || (refe.ToUnit().IsPet() && spellFlags.HasFlag(DisableFlags.SpellPet)))) ||
(refe.IsGameObject() && spellFlags.HasFlag(DisableFlags.SpellGameobject)))
{
if (spellFlags.HasAnyFlag(DisableFlags.SpellMap))
if (spellFlags.HasFlag(DisableFlags.SpellMap))
{
List<uint> mapIds = data.param0;
if (mapIds.Contains(unit.GetMapId()))
if (mapIds.Contains(refe.GetMapId()))
return true; // Spell is disabled on current map
if (!spellFlags.HasAnyFlag(DisableFlags.SpellArea))
if (!spellFlags.HasFlag(DisableFlags.SpellArea))
return false; // Spell is disabled on another map, but not this one, return false
// Spell is disabled in an area, but not explicitly our current mapId. Continue processing.
}
if (spellFlags.HasAnyFlag(DisableFlags.SpellArea))
if (spellFlags.HasFlag(DisableFlags.SpellArea))
{
var areaIds = data.param1;
if (areaIds.Contains(unit.GetAreaId()))
if (areaIds.Contains(refe.GetAreaId()))
return true; // Spell is disabled in this area
return false; // Spell is disabled in another area, but not this one, return false
}
@@ -329,34 +330,34 @@ namespace Game
return false;
}
else if (spellFlags.HasAnyFlag(DisableFlags.SpellDeprecatedSpell)) // call not from spellcast
else if (spellFlags.HasFlag(DisableFlags.SpellDeprecatedSpell)) // call not from spellcast
return true;
else if (flags.HasAnyFlag(DisableFlags.SpellLOS))
return spellFlags.HasAnyFlag(DisableFlags.SpellLOS);
else if (flags.HasAnyFlag((byte)DisableFlags.SpellLOS))
return spellFlags.HasFlag(DisableFlags.SpellLOS);
break;
}
case DisableType.Map:
case DisableType.LFGMap:
Player player = unit.ToPlayer();
Player player = refe.ToPlayer();
if (player != null)
{
MapRecord mapEntry = CliDB.MapStorage.LookupByKey(entry);
if (mapEntry.IsDungeon())
{
byte disabledModes = data.flags;
DisableFlags disabledModes = (DisableFlags)data.flags;
Difficulty targetDifficulty = player.GetDifficultyID(mapEntry);
Global.DB2Mgr.GetDownscaledMapDifficultyData(entry, ref targetDifficulty);
switch (targetDifficulty)
{
case Difficulty.Normal:
return disabledModes.HasAnyFlag(DisableFlags.DungeonStatusNormal);
return disabledModes.HasFlag(DisableFlags.DungeonStatusNormal);
case Difficulty.Heroic:
return disabledModes.HasAnyFlag(DisableFlags.DungeonStatusHeroic);
return disabledModes.HasFlag(DisableFlags.DungeonStatusHeroic);
case Difficulty.Raid10HC:
return disabledModes.HasAnyFlag(DisableFlags.DungeonStatusHeroic10Man);
return disabledModes.HasFlag(DisableFlags.DungeonStatusHeroic10Man);
case Difficulty.Raid25HC:
return disabledModes.HasAnyFlag(DisableFlags.DungeonStatusHeroic25Man);
return disabledModes.HasFlag(DisableFlags.DungeonStatusHeroic25Man);
default:
return false;
}
@@ -366,9 +367,9 @@ namespace Game
}
return false;
case DisableType.Quest:
if (unit == null)
if (refe == null)
return true;
Player player1 = unit.ToPlayer();
Player player1 = refe.ToPlayer();
if (player1 != null)
if (player1.IsGameMaster())
return false;
@@ -410,31 +411,32 @@ namespace Game
Max = 9
}
public struct DisableFlags
[Flags]
public enum DisableFlags
{
public const byte SpellPlayer = 0x1;
public const byte SpellCreature = 0x2;
public const byte SpellPet = 0x4;
public const byte SpellDeprecatedSpell = 0x8;
public const byte SpellMap = 0x10;
public const byte SpellArea = 0x20;
public const byte SpellLOS = 0x40;
public const byte MaxSpell = (SpellPlayer | SpellCreature | SpellPet | SpellDeprecatedSpell | SpellMap | SpellArea | SpellLOS);
SpellPlayer = 0x01,
SpellCreature = 0x02,
SpellPet = 0x04,
SpellDeprecatedSpell = 0x08,
SpellMap = 0x10,
SpellArea = 0x20,
SpellLOS = 0x40,
SpellGameobject = 0x80,
MaxSpell = SpellPlayer | SpellCreature | SpellPet | SpellDeprecatedSpell | SpellMap | SpellArea | SpellLOS | SpellGameobject,
public const byte VmapAreaFlag = 0x1;
public const byte VmapHeight = 0x2;
public const byte VmapLOS = 0x4;
public const byte VmapLiquidStatus = 0x8;
VmapAreaFlag = 0x01,
VmapHeight = 0x02,
VmapLOS = 0x04,
VmapLiquidStatus = 0x08,
public const byte MMapPathFinding = 0x0;
MMapPathFinding = 0x00,
public const byte DungeonStatusNormal = 0x01;
public const byte DungeonStatusHeroic = 0x02;
public const byte DungeonStatusNormal10Man = 0x01;
public const byte DungeonStatusNormal25Man = 0x02;
public const byte DungeonStatusHeroic10Man = 0x04;
public const byte DungeonStatusHeroic25Man = 0x08;
DungeonStatusNormal = 0x01,
DungeonStatusHeroic = 0x02,
DungeonStatusNormal10Man = 0x01,
DungeonStatusNormal25Man = 0x02,
DungeonStatusHeroic10Man = 0x04,
DungeonStatusHeroic25Man = 0x08
}
}
@@ -491,6 +491,15 @@ namespace Game.Entities
return Global.ObjAccessor.GetUnit(this, _targetGuid);
}
public override uint GetFaction()
{
Unit caster = GetCaster();
if (caster)
return caster.GetFaction();
return 0;
}
void UpdatePolygonOrientation()
{
float newOrientation = GetOrientation();
@@ -1002,6 +1011,7 @@ namespace Game.Entities
public AreaTriggerMiscTemplate GetMiscTemplate() { return _areaTriggerMiscTemplate; }
public override ObjectGuid GetOwnerGUID() { return GetCasterGuid(); }
public ObjectGuid GetCasterGuid() { return m_areaTriggerData.Caster; }
public Vector3 GetRollPitchYaw() { return _rollPitchYaw; }
+2
View File
@@ -288,6 +288,8 @@ namespace Game.Entities
public uint GetTextureKitId() { return _textureKitId; }
public ObjectGuid GetCreatorGuid() { return _creatorGuid; }
public override ObjectGuid GetOwnerGUID() { return GetCreatorGuid(); }
public override uint GetFaction() { return 0; }
public override float GetStationaryX() { return _stationaryPosition.GetPositionX(); }
public override float GetStationaryY() { return _stationaryPosition.GetPositionY(); }
+3 -1
View File
@@ -287,7 +287,7 @@ namespace Game.Entities
public void AddCorpseDynamicFlag(CorpseDynFlags dynamicFlags) { SetUpdateFieldFlagValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.DynamicFlags), (uint)dynamicFlags); }
public void RemoveCorpseDynamicFlag(CorpseDynFlags dynamicFlags) { RemoveUpdateFieldFlagValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.DynamicFlags), (uint)dynamicFlags); }
public void SetCorpseDynamicFlags(CorpseDynFlags dynamicFlags) { SetUpdateFieldValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.DynamicFlags), (uint)dynamicFlags); }
public ObjectGuid GetOwnerGUID() { return m_corpseData.Owner; }
public override ObjectGuid GetOwnerGUID() { return m_corpseData.Owner; }
public void SetOwnerGUID(ObjectGuid owner) { SetUpdateFieldValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.Owner), owner); }
public void SetPartyGUID(ObjectGuid partyGuid) { SetUpdateFieldValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.PartyGUID), partyGuid); }
public void SetGuildGUID(ObjectGuid guildGuid) { SetUpdateFieldValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.GuildGUID), guildGuid); }
@@ -297,6 +297,8 @@ namespace Game.Entities
public void SetSex(byte sex) { SetUpdateFieldValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.Sex), sex); }
public void SetFlags(CorpseFlags flags) { SetUpdateFieldValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.Flags), (uint)flags); }
public void SetFactionTemplate(int factionTemplate) { SetUpdateFieldValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.FactionTemplate), factionTemplate); }
public override uint GetFaction() { return (uint)(int)m_corpseData.FactionTemplate; }
public override void SetFaction(uint faction) { SetFactionTemplate((int)faction); }
public void SetItem(uint slot, uint item) { SetUpdateFieldValue(ref m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.Items, (int)slot), item); }
public void SetCustomizations(List<ChrCustomizationChoice> customizations)
+2 -2
View File
@@ -2039,7 +2039,7 @@ namespace Game.Entities
ApplySpellImmune(placeholderSpellId, SpellImmunity.School, 1u << i, true);
}
public override bool IsImmunedToSpell(SpellInfo spellInfo, Unit caster)
public override bool IsImmunedToSpell(SpellInfo spellInfo, WorldObject caster)
{
if (spellInfo == null)
return false;
@@ -2063,7 +2063,7 @@ namespace Game.Entities
return base.IsImmunedToSpell(spellInfo, caster);
}
public override bool IsImmunedToSpellEffect(SpellInfo spellInfo, uint index, Unit caster)
public override bool IsImmunedToSpellEffect(SpellInfo spellInfo, uint index, WorldObject caster)
{
SpellEffectInfo effect = spellInfo.GetEffect(index);
if (effect == null)
+7
View File
@@ -226,6 +226,12 @@ namespace Game.Entities
}
}
public override uint GetFaction()
{
Cypher.Assert(_caster != null);
return _caster.GetFaction();
}
void BindToCaster()
{
Cypher.Assert(_caster == null);
@@ -312,6 +318,7 @@ namespace Game.Entities
public Unit GetCaster() { return _caster; }
public uint GetSpellId() { return m_dynamicObjectData.SpellID; }
public ObjectGuid GetCasterGUID() { return m_dynamicObjectData.Caster; }
public override ObjectGuid GetOwnerGUID() { return GetCasterGUID(); }
public float GetRadius() { return m_dynamicObjectData.Radius; }
DynamicObjectData m_dynamicObjectData;
+21 -86
View File
@@ -423,6 +423,8 @@ namespace Game.Entities
public override void Update(uint diff)
{
m_Events.Update(diff);
if (GetAI() != null)
GetAI().UpdateAI(diff);
else if (!AIM_Initialize())
@@ -730,8 +732,9 @@ namespace Game.Entities
else if (target)
{
// Some traps do not have a spell but should be triggered
CastSpellExtraArgs args = new(GetOwnerGUID());
if (goInfo.Trap.spell != 0)
CastSpell(target, goInfo.Trap.spell);
CastSpell(target, goInfo.Trap.spell, args);
// Template value or 4 seconds
m_cooldownTime = (GameTime.GetGameTimeMS() + (goInfo.Trap.cooldown != 0 ? goInfo.Trap.cooldown : 4u)) * Time.InMilliseconds;
@@ -1202,11 +1205,6 @@ namespace Game.Entities
public Transport ToTransport() { return GetGoInfo().type == GameObjectTypes.MapObjTransport ? (this as Transport) : null; }
public Unit GetOwner()
{
return Global.ObjAccessor.GetUnit(this, GetOwnerGUID());
}
public override void SaveRespawnTime(uint forceDelay = 0, bool savetodb = true)
{
if (m_goData != null && (forceDelay != 0 || m_respawnTime > GameTime.GetGameTime()) && m_spawnedByDefault)
@@ -2089,69 +2087,6 @@ namespace Game.Entities
CastSpell(user, spellId);
}
public void CastSpell(Unit target, uint spellId, bool triggered = true)
{
CastSpell(target, spellId, triggered ? TriggerCastFlags.FullMask : TriggerCastFlags.None);
}
public void CastSpell(Unit target, uint spellId, TriggerCastFlags triggered)
{
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID());
if (spellInfo == null)
return;
bool self = false;
foreach (SpellEffectInfo effect in spellInfo.GetEffects())
{
if (effect != null && effect.TargetA.GetTarget() == Targets.UnitCaster)
{
self = true;
break;
}
}
if (self)
{
if (target != null)
target.CastSpell(target, spellInfo.Id, new CastSpellExtraArgs(triggered));
return;
}
//summon world trigger
Creature trigger = SummonTrigger(GetPositionX(), GetPositionY(), GetPositionZ(), 0, (uint)(spellInfo.CalcCastTime() + 100));
if (!trigger)
return;
// remove immunity flags, to allow spell to target anything
trigger.SetImmuneToAll(false);
PhasingHandler.InheritPhaseShift(trigger, this);
CastSpellExtraArgs args = new(triggered);
Unit owner = GetOwner();
if (owner)
{
trigger.SetFaction(owner.GetFaction());
if (owner.HasUnitFlag(UnitFlags.PvpAttackable))
trigger.AddUnitFlag(UnitFlags.PvpAttackable);
// copy pvp state flags from owner
trigger.SetPvpFlags(owner.GetPvpFlags());
// needed for GO casts for proper target validation checks
trigger.SetOwnerGUID(owner.GetGUID());
args.OriginalCaster = owner.GetGUID();
trigger.CastSpell(target ?? trigger, spellInfo.Id, args);
}
else
{
trigger.SetFaction(spellInfo.IsPositive() ? 35 : 14u);
// Set owner guid for target if no owner available - needed by trigger auras
// - trigger gets despawned and there's no caster avalible (see AuraEffect.TriggerSpell())
args.OriginalCaster = target ? target.GetGUID() : ObjectGuid.Empty;
trigger.CastSpell(target ?? trigger, spellInfo.Id, args);
}
}
public void SendCustomAnim(uint anim)
{
GameObjectCustomAnim customAnim = new();
@@ -2266,7 +2201,7 @@ namespace Game.Entities
SetWorldRotation(quat.X, quat.Y, quat.Z, quat.W);
}
public void ModifyHealth(int change, Unit attackerOrHealer = null, uint spellId = 0)
public void ModifyHealth(int change, WorldObject attackerOrHealer = null, uint spellId = 0)
{
if (m_goValue.Building.MaxHealth == 0 || change == 0)
return;
@@ -2285,9 +2220,8 @@ namespace Game.Entities
// Set the health bar, value = 255 * healthPct;
SetGoAnimProgress(m_goValue.Building.Health * 255 / m_goValue.Building.MaxHealth);
Player player = attackerOrHealer.GetCharmerOrOwnerPlayerOrPlayerItself();
// dealing damage, send packet
Player player = attackerOrHealer != null ? attackerOrHealer.GetCharmerOrOwnerPlayerOrPlayerItself() : null;
if (player != null)
{
DestructibleBuildingDamage packet = new();
@@ -2311,10 +2245,10 @@ namespace Game.Entities
if (newState == GetDestructibleState())
return;
SetDestructibleState(newState, player, false);
SetDestructibleState(newState, attackerOrHealer, false);
}
public void SetDestructibleState(GameObjectDestructibleState state, Player eventInvoker = null, bool setHealth = false)
public void SetDestructibleState(GameObjectDestructibleState state, WorldObject attackerOrHealer = null, bool setHealth = false)
{
// the user calling this must know he is already operating on destructible gameobject
Cypher.Assert(GetGoType() == GameObjectTypes.DestructibleBuilding);
@@ -2333,8 +2267,8 @@ namespace Game.Entities
break;
case GameObjectDestructibleState.Damaged:
{
EventInform(m_goInfo.DestructibleBuilding.DamagedEvent, eventInvoker);
GetAI().Damaged(eventInvoker, m_goInfo.DestructibleBuilding.DamagedEvent);
EventInform(m_goInfo.DestructibleBuilding.DamagedEvent, attackerOrHealer);
GetAI().Damaged(attackerOrHealer, m_goInfo.DestructibleBuilding.DamagedEvent);
RemoveFlag(GameObjectFlags.Destroyed);
AddFlag(GameObjectFlags.Damaged);
@@ -2359,13 +2293,14 @@ namespace Game.Entities
}
case GameObjectDestructibleState.Destroyed:
{
EventInform(m_goInfo.DestructibleBuilding.DestroyedEvent, eventInvoker);
GetAI().Destroyed(eventInvoker, m_goInfo.DestructibleBuilding.DestroyedEvent);
if (eventInvoker != null)
EventInform(m_goInfo.DestructibleBuilding.DestroyedEvent, attackerOrHealer);
GetAI().Destroyed(attackerOrHealer, m_goInfo.DestructibleBuilding.DestroyedEvent);
if (attackerOrHealer != null && attackerOrHealer.IsPlayer())
{
Battleground bg = eventInvoker.GetBattleground();
if (bg)
bg.DestroyGate(eventInvoker, this);
var bg = attackerOrHealer.ToPlayer().GetBattleground();
if (bg != null)
bg.DestroyGate(attackerOrHealer.ToPlayer(), this);
}
RemoveFlag(GameObjectFlags.Damaged);
@@ -2388,7 +2323,7 @@ namespace Game.Entities
}
case GameObjectDestructibleState.Rebuilding:
{
EventInform(m_goInfo.DestructibleBuilding.RebuildingEvent, eventInvoker);
EventInform(m_goInfo.DestructibleBuilding.RebuildingEvent, attackerOrHealer);
RemoveFlag(GameObjectFlags.Damaged | GameObjectFlags.Destroyed);
uint modelId = m_goInfo.displayId;
@@ -2769,7 +2704,7 @@ namespace Game.Entities
m_spawnedByDefault = false; // all object with owner is despawned after delay
SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.CreatedBy), owner);
}
public ObjectGuid GetOwnerGUID() { return m_gameObjectData.CreatedBy; }
public override ObjectGuid GetOwnerGUID() { return m_gameObjectData.CreatedBy; }
public void SetSpellId(uint id)
{
@@ -2871,8 +2806,8 @@ namespace Game.Entities
public uint GetDisplayId() { return m_gameObjectData.DisplayID; }
public uint GetFaction() { return m_gameObjectData.FactionTemplate; }
public void SetFaction(uint faction) { SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.FactionTemplate), faction); }
public override uint GetFaction() { return m_gameObjectData.FactionTemplate; }
public override void SetFaction(uint faction) { SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.FactionTemplate), faction); }
public override float GetStationaryX() { return StationaryPosition.GetPositionX(); }
public override float GetStationaryY() { return StationaryPosition.GetPositionY(); }
File diff suppressed because it is too large Load Diff
@@ -66,10 +66,10 @@ namespace Game.Entities
m_questObjectiveCriteriaMgr.ResetCriteria(failEvent, failAsset, evenIfCriteriaComplete);
}
public void UpdateCriteria(CriteriaTypes type, ulong miscValue1 = 0, ulong miscValue2 = 0, ulong miscValue3 = 0, Unit unit = null)
public void UpdateCriteria(CriteriaTypes type, ulong miscValue1 = 0, ulong miscValue2 = 0, ulong miscValue3 = 0, WorldObject refe = null)
{
m_achievementSys.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, this);
m_questObjectiveCriteriaMgr.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, this);
m_achievementSys.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, refe, this);
m_questObjectiveCriteriaMgr.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, refe, this);
// Update only individual achievement criteria here, otherwise we may get multiple updates
// from a single boss kill
@@ -78,11 +78,11 @@ namespace Game.Entities
Scenario scenario = GetScenario();
if (scenario != null)
scenario.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, this);
scenario.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, refe, this);
Guild guild = Global.GuildMgr.GetGuildById(GetGuildId());
if (guild)
guild.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, this);
guild.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, refe, this);
}
public void CompletedAchievement(AchievementRecord entry)
+2 -42
View File
@@ -3482,7 +3482,7 @@ namespace Game.Entities
SetFaction(rEntry != null ? (uint)rEntry.FactionID : 0);
}
public void SetResurrectRequestData(Unit caster, uint health, uint mana, uint appliedAura)
public void SetResurrectRequestData(WorldObject caster, uint health, uint mana, uint appliedAura)
{
Cypher.Assert(!IsResurrectRequested());
_resurrectionData = new ResurrectionData();
@@ -3633,7 +3633,7 @@ namespace Game.Entities
return false;
}
public override bool IsImmunedToSpellEffect(SpellInfo spellInfo, uint index, Unit caster)
public override bool IsImmunedToSpellEffect(SpellInfo spellInfo, uint index, WorldObject caster)
{
SpellEffectInfo effect = spellInfo.GetEffect(index);
if (effect == null || !effect.IsEffect())
@@ -6637,46 +6637,6 @@ namespace Game.Entities
return m_auraBaseFlatMod[(int)modGroup] * m_auraBasePctMod[(int)modGroup];
}
public void AddComboPoints(sbyte count, Spell spell = null)
{
if (count == 0)
return;
sbyte comboPoints = spell != null ? spell.m_comboPointGain : (sbyte)GetPower(PowerType.ComboPoints);
comboPoints += count;
if (comboPoints > 5)
comboPoints = 5;
else if (comboPoints < 0)
comboPoints = 0;
if (spell == null)
SetPower(PowerType.ComboPoints, comboPoints);
else
spell.m_comboPointGain = comboPoints;
}
public void GainSpellComboPoints(sbyte count)
{
if (count == 0)
return;
sbyte cp = (sbyte)GetPower(PowerType.ComboPoints);
cp += count;
if (cp > 5)
cp = 5;
else if (cp < 0)
cp = 0;
SetPower(PowerType.ComboPoints, cp);
}
public void ClearComboPoints()
{
SetPower(PowerType.ComboPoints, 0);
}
public byte GetComboPoints() { return (byte)GetPower(PowerType.ComboPoints); }
public byte GetDrunkValue() { return m_playerData.Inebriation; }
public void SetDrunkValue(byte newDrunkValue, uint itemId = 0)
{
+1 -1
View File
@@ -788,7 +788,7 @@ namespace Game.Entities
public void SetRangedWeaponAttackPower(int attackPower) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.RangedWeaponAttackPower), attackPower); }
//Chances
float MeleeSpellMissChance(Unit victim, WeaponAttackType attType, SpellInfo spellInfo)
public override float MeleeSpellMissChance(Unit victim, WeaponAttackType attType, SpellInfo spellInfo)
{
//calculate miss chance
float missChance = victim.GetUnitMissChance();
+1 -1
View File
@@ -143,7 +143,7 @@ namespace Game.Entities
AddObjectToRemoveList();
}
public override bool IsImmunedToSpellEffect(SpellInfo spellInfo, uint index, Unit caster)
public override bool IsImmunedToSpellEffect(SpellInfo spellInfo, uint index, WorldObject caster)
{
// @todo possibly all negative auras immune?
if (GetEntry() == 5925)
-328
View File
@@ -631,43 +631,6 @@ namespace Game.Entities
public void SetBaseWeaponDamage(WeaponAttackType attType, WeaponDamageRange damageRange, float value) { m_weaponDamage[(int)attType][(int)damageRange] = value; }
public Unit GetMagicHitRedirectTarget(Unit victim, SpellInfo spellInfo)
{
// Patch 1.2 notes: Spell Reflection no longer reflects abilities
if (spellInfo.HasAttribute(SpellAttr0.Ability) || spellInfo.HasAttribute(SpellAttr1.CantBeRedirected) || spellInfo.HasAttribute(SpellAttr0.UnaffectedByInvulnerability))
return victim;
var magnetAuras = victim.GetAuraEffectsByType(AuraType.SpellMagnet);
foreach (var eff in magnetAuras)
{
Unit magnet = eff.GetBase().GetCaster();
if (magnet != null)
{
if (spellInfo.CheckExplicitTarget(this, magnet) == SpellCastResult.SpellCastOk && IsValidAttackTarget(magnet, spellInfo))
{
// @todo handle this charge drop by proc in cast phase on explicit target
if (spellInfo.HasHitDelay())
{
// Set up missile speed based delay
float hitDelay = spellInfo.LaunchDelay;
if (spellInfo.HasAttribute(SpellAttr9.SpecialDelayCalculation))
hitDelay += spellInfo.Speed;
else if (spellInfo.Speed > 0.0f)
hitDelay += Math.Max(victim.GetDistance(this), 5.0f) / spellInfo.Speed;
uint delay = (uint)Math.Floor(hitDelay * 1000.0f);
// Schedule charge drop
eff.GetBase().DropChargeDelayed(delay, AuraRemoveMode.Expire);
}
else
eff.GetBase().DropCharge(AuraRemoveMode.Expire);
return magnet;
}
}
}
return victim;
}
public Unit GetMeleeHitRedirectTarget(Unit victim, SpellInfo spellInfo = null)
{
var interceptAuras = victim.GetAuraEffectsByType(AuraType.InterceptMeleeRangedAttacks);
@@ -753,17 +716,6 @@ namespace Game.Entities
}
}
internal void SendCombatLogMessage(CombatLogServerPacket combatLog)
{
CombatLogSender combatLogSender = new(combatLog);
if (IsPlayer())
combatLogSender.Invoke(ToPlayer());
var notifier = new MessageDistDeliverer<CombatLogSender>(this, combatLogSender, GetVisibilityRange());
Cell.VisitWorldObjects(this, notifier, GetVisibilityRange());
}
bool IsThreatened()
{
return !m_threatManager.IsThreatListEmpty();
@@ -1562,286 +1514,6 @@ namespace Game.Entities
}
}
// function based on function Unit::CanAttack from 13850 client
public bool IsValidAttackTarget(WorldObject target, SpellInfo bySpell = null, bool spellCheck = true)
{
Cypher.Assert(target != null);
// can't attack self
if (this == target)
return false;
// can't attack GMs
if (target.IsPlayer() && target.ToPlayer().IsGameMaster())
return false;
Unit unit = ToUnit();
Unit targetUnit = target.ToUnit();
// CvC case - can attack each other only when one of them is hostile
if (unit && !unit.HasUnitFlag(UnitFlags.PvpAttackable) && targetUnit && !targetUnit.HasUnitFlag(UnitFlags.PvpAttackable))
return IsHostileTo(target) || target.IsHostileTo(this);
// PvP, PvC, CvP case
// can't attack friendly targets
if (IsFriendlyTo(target) || target.IsFriendlyTo(this))
return false;
Player playerAffectingAttacker = unit && unit.HasUnitFlag(UnitFlags.PvpAttackable) ? GetAffectingPlayer() : null;
Player playerAffectingTarget = targetUnit && targetUnit.HasUnitFlag(UnitFlags.PvpAttackable) ? target.GetAffectingPlayer() : null;
// Not all neutral creatures can be attacked (even some unfriendly faction does not react aggresive to you, like Sporaggar)
if ((playerAffectingAttacker && !playerAffectingTarget) || (!playerAffectingAttacker && playerAffectingTarget))
{
Player player = playerAffectingAttacker ? playerAffectingAttacker : playerAffectingTarget;
Unit creature = playerAffectingAttacker ? targetUnit : unit;
if (creature != null)
{
if (creature.IsContestedGuard() && player.HasPlayerFlag(PlayerFlags.ContestedPVP))
return true;
var factionTemplate = creature.GetFactionTemplateEntry();
if (factionTemplate != null)
{
if (player.GetReputationMgr().GetForcedRankIfAny(factionTemplate) == 0)
{
var factionEntry = CliDB.FactionStorage.LookupByKey(factionTemplate.Faction);
if (factionEntry != null)
{
var repState = player.GetReputationMgr().GetState(factionEntry);
if (repState != null)
if (!repState.Flags.HasFlag(ReputationFlags.AtWar))
return false;
}
}
}
}
}
Creature creatureAttacker = ToCreature();
if (creatureAttacker && creatureAttacker.GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.TreatAsRaidUnit))
return false;
if (bySpell == null)
spellCheck = false;
if (spellCheck && !IsValidSpellAttackTarget(target, bySpell))
return false;
return true;
}
public bool IsValidSpellAttackTarget(WorldObject target, SpellInfo bySpell)
{
Cypher.Assert(target != null);
Cypher.Assert(bySpell != null);
// can't attack unattackable units
Unit unitTarget = target.ToUnit();
if (unitTarget && unitTarget.HasUnitState(UnitState.Unattackable))
return false;
Unit unit = ToUnit();
// visibility checks (only units)
if (unit)
{
// can't attack invisible
if (!bySpell.HasAttribute(SpellAttr6.CanTargetInvisible))
{
if (!unit.CanSeeOrDetect(target, bySpell.IsAffectingArea()))
return false;
/*
else if (!obj)
{
// ignore stealth for aoe spells. Ignore stealth if target is player and unit in combat with same player
bool const ignoreStealthCheck = (bySpell && bySpell.IsAffectingArea()) ||
(target.GetTypeId() == TYPEID_PLAYER && target.HasStealthAura() && IsInCombatWith(target));
if (!CanSeeOrDetect(target, ignoreStealthCheck))
return false;
}
*/
}
}
// can't attack dead
if (!bySpell.IsAllowingDeadTarget() && unitTarget && !unitTarget.IsAlive())
return false;
// can't attack untargetable
if (!bySpell.HasAttribute(SpellAttr6.CanTargetUntargetable) && unitTarget && unitTarget.HasUnitFlag(UnitFlags.NotSelectable))
return false;
Player playerAttacker = ToPlayer();
if (playerAttacker != null)
{
if (playerAttacker.HasPlayerFlag(PlayerFlags.Uber))
return false;
}
// check flags
if (unitTarget != null && unitTarget.HasUnitFlag(UnitFlags.NonAttackable | UnitFlags.TaxiFlight | UnitFlags.NotAttackable1 | UnitFlags.Unk16))
return false;
if (unit != null && !unit.HasUnitFlag(UnitFlags.PvpAttackable) && unitTarget && unitTarget.IsImmuneToNPC())
return false;
if (unitTarget != null && !unitTarget.HasUnitFlag(UnitFlags.PvpAttackable) && unit && unit.IsImmuneToNPC())
return false;
if (!bySpell.HasAttribute(SpellAttr8.AttackIgnoreImmuneToPCFlag))
{
if (unit && unit.HasUnitFlag(UnitFlags.PvpAttackable) && unitTarget && unitTarget.IsImmuneToPC())
return false;
if (unitTarget && unitTarget.HasUnitFlag(UnitFlags.PvpAttackable) && unit && unit.IsImmuneToPC())
return false;
}
// check duel - before sanctuary checks
Player playerAffectingAttacker = unit && unit.HasUnitFlag(UnitFlags.PvpAttackable) ? GetAffectingPlayer() : null;
Player playerAffectingTarget = unitTarget && unitTarget.HasUnitFlag(UnitFlags.PvpAttackable) ? target.GetAffectingPlayer() : null;
if (playerAffectingAttacker && playerAffectingTarget)
if (playerAffectingAttacker.duel != null && playerAffectingAttacker.duel.opponent == playerAffectingTarget && playerAffectingAttacker.duel.startTime != 0)
return true;
// PvP case - can't attack when attacker or target are in sanctuary
// however, 13850 client doesn't allow to attack when one of the unit's has sanctuary flag and is pvp
if (unitTarget && unitTarget.HasUnitFlag(UnitFlags.PvpAttackable) && unit && unit.HasUnitFlag(UnitFlags.PvpAttackable) && (unitTarget.IsInSanctuary() || unit.IsInSanctuary()))
return false;
// additional checks - only PvP case
if (playerAffectingAttacker && playerAffectingTarget)
{
if (unitTarget.IsPvP())
return true;
if (unit.IsFFAPvP() && unitTarget.IsFFAPvP())
return true;
return unit.HasPvpFlag(UnitPVPStateFlags.Unk1) ||
unitTarget.HasPvpFlag(UnitPVPStateFlags.Unk1);
}
return true;
}
// function based on function Unit::CanAssist from 13850 client
public bool IsValidAssistTarget(WorldObject target, SpellInfo bySpell = null, bool spellCheck = true)
{
Cypher.Assert(target != null);
// can assist to self
if (this == target)
return true;
// can't assist GMs
if (target.IsPlayer() && target.ToPlayer().IsGameMaster())
return false;
// can't assist non-friendly targets
if (GetReactionTo(target) < ReputationRank.Neutral && target.GetReactionTo(this) < ReputationRank.Neutral && (!ToCreature() || !ToCreature().GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.TreatAsRaidUnit)))
return false;
if (bySpell == null)
spellCheck = false;
if (spellCheck && !IsValidSpellAssistTarget(target, bySpell))
return false;
return true;
}
public bool IsValidSpellAssistTarget(WorldObject target, SpellInfo bySpell)
{
Cypher.Assert(target != null);
Cypher.Assert(bySpell != null);
// can't assist unattackable units
Unit unitTarget = target.ToUnit();
if (unitTarget && unitTarget.HasUnitState(UnitState.Unattackable))
return false;
// can't assist own vehicle or passenger
Unit unit = ToUnit();
if (unit && unitTarget && unit.GetVehicle())
{
if (unit.IsOnVehicle(unitTarget))
return false;
if (unit.GetVehicleBase().IsOnVehicle(unitTarget))
return false;
}
// can't assist invisible
if (!bySpell.HasAttribute(SpellAttr6.CanTargetInvisible) && !CanSeeOrDetect(target, bySpell.IsAffectingArea()))
return false;
// can't assist dead
if (!bySpell.IsAllowingDeadTarget() && unitTarget && !unitTarget.IsAlive())
return false;
// can't assist untargetable
if (!bySpell.HasAttribute(SpellAttr6.CanTargetUntargetable) && unitTarget && unitTarget.HasUnitFlag(UnitFlags.NotSelectable))
return false;
if (!bySpell.HasAttribute(SpellAttr6.AssistIgnoreImmuneFlag))
{
if (unit && unit.HasUnitFlag(UnitFlags.PvpAttackable))
{
if (unitTarget && unitTarget.IsImmuneToPC())
return false;
}
else
{
if (unitTarget && unitTarget.IsImmuneToNPC())
return false;
}
}
// PvP case
if (unitTarget && unitTarget.HasUnitFlag(UnitFlags.PvpAttackable))
{
Player targetPlayerOwner = target.GetAffectingPlayer();
if (unit && unit.HasUnitFlag(UnitFlags.PvpAttackable))
{
Player selfPlayerOwner = GetAffectingPlayer();
if (selfPlayerOwner && targetPlayerOwner)
{
// can't assist player which is dueling someone
if (selfPlayerOwner != targetPlayerOwner && targetPlayerOwner.duel != null)
return false;
}
// can't assist player in ffa_pvp zone from outside
if (unitTarget.IsFFAPvP() && unit && !unit.IsFFAPvP())
return false;
// can't assist player out of sanctuary from sanctuary if has pvp enabled
if (unitTarget.IsPvP())
if (unit && unit.IsInSanctuary() && !unitTarget.IsInSanctuary())
return false;
}
}
// PvC case - player can assist creature only if has specific type flags
// !target.HasFlag(UNIT_FIELD_FLAGS, UnitFlags.PvpAttackable) &&
else if (unit && unit.HasUnitFlag(UnitFlags.PvpAttackable))
{
if (!bySpell.HasAttribute(SpellAttr6.AssistIgnoreImmuneFlag))
{
if (unitTarget && !unitTarget.IsPvP())
{
Creature creatureTarget = target.ToCreature();
if (creatureTarget != null)
return creatureTarget.GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.TreatAsRaidUnit) || creatureTarget.GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.CanAssist);
}
}
}
return true;
}
public virtual bool CheckAttackFitToAuraRequirement(WeaponAttackType attackType, AuraEffect aurEff) { return true; }
public void ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply)
+5 -24
View File
@@ -55,7 +55,7 @@ namespace Game.Entities
protected float[][] m_weaponDamage = new float[(int)WeaponAttackType.Max][];
uint[] m_baseAttackSpeed = new uint[(int)WeaponAttackType.Max];
float[] m_modAttackSpeedPct = new float[(int)WeaponAttackType.Max];
internal float[] m_modAttackSpeedPct = new float[(int)WeaponAttackType.Max];
protected uint[] m_attackTimer = new uint[(int)WeaponAttackType.Max];
CombatManager m_combatManager;
@@ -117,7 +117,6 @@ namespace Game.Entities
float[] m_floatStatNegBuff = new float[(int)Stats.Max];
public ObjectGuid[] m_SummonSlot = new ObjectGuid[7];
public ObjectGuid[] m_ObjectSlot = new ObjectGuid[4];
public EventSystem m_Events = new();
public UnitTypeMask UnitTypeMask { get; set; }
UnitState m_state;
protected LiquidTypeRecord _lastLiquid;
@@ -498,14 +497,14 @@ namespace Game.Entities
public class DispelInfo
{
public DispelInfo(Unit dispeller, uint dispellerSpellId, byte chargesRemoved)
public DispelInfo(WorldObject dispeller, uint dispellerSpellId, byte chargesRemoved)
{
_dispellerUnit = dispeller;
_dispeller = dispeller;
_dispellerSpell = dispellerSpellId;
_chargesRemoved = chargesRemoved;
}
public Unit GetDispeller() { return _dispellerUnit; }
public WorldObject GetDispeller() { return _dispeller; }
uint GetDispellerSpellId() { return _dispellerSpell; }
public byte GetRemovedCharges() { return _chargesRemoved; }
public void SetRemovedCharges(byte amount)
@@ -513,7 +512,7 @@ namespace Game.Entities
_chargesRemoved = amount;
}
Unit _dispellerUnit;
WorldObject _dispeller;
uint _dispellerSpell;
byte _chargesRemoved;
}
@@ -554,22 +553,4 @@ namespace Game.Entities
{
public StringArray name = new(SharedConst.MaxDeclinedNameCases);
}
class CombatLogSender : IDoWork<Player>
{
CombatLogServerPacket i_message;
public CombatLogSender(CombatLogServerPacket msg)
{
i_message = msg;
}
public void Invoke(Player player)
{
i_message.Clear();
i_message.SetAdvancedCombatLogging(player.IsAdvancedCombatLoggingEnabled());
player.SendPacket(i_message);
}
}
}
+27 -323
View File
@@ -33,19 +33,6 @@ namespace Game.Entities
public void SetInstantCast(bool set) { _instantCast = set; }
public bool CanInstantCast() { return _instantCast; }
// function uses real base points (typically value - 1)
public int CalculateSpellDamage(Unit target, SpellInfo spellProto, uint effect_index, int? basePoints = null, uint castItemId = 0, int itemLevel = -1)
{
SpellEffectInfo effect = spellProto.GetEffect(effect_index);
return effect != null ? effect.CalcValue(this, basePoints, target, castItemId, itemLevel) : 0;
}
public int CalculateSpellDamage(Unit target, SpellInfo spellProto, uint effect_index, out float variance, int? basePoints = null, uint castItemId = 0, int itemLevel = -1)
{
SpellEffectInfo effect = spellProto.GetEffect(effect_index);
variance = 0.0f;
return effect != null ? effect.CalcValue(out variance, this, basePoints, target, castItemId, itemLevel) : 0;
}
public int SpellBaseDamageBonusDone(SpellSchoolMask schoolMask)
{
Player thisPlayer = ToPlayer();
@@ -754,66 +741,8 @@ namespace Game.Entities
return Math.Max(crit_chance, 0.0f);
}
// Calculate spell hit result can be:
// Every spell can: Evade/Immune/Reflect/Sucesful hit
// For melee based spells:
// Miss
// Dodge
// Parry
// For spells
// Resist
public SpellMissInfo SpellHitResult(Unit victim, SpellInfo spellInfo, bool canReflect = false)
{
// All positive spells can`t miss
// @todo client not show miss log for this spells - so need find info for this in dbc and use it!
if (spellInfo.IsPositive()
&& (!IsHostileTo(victim))) // prevent from affecting enemy by "positive" spell
return SpellMissInfo.None;
if (this == victim)
return SpellMissInfo.None;
// Return evade for units in evade mode
if (victim.IsTypeId(TypeId.Unit) && victim.ToCreature().IsEvadingAttacks())
return SpellMissInfo.Evade;
// Try victim reflect spell
if (canReflect)
{
int reflectchance = victim.GetTotalAuraModifier(AuraType.ReflectSpells);
reflectchance += victim.GetTotalAuraModifierByMiscMask(AuraType.ReflectSpellsSchool, (int)spellInfo.GetSchoolMask());
if (reflectchance > 0 && RandomHelper.randChance(reflectchance))
return SpellMissInfo.Reflect;
}
if (spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult))
return SpellMissInfo.None;
// Check for immune
if (victim.IsImmunedToSpell(spellInfo, this))
return SpellMissInfo.Immune;
// Damage immunity is only checked if the spell has damage effects, this immunity must not prevent aura apply
// returns SPELL_MISS_IMMUNE in that case, for other spells, the SMSG_SPELL_GO must show hit
if (spellInfo.HasOnlyDamageEffects() && victim.IsImmunedToDamage(spellInfo))
return SpellMissInfo.Immune;
switch (spellInfo.DmgClass)
{
case SpellDmgClass.Ranged:
case SpellDmgClass.Melee:
return MeleeSpellHitResult(victim, spellInfo);
case SpellDmgClass.None:
return SpellMissInfo.None;
case SpellDmgClass.Magic:
return MagicSpellHitResult(victim, spellInfo);
}
return SpellMissInfo.None;
}
// Melee based spells hit result calculations
SpellMissInfo MeleeSpellHitResult(Unit victim, SpellInfo spellInfo)
public override SpellMissInfo MeleeSpellHitResult(Unit victim, SpellInfo spellInfo)
{
WeaponAttackType attType = WeaponAttackType.BaseAttack;
@@ -949,142 +878,6 @@ namespace Game.Entities
return SpellMissInfo.None;
}
SpellMissInfo MagicSpellHitResult(Unit victim, SpellInfo spell)
{
// Can`t miss on dead target (on skinning for example)
if (!victim.IsAlive() && !victim.IsTypeId(TypeId.Player))
return SpellMissInfo.None;
SpellSchoolMask schoolMask = spell.GetSchoolMask();
// PvP - PvE spell misschances per leveldif > 2
int lchance = victim.IsTypeId(TypeId.Player) ? 7 : 11;
int thisLevel = (int)GetLevelForTarget(victim);
if (IsTypeId(TypeId.Unit) && ToCreature().IsTrigger())
thisLevel = (int)Math.Max(thisLevel, spell.SpellLevel);
int leveldif = (int)(victim.GetLevelForTarget(this)) - thisLevel;
int levelBasedHitDiff = leveldif;
// Base hit chance from attacker and victim levels
int modHitChance;
if (levelBasedHitDiff >= 0)
{
if (!victim.IsTypeId(TypeId.Player))
{
modHitChance = 94 - 3 * Math.Min(levelBasedHitDiff, 3);
levelBasedHitDiff -= 3;
}
else
{
modHitChance = 96 - Math.Min(levelBasedHitDiff, 2);
levelBasedHitDiff -= 2;
}
if (levelBasedHitDiff > 0)
modHitChance -= lchance * Math.Min(levelBasedHitDiff, 7);
}
else
modHitChance = 97 - levelBasedHitDiff;
// Spellmod from SpellModOp.HitChance
Player modOwner = GetSpellModOwner();
if (modOwner != null)
modOwner.ApplySpellMod(spell, SpellModOp.HitChance, ref modHitChance);
// Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will ignore target's avoidance effects
if (!spell.HasAttribute(SpellAttr3.IgnoreHitResult))
{
// Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
modHitChance += victim.GetTotalAuraModifierByMiscMask(AuraType.ModAttackerSpellHitChance, (int)schoolMask);
}
int HitChance = modHitChance * 100;
// Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
HitChance += (int)(modHitChance * 100.0f);
MathFunctions.RoundToInterval(ref HitChance, 0, 10000);
int tmp = 10000 - HitChance;
int rand = RandomHelper.IRand(0, 9999);
if (tmp > 0 && rand < tmp)
return SpellMissInfo.Miss;
// Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore
// resist and deflect chances
if (spell.HasAttribute(SpellAttr3.IgnoreHitResult))
return SpellMissInfo.None;
// Chance resist mechanic (select max value from every mechanic spell effect)
int resist_chance = victim.GetMechanicResistChance(spell) * 100;
// Roll chance
if (resist_chance > 0 && rand < (tmp += resist_chance))
return SpellMissInfo.Resist;
// cast by caster in front of victim
if (!victim.HasUnitState(UnitState.Controlled) && (victim.HasInArc(MathFunctions.PI, this) || victim.HasAuraType(AuraType.IgnoreHitDirection)))
{
int deflect_chance = victim.GetTotalAuraModifier(AuraType.DeflectSpells) * 100;
if (deflect_chance > 0 && rand < (tmp += deflect_chance))
return SpellMissInfo.Deflect;
}
return SpellMissInfo.None;
}
public void CastSpell(SpellCastTargets targets, uint spellId, CastSpellExtraArgs args)
{
if (args == null)
args = new CastSpellExtraArgs();
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, args.CastDifficulty != Difficulty.None ? args.CastDifficulty : GetMap().GetDifficultyID());
if (spellInfo == null)
{
Log.outError(LogFilter.Unit, $"CastSpell: unknown spell {spellId} by caster: {GetGUID()}");
return;
}
Spell spell = new(this, spellInfo, args.TriggerFlags, args.OriginalCaster);
foreach (var pair in args.SpellValueOverrides)
spell.SetSpellValue(pair.Key, pair.Value);
spell.m_CastItem = args.CastItem;
spell.Prepare(targets, args.TriggeringAura);
}
public void CastSpell(WorldObject target, uint spellId, bool triggered)
{
CastSpell(target, spellId, new CastSpellExtraArgs(triggered));
}
public void CastSpell(WorldObject target, uint spellId, CastSpellExtraArgs args = null)
{
SpellCastTargets targets = new();
if (target)
{
Unit unitTarget = target.ToUnit();
GameObject goTarget = target.ToGameObject();
if (unitTarget != null)
targets.SetUnitTarget(unitTarget);
else if (goTarget != null)
targets.SetGOTarget(goTarget);
else
{
Log.outError(LogFilter.Unit, $"CastSpell: Invalid target {target.GetGUID()} passed to spell cast by {GetGUID()}");
return;
}
}
CastSpell(targets, spellId, args);
}
public void CastSpell(Position dest, uint spellId, CastSpellExtraArgs args = null)
{
SpellCastTargets targets = new();
targets.SetDst(dest);
CastSpell(targets, spellId, args);
}
public void FinishSpell(CurrentSpellTypes spellType, bool ok = true)
{
Spell spell = GetCurrentSpell(spellType);
@@ -1223,7 +1016,7 @@ namespace Game.Entities
return spellInfo;
}
public uint GetCastSpellXSpellVisualId(SpellInfo spellInfo)
public override uint GetCastSpellXSpellVisualId(SpellInfo spellInfo)
{
var visualOverrides = GetAuraEffectsByType(AuraType.OverrideSpellVisual);
foreach (AuraEffect effect in visualOverrides)
@@ -1239,7 +1032,7 @@ namespace Game.Entities
}
}
return spellInfo.GetSpellXSpellVisualId(this);
return base.GetCastSpellXSpellVisualId(spellInfo);
}
public SpellHistory GetSpellHistory() { return _spellHistory; }
@@ -1520,7 +1313,7 @@ namespace Game.Entities
}
}
}
public virtual bool IsImmunedToSpell(SpellInfo spellInfo, Unit caster)
public virtual bool IsImmunedToSpell(SpellInfo spellInfo, WorldObject caster)
{
if (spellInfo == null)
return false;
@@ -1617,7 +1410,7 @@ namespace Game.Entities
return mask;
}
public virtual bool IsImmunedToSpellEffect(SpellInfo spellInfo, uint index, Unit caster)
public virtual bool IsImmunedToSpellEffect(SpellInfo spellInfo, uint index, WorldObject caster)
{
if (spellInfo == null)
return false;
@@ -1887,88 +1680,11 @@ namespace Game.Entities
if (GetCurrentSpell(i) != null && GetCurrentSpell(i).m_spellInfo.Id != except_spellid)
InterruptSpell(i, false);
}
public void ModSpellCastTime(SpellInfo spellInfo, ref int castTime, Spell spell = null)
{
if (spellInfo == null || castTime < 0)
return;
// called from caster
Player modOwner = GetSpellModOwner();
if (modOwner != null)
modOwner.ApplySpellMod(spellInfo, SpellModOp.ChangeCastTime, ref castTime, spell);
if (!(spellInfo.HasAttribute(SpellAttr0.Ability | SpellAttr0.Tradespell) || spellInfo.HasAttribute(SpellAttr3.NoDoneBonus))
&& (IsTypeId(TypeId.Player) && spellInfo.SpellFamilyName != 0) || IsTypeId(TypeId.Unit))
castTime = CanInstantCast() ? 0 : (int)(castTime * m_unitData.ModCastingSpeed);
else if (spellInfo.HasAttribute(SpellAttr0.ReqAmmo) && !spellInfo.HasAttribute(SpellAttr2.AutorepeatFlag))
castTime = (int)(castTime * m_modAttackSpeedPct[(int)WeaponAttackType.RangedAttack]);
else if (Global.SpellMgr.IsPartOfSkillLine(SkillType.Cooking, spellInfo.Id) && HasAura(67556)) // cooking with Chef Hat.
castTime = 500;
}
public void ModSpellDurationTime(SpellInfo spellInfo, ref int duration, Spell spell = null)
{
if (spellInfo == null || duration < 0)
return;
if (spellInfo.IsChanneled() && !spellInfo.HasAttribute(SpellAttr5.HasteAffectDuration))
return;
// called from caster
Player modOwner = GetSpellModOwner();
if (modOwner)
modOwner.ApplySpellMod(spellInfo, SpellModOp.ChangeCastTime, ref duration, spell);
if (!(spellInfo.HasAttribute(SpellAttr0.Ability) || spellInfo.HasAttribute(SpellAttr0.Tradespell) || spellInfo.HasAttribute(SpellAttr3.NoDoneBonus)) &&
(IsTypeId(TypeId.Player) && spellInfo.SpellFamilyName != 0) || IsTypeId(TypeId.Unit))
duration = (int)(duration * m_unitData.ModCastingSpeed);
else if (spellInfo.HasAttribute(SpellAttr0.ReqAmmo) && !spellInfo.HasAttribute(SpellAttr2.AutorepeatFlag))
duration = (int)(duration * m_modAttackSpeedPct[(int)WeaponAttackType.RangedAttack]);
}
public float ApplyEffectModifiers(SpellInfo spellProto, uint effect_index, float value)
{
Player modOwner = GetSpellModOwner();
if (modOwner != null)
{
modOwner.ApplySpellMod(spellProto, SpellModOp.Points, ref value);
switch (effect_index)
{
case 0:
modOwner.ApplySpellMod(spellProto, SpellModOp.PointsIndex0, ref value);
break;
case 1:
modOwner.ApplySpellMod(spellProto, SpellModOp.PointsIndex1, ref value);
break;
case 2:
modOwner.ApplySpellMod(spellProto, SpellModOp.PointsIndex2, ref value);
break;
case 3:
modOwner.ApplySpellMod(spellProto, SpellModOp.PointsIndex3, ref value);
break;
case 4:
modOwner.ApplySpellMod(spellProto, SpellModOp.PointsIndex4, ref value);
break;
}
}
return value;
}
public ushort GetMaxSkillValueForLevel(Unit target = null)
{
return (ushort)(target != null ? GetLevelForTarget(target) : GetLevel() * 5);
}
public Player GetSpellModOwner()
{
if (IsTypeId(TypeId.Player))
return ToPlayer();
if (HasUnitTypeMask(UnitTypeMask.Pet | UnitTypeMask.Totem | UnitTypeMask.Guardian))
{
Unit owner = GetOwner();
if (owner != null && owner.IsTypeId(TypeId.Player))
return owner.ToPlayer();
}
return null;
}
public Spell GetCurrentSpell(CurrentSpellTypes spellType)
{
@@ -2283,7 +1999,6 @@ namespace Game.Entities
// update for out of range group members (on 1 slot use)
aura.SetNeedClientUpdateForTargets();
Log.outDebug(LogFilter.Spells, "Aura {0} partially interrupted on {1}, new duration: {2} ms", aura.GetId(), GetGUID().ToString(), aura.GetDuration());
}
}
}
@@ -2641,7 +2356,7 @@ namespace Game.Entities
diminish.HitCount = currentLevel + 1;
}
public bool ApplyDiminishingToDuration(SpellInfo auraSpellInfo, ref int duration, Unit caster, DiminishingLevels previousLevel)
public bool ApplyDiminishingToDuration(SpellInfo auraSpellInfo, ref int duration, WorldObject caster, DiminishingLevels previousLevel)
{
DiminishingGroup group = auraSpellInfo.GetDiminishingReturnsGroupForSpell();
if (duration == -1 || group == DiminishingGroup.None)
@@ -2656,7 +2371,7 @@ namespace Game.Entities
if (limitDuration > 0 && duration > limitDuration)
{
Unit target = targetOwner ?? this;
Unit source = casterOwner ?? caster;
WorldObject source = casterOwner ?? caster;
if (target.IsAffectedByDiminishingReturns() && source.IsPlayer())
duration = limitDuration;
@@ -2863,9 +2578,6 @@ namespace Game.Entities
if (spellInfo == null)
return null;
if (!target.IsAlive() && !spellInfo.IsPassive() && !spellInfo.HasAttribute(SpellAttr2.CanTargetDead))
return null;
return AddAura(spellInfo, SpellConst.MaxEffectMask, target);
}
@@ -2874,6 +2586,9 @@ namespace Game.Entities
if (spellInfo == null)
return null;
if (!target.IsAlive() && !spellInfo.IsPassive() && !spellInfo.HasAttribute(SpellAttr2.CanTargetDead))
return null;
if (target.IsImmunedToSpell(spellInfo, this))
return null;
@@ -3037,29 +2752,6 @@ namespace Game.Entities
return false;
}
// target dependent range checks
public float GetSpellMaxRangeForTarget(Unit target, SpellInfo spellInfo)
{
if (spellInfo.RangeEntry == null)
return 0;
if (spellInfo.RangeEntry.RangeMax[0] == spellInfo.RangeEntry.RangeMax[1])
return spellInfo.GetMaxRange();
if (!target)
return spellInfo.GetMaxRange(true);
return spellInfo.GetMaxRange(!IsHostileTo(target));
}
public float GetSpellMinRangeForTarget(Unit target, SpellInfo spellInfo)
{
if (spellInfo.RangeEntry == null)
return 0;
if (spellInfo.RangeEntry.RangeMin[0] == spellInfo.RangeEntry.RangeMin[1])
return spellInfo.GetMinRange();
if (!target)
return spellInfo.GetMinRange(true);
return spellInfo.GetMinRange(!IsHostileTo(target));
}
public bool HasAuraType(AuraType auraType)
{
return !m_modAuras.LookupByKey(auraType).Empty();
@@ -3177,7 +2869,7 @@ namespace Game.Entities
return null;
}
public List<DispelableAura> GetDispellableAuraList(Unit caster, uint dispelMask, bool isReflect = false)
public List<DispelableAura> GetDispellableAuraList(WorldObject caster, uint dispelMask, bool isReflect = false)
{
List<DispelableAura> dispelList = new();
@@ -3311,7 +3003,7 @@ namespace Game.Entities
}
}
}
public void RemoveAurasDueToSpellBySteal(uint spellId, ObjectGuid casterGUID, Unit stealer)
public void RemoveAurasDueToSpellBySteal(uint spellId, ObjectGuid casterGUID, WorldObject stealer)
{
var range = m_ownedAuras.LookupByKey(spellId);
foreach (var aura in range)
@@ -3344,7 +3036,10 @@ namespace Game.Entities
// Cast duration to unsigned to prevent permanent aura's such as Righteous Fury being permanently added to caster
uint dur = (uint)Math.Min(2u * Time.Minute * Time.InMilliseconds, aura.GetDuration());
Aura oldAura = stealer.GetAura(aura.GetId(), aura.GetCasterGUID());
Unit unitStealer = stealer.ToUnit();
if (unitStealer != null)
{
Aura oldAura = unitStealer.GetAura(aura.GetId(), aura.GetCasterGUID());
if (oldAura != null)
{
if (stealCharge)
@@ -3379,6 +3074,7 @@ namespace Game.Entities
newAura.ApplyForTargets();
}
}
}
if (stealCharge)
aura.ModCharges(-1, AuraRemoveMode.EnemySpell);
@@ -3524,7 +3220,7 @@ namespace Game.Entities
}
}
}
public void RemoveAurasDueToSpellByDispel(uint spellId, uint dispellerSpellId, ObjectGuid casterGUID, Unit dispeller, byte chargesRemoved = 1)
public void RemoveAurasDueToSpellByDispel(uint spellId, uint dispellerSpellId, ObjectGuid casterGUID, WorldObject dispeller, byte chargesRemoved = 1)
{
foreach (var pair in GetOwnedAuras())
{
@@ -4270,6 +3966,14 @@ namespace Game.Entities
if (createInfo.CasterGUID.IsEmpty() && !createInfo.GetSpellInfo().IsStackableOnOneSlotWithDifferentCasters())
createInfo.CasterGUID = createInfo.Caster.GetGUID();
// world gameobjects can't own auras and they send empty casterguid
// checked on sniffs with spell 22247
if (createInfo.CasterGUID.IsGameObject())
{
createInfo.Caster = null;
createInfo.CasterGUID.Clear();
}
// passive and Incanter's Absorption and auras with different type can stack with themselves any number of times
if (!createInfo.GetSpellInfo().IsMultiSlotAura())
{
@@ -4612,7 +4316,7 @@ namespace Game.Entities
});
}
int GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int miscValue)
public int GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int miscValue)
{
return GetMaxNegativeAuraModifier(auratype, aurEff =>
{
+63 -315
View File
@@ -1394,101 +1394,6 @@ namespace Game.Entities
SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.ShapeshiftForm), (byte)form);
}
public int CalcSpellDuration(SpellInfo spellProto)
{
sbyte comboPoints = (sbyte)(m_playerMovingMe != null ? m_playerMovingMe.GetComboPoints() : 0);
int minduration = spellProto.GetDuration();
int maxduration = spellProto.GetMaxDuration();
int duration;
if (comboPoints != 0 && minduration != -1 && minduration != maxduration)
duration = minduration + (maxduration - minduration) * comboPoints / 5;
else
duration = minduration;
return duration;
}
public int ModSpellDuration(SpellInfo spellProto, Unit target, int duration, bool positive, uint effectMask)
{
// don't mod permanent auras duration
if (duration < 0)
return duration;
// some auras are not affected by duration modifiers
if (spellProto.HasAttribute(SpellAttr7.IgnoreDurationMods))
return duration;
// cut duration only of negative effects
if (!positive)
{
uint mechanic = spellProto.GetSpellMechanicMaskByEffectMask(effectMask);
int durationMod;
int durationMod_always = 0;
int durationMod_not_stack = 0;
for (byte i = 1; i <= (int)Mechanics.Enraged; ++i)
{
if (!Convert.ToBoolean(mechanic & 1 << i))
continue;
// Find total mod value (negative bonus)
int new_durationMod_always = target.GetTotalAuraModifierByMiscValue(AuraType.MechanicDurationMod, i);
// Find max mod (negative bonus)
int new_durationMod_not_stack = target.GetMaxNegativeAuraModifierByMiscValue(AuraType.MechanicDurationModNotStack, i);
// Check if mods applied before were weaker
if (new_durationMod_always < durationMod_always)
durationMod_always = new_durationMod_always;
if (new_durationMod_not_stack < durationMod_not_stack)
durationMod_not_stack = new_durationMod_not_stack;
}
// Select strongest negative mod
if (durationMod_always > durationMod_not_stack)
durationMod = durationMod_not_stack;
else
durationMod = durationMod_always;
if (durationMod != 0)
MathFunctions.AddPct(ref duration, durationMod);
// there are only negative mods currently
durationMod_always = target.GetTotalAuraModifierByMiscValue(AuraType.ModAuraDurationByDispel, (int)spellProto.Dispel);
durationMod_not_stack = target.GetMaxNegativeAuraModifierByMiscValue(AuraType.ModAuraDurationByDispelNotStack, (int)spellProto.Dispel);
durationMod = 0;
if (durationMod_always > durationMod_not_stack)
durationMod += durationMod_not_stack;
else
durationMod += durationMod_always;
if (durationMod != 0)
MathFunctions.AddPct(ref duration, durationMod);
}
else
{
// else positive mods here, there are no currently
// when there will be, change GetTotalAuraModifierByMiscValue to GetTotalPositiveAuraModifierByMiscValue
// Mixology - duration boost
if (target.IsTypeId(TypeId.Player))
{
if (spellProto.SpellFamilyName == SpellFamilyNames.Potion && (
Global.SpellMgr.IsSpellMemberOfSpellGroup(spellProto.Id, SpellGroup.ElixirBattle) ||
Global.SpellMgr.IsSpellMemberOfSpellGroup(spellProto.Id, SpellGroup.ElixirGuardian)))
{
SpellEffectInfo effect = spellProto.GetEffect(0);
if (target.HasAura(53042) && effect != null && target.HasSpell(effect.TriggerSpell))
duration *= 2;
}
}
}
return Math.Max(duration, 0);
}
// creates aura application instance and registers it in lists
// aura application effects are handled separately to prevent aura list corruption
public AuraApplication _CreateAuraApplication(Aura aura, uint effMask)
@@ -1528,8 +1433,8 @@ namespace Game.Entities
return aurApp;
}
bool HasInterruptFlag(SpellAuraInterruptFlags flags) { return m_interruptMask.HasFlag(flags); }
bool HasInterruptFlag(SpellAuraInterruptFlags2 flags) { return m_interruptMask2.HasFlag(flags); }
bool HasInterruptFlag(SpellAuraInterruptFlags flags) { return m_interruptMask.HasAnyFlag(flags); }
bool HasInterruptFlag(SpellAuraInterruptFlags2 flags) { return m_interruptMask2.HasAnyFlag(flags); }
public void AddInterruptMask(SpellAuraInterruptFlags flags, SpellAuraInterruptFlags2 flags2)
{
@@ -1649,26 +1554,6 @@ namespace Game.Entities
RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Sheathing);
}
public FactionTemplateRecord GetFactionTemplateEntry()
{
FactionTemplateRecord entry = CliDB.FactionTemplateStorage.LookupByKey(GetFaction());
if (entry == null)
{
Player player = ToPlayer();
if (player != null)
Log.outError(LogFilter.Unit, "Player {0} has invalid faction (faction template id) #{1}", player.GetName(), GetFaction());
else
{
Creature creature = ToCreature();
if (creature != null)
Log.outError(LogFilter.Unit, "Creature (template id: {0}) has invalid faction (faction template id) #{1}", creature.GetCreatureTemplate().Entry, GetFaction());
else
Log.outError(LogFilter.Unit, "Unit (name={0}, type={1}) has invalid faction (faction template id) #{2}", GetName(), GetTypeId(), GetFaction());
}
}
return entry;
}
public bool IsInFeralForm()
{
ShapeShiftForm form = GetShapeshiftForm();
@@ -1902,17 +1787,9 @@ namespace Game.Entities
public uint GetMountDisplayId() { return m_unitData.MountDisplayID; }
public void SetMountDisplayId(uint mountDisplayId) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.MountDisplayID), mountDisplayId); }
public virtual Unit GetOwner()
{
ObjectGuid ownerid = GetOwnerGUID();
if (!ownerid.IsEmpty())
return Global.ObjAccessor.GetUnit(this, ownerid);
return null;
}
public virtual float GetFollowAngle() { return MathFunctions.PiOver2; }
public ObjectGuid GetOwnerGUID() { return m_unitData.SummonedBy; }
public override ObjectGuid GetOwnerGUID() { return m_unitData.SummonedBy; }
public void SetOwnerGUID(ObjectGuid owner)
{
if (GetOwnerGUID() == owner)
@@ -1947,18 +1824,10 @@ namespace Game.Entities
public void SetCritterGUID(ObjectGuid guid) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.Critter), guid); }
public ObjectGuid GetBattlePetCompanionGUID() { return m_unitData.BattlePetCompanionGUID; }
public void SetBattlePetCompanionGUID(ObjectGuid guid) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.BattlePetCompanionGUID), guid); }
public ObjectGuid GetCharmerOrOwnerGUID()
public override ObjectGuid GetCharmerOrOwnerGUID()
{
return !GetCharmerGUID().IsEmpty() ? GetCharmerGUID() : GetOwnerGUID();
}
public ObjectGuid GetCharmerOrOwnerOrOwnGUID()
{
ObjectGuid guid = GetCharmerOrOwnerGUID();
if (!guid.IsEmpty())
return guid;
return GetGUID();
}
public Unit GetCharmer()
{
ObjectGuid charmerid = GetCharmerGUID();
@@ -1966,22 +1835,6 @@ namespace Game.Entities
return Global.ObjAccessor.GetUnit(this, charmerid);
return null;
}
public Unit GetCharmerOrOwnerOrSelf()
{
Unit u = GetCharmerOrOwner();
if (u != null)
return u;
return this;
}
public Player GetCharmerOrOwnerPlayerOrPlayerItself()
{
ObjectGuid guid = GetCharmerOrOwnerGUID();
if (guid.IsPlayer())
return Global.ObjAccessor.FindPlayer(guid);
return IsTypeId(TypeId.Player) ? ToPlayer() : null;
}
public Unit GetCharmerOrOwner()
{
return !GetCharmerGUID().IsEmpty() ? GetCharmer() : GetOwner();
@@ -2044,16 +1897,6 @@ namespace Game.Entities
else
return ToCreature().GetCreatureTemplate().CreatureType;
}
public Player GetAffectingPlayer()
{
if (GetCharmerOrOwnerGUID().IsEmpty())
return IsTypeId(TypeId.Player) ? ToPlayer() : null;
Unit owner = GetCharmerOrOwner();
if (owner != null)
return owner.GetCharmerOrOwnerPlayerOrPlayerItself();
return null;
}
public void DeMorph()
{
@@ -2079,7 +1922,7 @@ namespace Game.Entities
}
public bool HasUnitState(UnitState f)
{
return m_state.HasFlag(f);
return m_state.HasAnyFlag(f);
}
public void ClearUnitState(UnitState f)
{
@@ -2113,146 +1956,8 @@ namespace Game.Entities
return false;
}
//Faction
public bool IsNeutralToAll()
{
var my_faction = GetFactionTemplateEntry();
if (my_faction == null || my_faction.Faction == 0)
return true;
var raw_faction = CliDB.FactionStorage.LookupByKey(my_faction.Faction);
if (raw_faction != null && raw_faction.ReputationIndex >= 0)
return false;
return my_faction.IsNeutralToAll();
}
public bool IsHostileTo(Unit unit)
{
return GetReactionTo(unit) <= ReputationRank.Hostile;
}
public bool IsFriendlyTo(Unit unit)
{
return GetReactionTo(unit) >= ReputationRank.Friendly;
}
public ReputationRank GetReactionTo(Unit target)
{
// always friendly to self
if (this == target)
return ReputationRank.Friendly;
// always friendly to charmer or owner
if (GetCharmerOrOwnerOrSelf() == target.GetCharmerOrOwnerOrSelf())
return ReputationRank.Friendly;
if (HasUnitFlag(UnitFlags.PvpAttackable))
{
if (target.HasUnitFlag(UnitFlags.PvpAttackable))
{
Player selfPlayerOwner = GetAffectingPlayer();
Player targetPlayerOwner = target.GetAffectingPlayer();
if (selfPlayerOwner != null && targetPlayerOwner != null)
{
// always friendly to other unit controlled by player, or to the player himself
if (selfPlayerOwner == targetPlayerOwner)
return ReputationRank.Friendly;
// duel - always hostile to opponent
if (selfPlayerOwner.duel != null && selfPlayerOwner.duel.opponent == targetPlayerOwner && selfPlayerOwner.duel.startTime != 0)
return ReputationRank.Hostile;
// same group - checks dependant only on our faction - skip FFA_PVP for example
if (selfPlayerOwner.IsInRaidWith(targetPlayerOwner))
return ReputationRank.Friendly; // return true to allow config option AllowTwoSide.Interaction.Group to work
}
// check FFA_PVP
if (IsFFAPvP() && target.IsFFAPvP())
return ReputationRank.Hostile;
if (selfPlayerOwner != null)
{
var targetFactionTemplateEntry = target.GetFactionTemplateEntry();
if (targetFactionTemplateEntry != null)
{
if (!selfPlayerOwner.HasUnitFlag2(UnitFlags2.IgnoreReputation))
{
var targetFactionEntry = CliDB.FactionStorage.LookupByKey(targetFactionTemplateEntry.Faction);
if (targetFactionEntry != null)
{
if (targetFactionEntry.CanHaveReputation())
{
// check contested flags
if (Convert.ToBoolean(targetFactionTemplateEntry.Flags & (uint)FactionTemplateFlags.ContestedGuard)
&& selfPlayerOwner.HasPlayerFlag(PlayerFlags.ContestedPVP))
return ReputationRank.Hostile;
// if faction has reputation, hostile state depends only from AtWar state
if (selfPlayerOwner.GetReputationMgr().IsAtWar(targetFactionEntry))
return ReputationRank.Hostile;
return ReputationRank.Friendly;
}
}
}
}
}
}
}
// do checks dependant only on our faction
return GetFactionReactionTo(GetFactionTemplateEntry(), target);
}
ReputationRank GetFactionReactionTo(FactionTemplateRecord factionTemplateEntry, Unit target)
{
// always neutral when no template entry found
if (factionTemplateEntry == null)
return ReputationRank.Neutral;
var targetFactionTemplateEntry = target.GetFactionTemplateEntry();
if (targetFactionTemplateEntry == null)
return ReputationRank.Neutral;
Player targetPlayerOwner = target.GetAffectingPlayer();
if (targetPlayerOwner != null)
{
// check contested flags
if (Convert.ToBoolean(factionTemplateEntry.Flags & (uint)FactionTemplateFlags.ContestedGuard)
&& targetPlayerOwner.HasPlayerFlag(PlayerFlags.ContestedPVP))
return ReputationRank.Hostile;
ReputationRank repRank = targetPlayerOwner.GetReputationMgr().GetForcedRankIfAny(factionTemplateEntry);
if (repRank != ReputationRank.None)
return repRank;
if (!target.HasUnitFlag2(UnitFlags2.IgnoreReputation))
{
var factionEntry = CliDB.FactionStorage.LookupByKey(factionTemplateEntry.Faction);
if (factionEntry != null)
{
if (factionEntry.CanHaveReputation())
{
// CvP case - check reputation, don't allow state higher than neutral when at war
repRank = targetPlayerOwner.GetReputationMgr().GetRank(factionEntry);
if (targetPlayerOwner.GetReputationMgr().IsAtWar(factionEntry))
repRank = (ReputationRank)Math.Min((int)ReputationRank.Neutral, (int)repRank);
return repRank;
}
}
}
}
// common faction based check
if (factionTemplateEntry.IsHostileTo(targetFactionTemplateEntry))
return ReputationRank.Hostile;
if (factionTemplateEntry.IsFriendlyTo(targetFactionTemplateEntry))
return ReputationRank.Friendly;
if (targetFactionTemplateEntry.IsFriendlyTo(factionTemplateEntry))
return ReputationRank.Friendly;
if (Convert.ToBoolean(factionTemplateEntry.Flags & (uint)FactionTemplateFlags.HostileByDefault))
return ReputationRank.Hostile;
// neutral by default
return ReputationRank.Neutral;
}
public uint GetFaction() { return m_unitData.FactionTemplate; }
public void SetFaction(uint faction) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.FactionTemplate), faction); }
public override uint GetFaction() { return m_unitData.FactionTemplate; }
public override void SetFaction(uint faction) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.FactionTemplate), faction); }
public void RestoreFaction()
{
@@ -2834,11 +2539,9 @@ namespace Game.Entities
}
}
if (damagetype != DamageEffectType.NoDamage)
if (damagetype != DamageEffectType.NoDamage && damagetype != DamageEffectType.DOT)
{
if (victim != attacker && (spellProto == null || !(spellProto.HasAttribute(SpellAttr7.NoPushbackOnDamage) || spellProto.HasAttribute(SpellAttr3.TreatAsPeriodic))))
{
if (damagetype != DamageEffectType.DOT)
{
Spell spell = victim.GetCurrentSpell(CurrentSpellTypes.Generic);
if (spell != null)
@@ -2887,7 +2590,7 @@ namespace Game.Entities
if (spell1.GetState() == SpellState.Casting && spell1.m_spellInfo.HasChannelInterruptFlag(SpellAuraInterruptFlags.DamageChannelDuration))
spell1.DelayedChannel();
}
}
}
}
@@ -3322,6 +3025,47 @@ namespace Game.Entities
return nearMembers[randTarget];
}
public uint GetComboPoints() { return (uint)GetPower(PowerType.ComboPoints); }
public void AddComboPoints(sbyte count, Spell spell = null)
{
if (count == 0)
return;
sbyte comboPoints = (sbyte)(spell != null ? spell.m_comboPointGain : GetPower(PowerType.ComboPoints));
comboPoints += count;
if (comboPoints > 5)
comboPoints = 5;
else if (comboPoints < 0)
comboPoints = 0;
if (!spell)
SetPower(PowerType.ComboPoints, comboPoints);
else
spell.m_comboPointGain = comboPoints;
}
void GainSpellComboPoints(sbyte count)
{
if (count == 0)
return;
sbyte cp = (sbyte)GetPower(PowerType.ComboPoints);
cp += count;
if (cp > 5) cp = 5;
else if (cp < 0) cp = 0;
SetPower(PowerType.ComboPoints, cp);
}
public void ClearComboPoints()
{
SetPower(PowerType.ComboPoints, 0);
}
public void ClearAllReactives()
{
for (ReactiveType i = 0; i < ReactiveType.Max; ++i)
@@ -3411,22 +3155,25 @@ namespace Game.Entities
return (uint)damageResisted;
}
static float CalculateAverageResistReduction(Unit attacker, SpellSchoolMask schoolMask, Unit victim, SpellInfo spellInfo = null)
static float CalculateAverageResistReduction(WorldObject caster, SpellSchoolMask schoolMask, Unit victim, SpellInfo spellInfo = null)
{
float victimResistance = victim.GetResistance(schoolMask);
if (attacker != null)
if (caster != null)
{
// pets inherit 100% of masters penetration
// excluding traps
Player player = attacker.GetSpellModOwner();
if (player != null && attacker.GetEntry() != SharedConst.WorldTrigger)
Player player = caster.GetSpellModOwner();
if (player != null)
{
victimResistance += player.GetTotalAuraModifierByMiscMask(AuraType.ModTargetResistance, (int)schoolMask);
victimResistance -= player.GetSpellPenetrationItemMod();
}
else
victimResistance += attacker.GetTotalAuraModifierByMiscMask(AuraType.ModTargetResistance, (int)schoolMask);
{
Unit unitCaster = caster.ToUnit();
if (unitCaster != null)
victimResistance += unitCaster.GetTotalAuraModifierByMiscMask(AuraType.ModTargetResistance, (int)schoolMask);
}
}
// holy resistance exists in pve and comes from level difference, ignore template values
@@ -3440,12 +3187,13 @@ namespace Game.Entities
victimResistance = Math.Max(victimResistance, 0.0f);
// level-based resistance does not apply to binary spells, and cannot be overcome by spell penetration
if (attacker != null && (spellInfo == null || !spellInfo.HasAttribute(SpellCustomAttributes.BinarySpell)))
victimResistance += Math.Max(((float)victim.GetLevelForTarget(attacker) - (float)attacker.GetLevelForTarget(victim)) * 5.0f, 0.0f);
// gameobject caster -- should it have level based resistance?
if (caster != null && !caster.IsGameObject() && (spellInfo == null || !spellInfo.HasAttribute(SpellCustomAttributes.BinarySpell)))
victimResistance += Math.Max(((float)victim.GetLevelForTarget(caster) - (float)caster.GetLevelForTarget(victim)) * 5.0f, 0.0f);
uint bossLevel = 83;
float bossResistanceConstant = 510.0f;
uint level = attacker != null ? victim.GetLevelForTarget(attacker) : attacker.GetLevel();
uint level = caster ? victim.GetLevelForTarget(caster) : victim.GetLevel();
float resistanceConstant;
if (level == bossLevel)
+2 -2
View File
@@ -2331,9 +2331,9 @@ namespace Game.Guilds
return m_achievementSys.HasAchieved(achievementId);
}
public void UpdateCriteria(CriteriaTypes type, ulong miscValue1, ulong miscValue2, ulong miscValue3, Unit unit, Player player)
public void UpdateCriteria(CriteriaTypes type, ulong miscValue1, ulong miscValue2, ulong miscValue3, WorldObject refe, Player player)
{
m_achievementSys.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, player);
m_achievementSys.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, refe, player);
}
public void HandleNewsSetSticky(WorldSession session, uint newsId, bool sticky)
+10 -14
View File
@@ -2577,27 +2577,26 @@ namespace Game.Maps
class GameObjectFocusCheck : ICheck<GameObject>
{
public GameObjectFocusCheck(Unit unit, uint focusId)
public GameObjectFocusCheck(WorldObject caster, uint focusId)
{
i_unit = unit;
i_focusId = focusId;
_caster = caster;
_focusId = focusId;
}
public bool Invoke(GameObject go)
{
if (go.GetGoInfo().GetSpellFocusType() != i_focusId)
if (go.GetGoInfo().GetSpellFocusType() != _focusId)
return false;
if (!go.IsSpawned())
return false;
float dist = go.GetGoInfo().GetSpellFocusRadius() / 2.0f;
return go.IsWithinDistInMap(i_unit, dist);
return go.IsWithinDistInMap(_caster, dist);
}
Unit i_unit;
uint i_focusId;
WorldObject _caster;
uint _focusId;
}
// Find the nearest Fishing hole and return true only if source object is in range of hole
@@ -2697,7 +2696,7 @@ namespace Game.Maps
public class AnyDeadUnitObjectInRangeCheck<T> : ICheck<T> where T : WorldObject
{
public AnyDeadUnitObjectInRangeCheck(Unit searchObj, float range)
public AnyDeadUnitObjectInRangeCheck(WorldObject searchObj, float range)
{
i_searchObj = searchObj;
i_range = range;
@@ -2720,16 +2719,14 @@ namespace Game.Maps
return false;
}
Unit i_searchObj;
WorldObject i_searchObj;
float i_range;
}
public class AnyDeadUnitSpellTargetInRangeCheck<T> : AnyDeadUnitObjectInRangeCheck<T> where T : WorldObject
{
public AnyDeadUnitSpellTargetInRangeCheck(Unit searchObj, float range, SpellInfo spellInfo, SpellTargetCheckTypes check, SpellTargetObjectTypes objectType)
: base(searchObj, range)
public AnyDeadUnitSpellTargetInRangeCheck(WorldObject searchObj, float range, SpellInfo spellInfo, SpellTargetCheckTypes check, SpellTargetObjectTypes objectType) : base(searchObj, range)
{
i_spellInfo = spellInfo;
i_check = new WorldObjectSpellTargetCheck(searchObj, searchObj, spellInfo, check, null, objectType);
}
@@ -2738,7 +2735,6 @@ namespace Game.Maps
return base.Invoke(obj) && i_check.Invoke(obj);
}
SpellInfo i_spellInfo;
WorldObjectSpellTargetCheck i_check;
}
+1 -1
View File
@@ -4994,7 +4994,7 @@ namespace Game.Maps
List<WorldObject> _updateObjects = new();
delegate void FarSpellCallback(Map map);
public delegate void FarSpellCallback(Map map);
Queue<FarSpellCallback> _farSpellCallbacks = new();
#endregion
}
@@ -23,7 +23,7 @@ using System.Collections.Generic;
namespace Game.Networking.Packets
{
class CombatLogServerPacket : ServerPacket
public class CombatLogServerPacket : ServerPacket
{
public CombatLogServerPacket(ServerOpcodes opcode, ConnectionType connection = ConnectionType.Realm) : base(opcode, connection)
{
+11 -7
View File
@@ -1181,21 +1181,25 @@ namespace Game.Networking.Packets
public void Initialize(Spell spell)
{
Health = (long)spell.GetCaster().GetHealth();
AttackPower = (int)spell.GetCaster().GetTotalAttackPowerValue(spell.GetCaster().GetClass() == Class.Hunter ? WeaponAttackType.RangedAttack : WeaponAttackType.BaseAttack);
SpellPower = spell.GetCaster().SpellBaseDamageBonusDone(SpellSchoolMask.Spell);
Armor = spell.GetCaster().GetArmor();
PowerType primaryPowerType = spell.GetCaster().GetPowerType();
Unit unitCaster = spell.GetCaster().ToUnit();
if (unitCaster != null)
{
Health = (long)unitCaster.GetHealth();
AttackPower = (int)unitCaster.GetTotalAttackPowerValue(unitCaster.GetClass() == Class.Hunter ? WeaponAttackType.RangedAttack : WeaponAttackType.BaseAttack);
SpellPower = unitCaster.SpellBaseDamageBonusDone(SpellSchoolMask.Spell);
Armor = unitCaster.GetArmor();
PowerType primaryPowerType = unitCaster.GetPowerType();
bool primaryPowerAdded = false;
foreach (SpellPowerCost cost in spell.GetPowerCost())
{
PowerData.Add(new SpellLogPowerData((int)cost.Power, spell.GetCaster().GetPower(cost.Power), cost.Amount));
PowerData.Add(new SpellLogPowerData((int)cost.Power, unitCaster.GetPower(cost.Power), (int)cost.Amount));
if (cost.Power == primaryPowerType)
primaryPowerAdded = true;
}
if (!primaryPowerAdded)
PowerData.Insert(0, new SpellLogPowerData((int)primaryPowerType, spell.GetCaster().GetPower(primaryPowerType), 0));
PowerData.Insert(0, new SpellLogPowerData((int)primaryPowerType, unitCaster.GetPower(primaryPowerType), 0));
}
}
public void Write(WorldPacket data)
+2 -2
View File
@@ -540,7 +540,7 @@ namespace Game
return;
// always invisible or hidden faction can't change war state
if (factionState.Flags.HasFlag(ReputationFlags.Hidden | ReputationFlags.Header))
if (factionState.Flags.HasAnyFlag(ReputationFlags.Hidden | ReputationFlags.Header))
return;
SetAtWar(factionState, on);
@@ -577,7 +577,7 @@ namespace Game
void SetInactive(FactionState faction, bool inactive)
{
// always invisible or hidden faction can't be inactive
if (faction.Flags.HasFlag(ReputationFlags.Hidden | ReputationFlags.Header) || !faction.Flags.HasFlag(ReputationFlags.Visible))
if (faction.Flags.HasAnyFlag(ReputationFlags.Hidden | ReputationFlags.Header) || !faction.Flags.HasFlag(ReputationFlags.Visible))
return;
// already set
+19 -2
View File
@@ -536,7 +536,8 @@ namespace Game.Scripting
// methods allowing interaction with Spell object
//
// methods useable during all spell handling phases
public Unit GetCaster() { return m_spell.GetCaster(); }
public Unit GetCaster() { return m_spell.GetCaster().ToUnit(); }
public GameObject GetGObjCaster() { return m_spell.GetCaster().ToGameObject(); }
public Unit GetOriginalCaster() { return m_spell.GetOriginalCaster(); }
public SpellInfo GetSpellInfo() { return m_spell.GetSpellInfo(); }
public Difficulty GetCastDifficulty() { return m_spell.GetCastDifficulty(); }
@@ -1453,7 +1454,23 @@ namespace Game.Scripting
// returns guid of object which casted the aura (m_originalCaster of the Spell class)
public ObjectGuid GetCasterGUID() { return m_aura.GetCasterGUID(); }
// returns unit which casted the aura or null if not avalible (caster logged out for example)
public Unit GetCaster() { return m_aura.GetCaster(); }
public Unit GetCaster()
{
WorldObject caster = m_aura.GetCaster();
if (caster != null)
return caster.ToUnit();
return null;
}
// returns gameobject which cast the aura or NULL if not available
public GameObject GetGObjCaster()
{
WorldObject caster = m_aura.GetCaster();
if (caster != null)
return caster.ToGameObject();
return null;
}
// returns object on which aura was casted, target for non-area auras, area aura source for area auras
public WorldObject GetOwner() { return m_aura.GetOwner(); }
// returns owner if it's unit or unit derived object, null otherwise (only for persistent area auras null is returned)
+15 -9
View File
@@ -330,7 +330,7 @@ namespace Game.Spells
m_spellInfo = createInfo._spellInfo;
m_castDifficulty = createInfo._castDifficulty;
m_castGuid = createInfo._castId;
m_casterGuid = createInfo.CasterGUID.IsEmpty() ? createInfo.Caster.GetGUID() : createInfo.CasterGUID;
m_casterGuid = createInfo.CasterGUID;
m_castItemGuid = createInfo.CastItemGUID;
m_castItemId = createInfo.CastItemId;
m_castItemLevel = createInfo.CastItemLevel;
@@ -2457,8 +2457,6 @@ namespace Game.Spells
public static Aura TryCreate(AuraCreateInfo createInfo)
{
Cypher.Assert(createInfo.Caster != null || !createInfo.CasterGUID.IsEmpty());
uint effMask = createInfo._auraEffectMask;
if (createInfo._targetEffectMask != 0)
effMask = createInfo._targetEffectMask;
@@ -2472,17 +2470,25 @@ namespace Game.Spells
public static Aura Create(AuraCreateInfo createInfo)
{
Cypher.Assert(createInfo.Caster != null || !createInfo.CasterGUID.IsEmpty());
// try to get caster of aura
if (!createInfo.CasterGUID.IsEmpty())
{
if (createInfo.GetOwner().GetGUID() == createInfo.CasterGUID)
createInfo.Caster = createInfo.GetOwner().ToUnit();
else
createInfo.Caster = Global.ObjAccessor.GetUnit(createInfo.GetOwner(), createInfo.CasterGUID);
// world gameobjects can't own auras and they send empty casterguid
// checked on sniffs with spell 22247
if (createInfo.CasterGUID.IsGameObject())
{
createInfo.Caster = null;
createInfo.CasterGUID.Clear();
}
else
{
if (createInfo._owner.GetGUID() == createInfo.CasterGUID)
createInfo.Caster = createInfo._owner.ToUnit();
else
createInfo.Caster = Global.ObjAccessor.GetUnit(createInfo._owner, createInfo.CasterGUID);
}
}
else if (createInfo.Caster != null)
createInfo.CasterGUID = createInfo.Caster.GetGUID();
// check if aura can be owned by owner
File diff suppressed because it is too large Load Diff
+2 -3
View File
@@ -345,9 +345,9 @@ namespace Game.Spells
m_targetMask &= ~SpellCastTargetFlags.DestLocation;
}
public void Update(Unit caster)
public void Update(WorldObject caster)
{
m_objectTarget = !m_objectTargetGUID.IsEmpty() ? ((m_objectTargetGUID == caster.GetGUID()) ? caster : Global.ObjAccessor.GetWorldObject(caster, m_objectTargetGUID)) : null;
m_objectTarget = (m_objectTargetGUID == caster.GetGUID()) ? caster : Global.ObjAccessor.GetWorldObject(caster, m_objectTargetGUID);
m_itemTarget = null;
if (caster is Player)
@@ -403,7 +403,6 @@ namespace Game.Spells
public bool HasDst() { return Convert.ToBoolean(m_targetMask & SpellCastTargetFlags.DestLocation); }
public bool HasTraj() { return m_speed != 0; }
public float GetPitch() { return m_pitch; }
public void SetPitch(float pitch) { m_pitch = pitch; }
float GetSpeed() { return m_speed; }
File diff suppressed because it is too large Load Diff
+86 -61
View File
@@ -1010,7 +1010,7 @@ namespace Game.Spells
return SpellCastResult.SpellCastOk;
}
public SpellCastResult CheckTarget(Unit caster, WorldObject target, bool Implicit = true)
public SpellCastResult CheckTarget(WorldObject caster, WorldObject target, bool Implicit = true)
{
if (HasAttribute(SpellAttr1.CantTargetSelf) && caster == target)
return SpellCastResult.BadTargets;
@@ -1112,7 +1112,7 @@ namespace Game.Spells
}
// check GM mode and GM invisibility - only for player casts (npc casts are controlled by AI) and negative spells
if (unitTarget != caster && (caster.IsControlledByPlayer() || !IsPositive()) && unitTarget.IsTypeId(TypeId.Player))
if (unitTarget != caster && (caster.GetAffectingPlayer() != null || !IsPositive()) && unitTarget.IsTypeId(TypeId.Player))
{
if (!unitTarget.ToPlayer().IsVisible())
return SpellCastResult.BmOrInvisgod;
@@ -1132,14 +1132,18 @@ namespace Game.Spells
him, because it would be it's passenger, there's no such case where this gets to fail legitimacy, this problem
cannot be solved from within the check in other way since target type cannot be called for the spell currently
Spell examples: [ID - 52864 Devour Water, ID - 52862 Devour Wind, ID - 49370 Wyrmrest Defender: Destabilize Azure Dragonshrine Effect] */
if (!caster.IsVehicle() && caster.GetCharmerOrOwner() != target)
Unit unitCaster = caster.ToUnit();
if (unitCaster != null)
{
if (TargetAuraState != 0 && !unitTarget.HasAuraState(TargetAuraState, this, caster))
if (!unitCaster.IsVehicle() && unitCaster.GetCharmerOrOwner() != target)
{
if (TargetAuraState != 0 && !unitTarget.HasAuraState(TargetAuraState, this, unitCaster))
return SpellCastResult.TargetAurastate;
if (ExcludeTargetAuraState != 0 && unitTarget.HasAuraState(ExcludeTargetAuraState, this, caster))
if (ExcludeTargetAuraState != 0 && unitTarget.HasAuraState(ExcludeTargetAuraState, this, unitCaster))
return SpellCastResult.TargetAurastate;
}
}
if (TargetAuraSpell != 0 && !unitTarget.HasAura(TargetAuraSpell))
return SpellCastResult.TargetAurastate;
@@ -1170,7 +1174,7 @@ namespace Game.Spells
return SpellCastResult.SpellCastOk;
}
public SpellCastResult CheckExplicitTarget(Unit caster, WorldObject target, Item itemTarget = null)
public SpellCastResult CheckExplicitTarget(WorldObject caster, WorldObject target, Item itemTarget = null)
{
SpellCastTargetFlags neededTargets = GetExplicitTargetMask();
if (target == null)
@@ -1183,22 +1187,27 @@ namespace Game.Spells
Unit unitTarget = target.ToUnit();
if (unitTarget != null)
{
if (Convert.ToBoolean(neededTargets & (SpellCastTargetFlags.UnitEnemy | SpellCastTargetFlags.UnitAlly | SpellCastTargetFlags.UnitRaid | SpellCastTargetFlags.UnitParty | SpellCastTargetFlags.UnitMinipet | SpellCastTargetFlags.UnitPassenger)))
if (neededTargets.HasAnyFlag(SpellCastTargetFlags.UnitEnemy | SpellCastTargetFlags.UnitAlly | SpellCastTargetFlags.UnitRaid | SpellCastTargetFlags.UnitParty | SpellCastTargetFlags.UnitMinipet | SpellCastTargetFlags.UnitPassenger))
{
if (Convert.ToBoolean(neededTargets & SpellCastTargetFlags.UnitEnemy))
Unit unitCaster = caster.ToUnit();
if (neededTargets.HasFlag(SpellCastTargetFlags.UnitEnemy))
if (caster.IsValidAttackTarget(unitTarget, this))
return SpellCastResult.SpellCastOk;
if (neededTargets.HasAnyFlag(SpellCastTargetFlags.UnitAlly)
|| (neededTargets.HasAnyFlag(SpellCastTargetFlags.UnitParty) && caster.IsInPartyWith(unitTarget))
|| (neededTargets.HasAnyFlag(SpellCastTargetFlags.UnitRaid) && caster.IsInRaidWith(unitTarget)))
if (neededTargets.HasFlag(SpellCastTargetFlags.UnitAlly)
|| (neededTargets.HasFlag(SpellCastTargetFlags.UnitParty) && unitCaster != null && unitCaster.IsInPartyWith(unitTarget))
|| (neededTargets.HasFlag(SpellCastTargetFlags.UnitRaid) && unitCaster != null && unitCaster.IsInRaidWith(unitTarget)))
if (caster.IsValidAssistTarget(unitTarget, this))
return SpellCastResult.SpellCastOk;
if (Convert.ToBoolean(neededTargets & SpellCastTargetFlags.UnitMinipet))
if (unitTarget.GetGUID() == caster.GetCritterGUID())
if (neededTargets.HasFlag(SpellCastTargetFlags.UnitMinipet) && unitCaster != null)
if (unitTarget.GetGUID() == unitCaster.GetCritterGUID())
return SpellCastResult.SpellCastOk;
if (Convert.ToBoolean(neededTargets & SpellCastTargetFlags.UnitPassenger))
if (unitTarget.IsOnVehicle(caster))
if (neededTargets.HasFlag(SpellCastTargetFlags.UnitPassenger) && unitCaster != null)
if (unitTarget.IsOnVehicle(unitCaster))
return SpellCastResult.SpellCastOk;
return SpellCastResult.BadTargets;
}
}
@@ -2625,7 +2634,7 @@ namespace Game.Spells
return RangeEntry.RangeMin[positive ? 1 : 0];
}
public float GetMaxRange(bool positive = false, Unit caster = null, Spell spell = null)
public float GetMaxRange(bool positive = false, WorldObject caster = null, Spell spell = null)
{
if (RangeEntry == null)
return 0.0f;
@@ -2640,7 +2649,7 @@ namespace Game.Spells
return range;
}
public int CalcDuration(Unit caster = null)
public int CalcDuration(WorldObject caster = null)
{
int duration = GetDuration();
@@ -2733,8 +2742,13 @@ namespace Game.Spells
return RecoveryTime > CategoryRecoveryTime ? RecoveryTime : CategoryRecoveryTime;
}
public SpellPowerCost CalcPowerCost(PowerType powerType, bool optionalCost, Unit caster, SpellSchoolMask schoolMask, Spell spell = null)
public SpellPowerCost CalcPowerCost(PowerType powerType, bool optionalCost, WorldObject caster, SpellSchoolMask schoolMask, Spell spell = null)
{
// gameobject casts don't use power
Unit unitCaster = caster.ToUnit();
if (unitCaster == null)
return null;
var spellPowerRecord = PowerCosts.FirstOrDefault(spellPowerEntry => spellPowerEntry?.PowerType == powerType);
if (spellPowerRecord == null)
return null;
@@ -2742,9 +2756,14 @@ namespace Game.Spells
return CalcPowerCost(spellPowerRecord, optionalCost, caster, schoolMask, spell);
}
public SpellPowerCost CalcPowerCost(SpellPowerRecord power, bool optionalCost, Unit caster, SpellSchoolMask schoolMask, Spell spell = null)
public SpellPowerCost CalcPowerCost(SpellPowerRecord power, bool optionalCost, WorldObject caster, SpellSchoolMask schoolMask, Spell spell = null)
{
if (power.RequiredAuraSpellID != 0 && !caster.HasAura(power.RequiredAuraSpellID))
// gameobject casts don't use power
Unit unitCaster = caster.ToUnit();
if (!unitCaster)
return null;
if (power.RequiredAuraSpellID != 0 && !unitCaster.HasAura(power.RequiredAuraSpellID))
return null;
SpellPowerCost cost = new();
@@ -2756,14 +2775,14 @@ namespace Game.Spells
if (power.PowerType == PowerType.Health)
{
cost.Power = PowerType.Health;
cost.Amount = (int)caster.GetHealth();
cost.Amount = (int)unitCaster.GetHealth();
return cost;
}
// Else drain all power
if (power.PowerType < PowerType.Max)
{
cost.Power = power.PowerType;
cost.Amount = caster.GetPower(cost.Power);
cost.Amount = unitCaster.GetPower(cost.Power);
return cost;
}
@@ -2784,12 +2803,12 @@ namespace Game.Spells
// health as power used
case PowerType.Health:
if (MathFunctions.fuzzyEq(power.PowerCostPct, 0.0f))
powerCost += (int)MathFunctions.CalculatePct(caster.GetMaxHealth(), power.PowerCostMaxPct);
powerCost += (int)MathFunctions.CalculatePct(unitCaster.GetMaxHealth(), power.PowerCostMaxPct);
else
powerCost += (int)MathFunctions.CalculatePct(caster.GetMaxHealth(), power.PowerCostPct);
powerCost += (int)MathFunctions.CalculatePct(unitCaster.GetMaxHealth(), power.PowerCostPct);
break;
case PowerType.Mana:
powerCost += (int)MathFunctions.CalculatePct(caster.GetCreateMana(), power.PowerCostPct);
powerCost += (int)MathFunctions.CalculatePct(unitCaster.GetCreateMana(), power.PowerCostPct);
break;
case PowerType.AlternatePower:
Log.outError(LogFilter.Spells, $"SpellInfo.CalcPowerCost: Unknown power type '{power.PowerType}' in spell {Id}");
@@ -2812,7 +2831,7 @@ namespace Game.Spells
else
{
powerCost = (int)power.OptionalCost;
powerCost += caster.GetTotalAuraModifier(AuraType.ModAdditionalPowerCost, aurEff =>
powerCost += unitCaster.GetTotalAuraModifier(AuraType.ModAdditionalPowerCost, aurEff =>
{
return aurEff.GetMiscValue() == (int)power.PowerType && aurEff.IsAffectingSpell(this);
});
@@ -2824,7 +2843,7 @@ namespace Game.Spells
if (HasAttribute(SpellAttr4.SpellVsExtendCost))
{
uint speed = 0;
SpellShapeshiftFormRecord ss = CliDB.SpellShapeshiftFormStorage.LookupByKey(caster.GetShapeshiftForm());
SpellShapeshiftFormRecord ss = CliDB.SpellShapeshiftFormStorage.LookupByKey(unitCaster.GetShapeshiftForm());
if (ss != null)
speed = ss.CombatRoundTime;
else
@@ -2833,7 +2852,7 @@ namespace Game.Spells
if (!HasAttribute(SpellAttr3.MainHand) && HasAttribute(SpellAttr3.ReqOffhand))
slot = WeaponAttackType.OffAttack;
speed = caster.GetBaseAttackTime(slot);
speed = unitCaster.GetBaseAttackTime(slot);
}
powerCost += (int)speed / 100;
@@ -2844,7 +2863,7 @@ namespace Game.Spells
if (!optionalCost)
{
// Flat mod from caster auras by spell school and power type
foreach (AuraEffect aura in caster.GetAuraEffectsByType(AuraType.ModPowerCostSchool))
foreach (AuraEffect aura in unitCaster.GetAuraEffectsByType(AuraType.ModPowerCostSchool))
{
if ((aura.GetMiscValue() & (int)schoolMask) == 0)
continue;
@@ -2857,7 +2876,7 @@ namespace Game.Spells
}
// PCT mod from user auras by spell school and power type
foreach (var schoolCostPct in caster.GetAuraEffectsByType(AuraType.ModPowerCostSchoolPct))
foreach (var schoolCostPct in unitCaster.GetAuraEffectsByType(AuraType.ModPowerCostSchoolPct))
{
if ((schoolCostPct.GetMiscValue() & (int)schoolMask) == 0)
continue;
@@ -2870,7 +2889,7 @@ namespace Game.Spells
}
// Apply cost mod by spell
Player modOwner = caster.GetSpellModOwner();
Player modOwner = unitCaster.GetSpellModOwner();
if (modOwner != null)
{
SpellModOp mod = SpellModOp.Max;
@@ -2904,19 +2923,19 @@ namespace Game.Spells
}
}
if (!caster.IsControlledByPlayer() && MathFunctions.fuzzyEq(power.PowerCostPct, 0.0f) && SpellLevel != 0 && power.PowerType == PowerType.Mana)
if (!unitCaster.IsControlledByPlayer() && MathFunctions.fuzzyEq(power.PowerCostPct, 0.0f) && SpellLevel != 0 && power.PowerType == PowerType.Mana)
{
if (HasAttribute(SpellAttr0.LevelDamageCalculation))
{
GtNpcManaCostScalerRecord spellScaler = CliDB.NpcManaCostScalerGameTable.GetRow(SpellLevel);
GtNpcManaCostScalerRecord casterScaler = CliDB.NpcManaCostScalerGameTable.GetRow(caster.GetLevel());
GtNpcManaCostScalerRecord casterScaler = CliDB.NpcManaCostScalerGameTable.GetRow(unitCaster.GetLevel());
if (spellScaler != null && casterScaler != null)
powerCost *= (int)(casterScaler.Scaler / spellScaler.Scaler);
}
}
if (power.PowerType == PowerType.Mana)
powerCost = (int)((float)powerCost * (1.0f + caster.m_unitData.ManaCostMultiplier));
powerCost = (int)((float)powerCost * (1.0f + unitCaster.m_unitData.ManaCostMultiplier));
// power cost cannot become negative if initially positive
if (initiallyNegative != (powerCost < 0))
@@ -2927,16 +2946,14 @@ namespace Game.Spells
return cost;
}
public List<SpellPowerCost> CalcPowerCost(Unit caster, SpellSchoolMask schoolMask, Spell spell = null)
public List<SpellPowerCost> CalcPowerCost(WorldObject caster, SpellSchoolMask schoolMask, Spell spell = null)
{
List<SpellPowerCost> costs = new();
if (caster.IsUnit())
{
SpellPowerCost getOrCreatePowerCost(PowerType powerType)
{
var itr = costs.Find(cost =>
{
return cost.Power == powerType;
});
var itr = costs.Find(cost => cost.Power == powerType);
if (itr != null)
return itr;
@@ -2960,11 +2977,12 @@ namespace Game.Spells
if (optionalCost != null)
{
SpellPowerCost cost1 = getOrCreatePowerCost(optionalCost.Power);
int remainingPower = caster.GetPower(optionalCost.Power) - cost1.Amount;
int remainingPower = caster.ToUnit().GetPower(optionalCost.Power) - cost1.Amount;
if (remainingPower > 0)
cost1.Amount += Math.Min(optionalCost.Amount, remainingPower);
}
}
}
return costs;
}
@@ -3195,11 +3213,10 @@ namespace Game.Spells
return false;
}
public uint GetSpellXSpellVisualId(Unit caster = null)
public uint GetSpellXSpellVisualId(WorldObject caster = null)
{
foreach (SpellXSpellVisualRecord visual in _visuals)
{
PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(visual.CasterPlayerConditionID);
if (playerCondition == null || (caster && caster.GetTypeId() == TypeId.Player && ConditionManager.IsPlayerMeetingCondition(caster.ToPlayer(), playerCondition)))
return visual.Id;
@@ -3208,7 +3225,7 @@ namespace Game.Spells
return 0;
}
public uint GetSpellVisual(Unit caster = null)
public uint GetSpellVisual(WorldObject caster = null)
{
var visual = CliDB.SpellXSpellVisualStorage.LookupByKey(GetSpellXSpellVisualId(caster));
if (visual != null)
@@ -3817,13 +3834,13 @@ namespace Game.Spells
public bool HasAttribute(SpellAttr14 attribute) { return Convert.ToBoolean(AttributesEx14 & attribute); }
public bool HasAttribute(SpellCustomAttributes attribute) { return Convert.ToBoolean(AttributesCu & attribute); }
public bool CanBeInterrupted(Unit interruptCaster, Unit interruptTarget)
public bool CanBeInterrupted(WorldObject interruptCaster, Unit interruptTarget)
{
return HasAttribute(SpellAttr7.CanAlwaysBeInterrupted)
|| HasChannelInterruptFlag(SpellAuraInterruptFlags.Damage | SpellAuraInterruptFlags.EnteringCombat)
|| (interruptTarget.IsPlayer() && InterruptFlags.HasFlag(SpellInterruptFlags.DamageCancelsPlayerOnly))
|| InterruptFlags.HasFlag(SpellInterruptFlags.DamageCancels)
|| interruptCaster.HasAuraTypeWithMiscvalue(AuraType.AllowInterruptSpell, (int)Id)
|| interruptCaster.IsUnit() && interruptCaster.ToUnit().HasAuraTypeWithMiscvalue(AuraType.AllowInterruptSpell, (int)Id)
|| ((interruptTarget.GetMechanicImmunityMask() & (1 << (int)Mechanics.Interrupt)) == 0
&& !interruptTarget.HasAuraTypeWithAffectMask(AuraType.PreventInterrupt, this)
&& PreventionType.HasAnyFlag(SpellPreventionType.Silence));
@@ -4028,12 +4045,12 @@ namespace Game.Spells
return IsAreaAuraEffect() || Effect == SpellEffectName.ApplyAura || Effect == SpellEffectName.ApplyAuraOnPet;
}
public int CalcValue(Unit caster = null, int? bp = null, Unit target = null, uint castItemId = 0, int itemLevel = -1)
public int CalcValue(WorldObject caster = null, int? bp = null, Unit target = null, uint castItemId = 0, int itemLevel = -1)
{
return CalcValue(out _, caster, bp, target, castItemId, itemLevel);
}
public int CalcValue(out float variance, Unit caster = null, int? bp = null, Unit target = null, uint castItemId = 0, int itemLevel = -1)
public int CalcValue(out float variance, WorldObject caster = null, int? bp = null, Unit target = null, uint castItemId = 0, int itemLevel = -1)
{
variance = 0.0f;
float basePointsPerLevel = RealPointsPerLevel;
@@ -4042,6 +4059,10 @@ namespace Game.Spells
float value = bp.HasValue ? bp.Value : basePoints;
float comboDamage = PointsPerResource;
Unit casterUnit = null;
if (caster != null)
casterUnit = caster.ToUnit();
if (Scaling.Variance != 0)
{
float delta = Math.Abs(Scaling.Variance * 0.5f);
@@ -4058,9 +4079,9 @@ namespace Game.Spells
}
else if (GetScalingExpectedStat() == ExpectedStatType.None)
{
if (caster != null && basePointsPerLevel != 0.0f)
if (casterUnit != null && basePointsPerLevel != 0.0f)
{
int level = (int)caster.GetLevel();
int level = (int)casterUnit.GetLevel();
if (level > (int)_spellInfo.MaxLevel && _spellInfo.MaxLevel > 0)
level = (int)_spellInfo.MaxLevel;
@@ -4072,31 +4093,32 @@ namespace Game.Spells
}
}
// random damage
if (caster)
if (casterUnit != null)
{
// bonus amount from combo points
if (caster.m_playerMovingMe && comboDamage != 0)
if (comboDamage != 0)
{
uint comboPoints = caster.m_playerMovingMe.GetComboPoints();
uint comboPoints = casterUnit.GetComboPoints();
if (comboPoints != 0)
value += comboDamage * comboPoints;
}
if (caster != null)
value = caster.ApplyEffectModifiers(_spellInfo, EffectIndex, value);
}
return (int)Math.Round(value);
}
public int CalcBaseValue(Unit caster, Unit target, uint itemId, int itemLevel)
public int CalcBaseValue(WorldObject caster, Unit target, uint itemId, int itemLevel)
{
if (Scaling.Coefficient != 0.0f)
{
uint level = _spellInfo.SpellLevel;
if (target && _spellInfo.IsPositiveEffect(EffectIndex) && (Effect == SpellEffectName.ApplyAura))
level = target.GetLevel();
else if (caster)
level = caster.GetLevel();
else if (caster != null && caster.IsUnit())
level = caster.ToUnit().GetLevel();
if (_spellInfo.BaseLevel != 0 && !_spellInfo.HasAttribute(SpellAttr11.ScalesWithItemLevel) && _spellInfo.HasAttribute(SpellAttr10.UseSpellBaseLevelForScaling))
level = _spellInfo.BaseLevel;
@@ -4188,7 +4210,7 @@ namespace Game.Spells
if (contentTuning != null)
expansion = contentTuning.ExpansionID;
uint level = caster ? caster.GetLevel() : 1;
uint level = caster != null && caster.IsUnit() ? caster.ToUnit().GetLevel() : 1;
tempValue = Global.DB2Mgr.EvaluateExpectedStat(stat, level, expansion, 0, Class.None) * BasePoints / 100.0f;
}
@@ -4196,7 +4218,7 @@ namespace Game.Spells
}
}
public float CalcValueMultiplier(Unit caster, Spell spell = null)
public float CalcValueMultiplier(WorldObject caster, Spell spell = null)
{
float multiplier = Amplitude;
Player modOwner = (caster != null ? caster.GetSpellModOwner() : null);
@@ -4205,7 +4227,7 @@ namespace Game.Spells
return multiplier;
}
public float CalcDamageMultiplier(Unit caster, Spell spell = null)
public float CalcDamageMultiplier(WorldObject caster, Spell spell = null)
{
float multiplierPercent = ChainAmplitude * 100.0f;
Player modOwner = (caster != null ? caster.GetSpellModOwner() : null);
@@ -4224,7 +4246,7 @@ namespace Game.Spells
return MaxRadiusEntry != null;
}
public float CalcRadius(Unit caster = null, Spell spell = null)
public float CalcRadius(WorldObject caster = null, Spell spell = null)
{
SpellRadiusRecord entry = RadiusEntry;
if (!HasRadius() && HasMaxRadius())
@@ -4241,7 +4263,10 @@ namespace Game.Spells
if (caster != null)
{
radius += entry.RadiusPerLevel * caster.GetLevel();
Unit casterUnit = caster.ToUnit();
if (casterUnit != null)
radius += entry.RadiusPerLevel * casterUnit.GetLevel();
radius = Math.Min(radius, entry.RadiusMax);
Player modOwner = caster.GetSpellModOwner();
if (modOwner != null)
+1 -1
View File
@@ -494,7 +494,7 @@ namespace Game.Entities
}
// always trigger for these types
if (eventInfo.GetTypeMask().HasFlag(ProcFlags.Killed | ProcFlags.Kill | ProcFlags.Death))
if (eventInfo.GetTypeMask().HasAnyFlag(ProcFlags.Killed | ProcFlags.Kill | ProcFlags.Death))
return true;
// Do not consider autoattacks as triggered spells
+1 -1
View File
@@ -906,7 +906,7 @@ namespace Scripts.Spells.Druid
if (caster != null)
{
// 0.01 * $AP * cp
byte cp = caster.ToPlayer().GetComboPoints();
byte cp = (byte)caster.ToPlayer().GetComboPoints();
// Idol of Feral Shadows. Can't be handled as SpellMod due its dependency from CPs
AuraEffect idol = caster.GetAuraEffect(SpellIds.IdolOfFeralShadows, 0);
+1 -1
View File
@@ -1380,7 +1380,7 @@ namespace Scripts.Spells.Items
void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo)
{
if (eventInfo.GetTypeMask().HasFlag(ProcFlags.DoneRangedAutoAttack | ProcFlags.DoneSpellRangedDmgClass))
if (eventInfo.GetTypeMask().HasAnyFlag(ProcFlags.DoneRangedAutoAttack | ProcFlags.DoneSpellRangedDmgClass))
{
// in that case, do not cast heal spell
PreventDefaultAction();
+1 -1
View File
@@ -1463,7 +1463,7 @@ namespace Scripts.World.NpcSpecial
public override void Reset() { }
public override void JustEngagedWith(Unit who) { }
public override void OnPossess(bool apply)
public void OnPossess(bool apply)
{
if (apply)
{