Core/Unit: don't clear low health aura states on death
Core/Gossip: Fix gossip bug on modify money
Core/Spells: Change the radius of PBAoEs following the feedback received on
Core/Player: update interaction checks, some info taken from client
Core/Spell: abort channeling if no valid targets are found after searching
Core/Creature: fix _DespawnAtEvade saving wrong respawn time
Core/Spell: fixed some problems with per caster aura states
Quickfix a bug introduced by 2f19d97 which prevented GTAoE from being cast.
Core/SmartAI: allow SMART_ACTION_SEND_GOSSIP_MENU to override default gossip
Core/Spell: in case of immunity, check all effects to choose correct procFlags, as none has technically hit
Fix evade issues when a spell hits the target just before evading.
Scripts/Command: implement .debug play music command
Partial revert, Unit::getAttackerForHelper() shouldn't return units that we aren't in combat with (victim can be such a unit for players/player pets, which can startattack from a distance without entering combat).
Fix an issue where CanSpawn would never get invoked on creatures without per-guid script.
Core/Players: fix null dereference crash
This commit is contained in:
hondacrx
2020-06-21 13:01:24 -04:00
parent c1f79334ef
commit 1a2411ae0f
14 changed files with 189 additions and 109 deletions
@@ -760,6 +760,7 @@ namespace Framework.Constants
CommandGoOffset = 852, CommandGoOffset = 852,
CommandReloadConversationTemplate = 853, CommandReloadConversationTemplate = 853,
CommandDebugConversation = 854, CommandDebugConversation = 854,
CommandDebugPlayMusic = 855,
CommandNpcSpawngroup = 856, // Reserved For DynamicSpawning CommandNpcSpawngroup = 856, // Reserved For DynamicSpawning
CommandNpcDespawngroup = 857, // Reserved For DynamicSpawning CommandNpcDespawngroup = 857, // Reserved For DynamicSpawning
CommandGobjectSpawngroup = 858, // Reserved For DynamicSpawning CommandGobjectSpawngroup = 858, // Reserved For DynamicSpawning
+18 -5
View File
@@ -791,14 +791,16 @@ namespace Game.AI
public override bool GossipHello(Player player) public override bool GossipHello(Player player)
{ {
_gossipReturn = false;
GetScript().ProcessEventsFor(SmartEvents.GossipHello, player); GetScript().ProcessEventsFor(SmartEvents.GossipHello, player);
return false; return _gossipReturn;
} }
public override bool GossipSelect(Player player, uint menuId, uint gossipListId) public override bool GossipSelect(Player player, uint menuId, uint gossipListId)
{ {
_gossipReturn = false;
GetScript().ProcessEventsFor(SmartEvents.GossipSelect, player, menuId, gossipListId); GetScript().ProcessEventsFor(SmartEvents.GossipSelect, player, menuId, gossipListId);
return false; return _gossipReturn;
} }
public override bool GossipSelectCode(Player player, uint menuId, uint gossipListId, string code) public override bool GossipSelectCode(Player player, uint menuId, uint gossipListId, string code)
@@ -993,6 +995,8 @@ namespace Game.AI
public void SetWPPauseTimer(uint time) { mWPPauseTimer = time; } public void SetWPPauseTimer(uint time) { mWPPauseTimer = time; }
public void SetGossipReturn(bool val) { _gossipReturn = val; }
bool mIsCharmed; bool mIsCharmed;
uint mFollowCreditType; uint mFollowCreditType;
uint mFollowArrivedTimer; uint mFollowArrivedTimer;
@@ -1032,6 +1036,9 @@ namespace Game.AI
// Vehicle conditions // Vehicle conditions
bool mHasConditions; bool mHasConditions;
uint mConditionsTimer; uint mConditionsTimer;
// Gossip
bool _gossipReturn;
} }
public class SmartGameObjectAI : GameObjectAI public class SmartGameObjectAI : GameObjectAI
@@ -1064,15 +1071,16 @@ namespace Game.AI
public override bool GossipHello(Player player, bool reportUse) public override bool GossipHello(Player player, bool reportUse)
{ {
Log.outDebug(LogFilter.ScriptsAi, "SmartGameObjectAI.GossipHello"); _gossipReturn = false;
GetScript().ProcessEventsFor(SmartEvents.GossipHello, player, reportUse ? 1 : 0u, 0, false, null, me); GetScript().ProcessEventsFor(SmartEvents.GossipHello, player, reportUse ? 1 : 0u, 0, false, null, me);
return false; return _gossipReturn;
} }
public override bool GossipSelect(Player player, uint menuId, uint gossipListId) public override bool GossipSelect(Player player, uint menuId, uint gossipListId)
{ {
_gossipReturn = false;
GetScript().ProcessEventsFor(SmartEvents.GossipSelect, player, menuId, gossipListId, false, null, me); GetScript().ProcessEventsFor(SmartEvents.GossipSelect, player, menuId, gossipListId, false, null, me);
return false; return _gossipReturn;
} }
public override bool GossipSelectCode(Player player, uint menuId, uint gossipListId, string code) public override bool GossipSelectCode(Player player, uint menuId, uint gossipListId, string code)
@@ -1132,9 +1140,14 @@ namespace Game.AI
GetScript().ProcessEventsFor(SmartEvents.SpellHit, unit, 0, 0, false, spellInfo); GetScript().ProcessEventsFor(SmartEvents.SpellHit, unit, 0, 0, false, spellInfo);
} }
public void SetGossipReturn(bool val) { _gossipReturn = val; }
public SmartScript GetScript() { return mScript; } public SmartScript GetScript() { return mScript; }
SmartScript mScript; SmartScript mScript;
// Gossip
bool _gossipReturn;
} }
public enum SmartEscortState public enum SmartEscortState
+7 -1
View File
@@ -2189,7 +2189,7 @@ namespace Game.AI
} }
case SmartActions.SendGossipMenu: case SmartActions.SendGossipMenu:
{ {
if (GetBaseObject() == null) if (GetBaseObject() == null || !IsSmart())
break; break;
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction. SMART_ACTION_SEND_GOSSIP_MENU: gossipMenuId {0}, gossipNpcTextId {1}", Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction. SMART_ACTION_SEND_GOSSIP_MENU: gossipMenuId {0}, gossipNpcTextId {1}",
@@ -2199,6 +2199,12 @@ namespace Game.AI
if (targets.Empty()) if (targets.Empty())
break; break;
// override default gossip
if (me)
((SmartAI)me.GetAI()).SetGossipReturn(true);
else if (go)
((SmartGameObjectAI)go.GetAI()).SetGossipReturn(true);
foreach (var obj in targets) foreach (var obj in targets)
{ {
Player player = obj.ToPlayer(); Player player = obj.ToPlayer();
+40 -12
View File
@@ -1057,12 +1057,12 @@ namespace Game.Chat
return false; return false;
} }
uint id = args.NextUInt32(); uint cinematicId = args.NextUInt32();
CinematicSequencesRecord cineSeq = CliDB.CinematicSequencesStorage.LookupByKey(id); CinematicSequencesRecord cineSeq = CliDB.CinematicSequencesStorage.LookupByKey(cinematicId);
if (cineSeq == null) if (cineSeq == null)
{ {
handler.SendSysMessage(CypherStrings.CinematicNotExist, id); handler.SendSysMessage(CypherStrings.CinematicNotExist, cinematicId);
return false; return false;
} }
@@ -1070,7 +1070,7 @@ namespace Game.Chat
var list = M2Storage.GetFlyByCameras(cineSeq.Camera[0]); var list = M2Storage.GetFlyByCameras(cineSeq.Camera[0]);
if (list != null) if (list != null)
{ {
handler.SendSysMessage("Waypoints for sequence {0}, camera {1}", id, cineSeq.Camera[0]); handler.SendSysMessage("Waypoints for sequence {0}, camera {1}", cinematicId, cineSeq.Camera[0]);
uint count = 1; uint count = 1;
foreach (FlyByCamera cam in list) foreach (FlyByCamera cam in list)
{ {
@@ -1080,7 +1080,7 @@ namespace Game.Chat
handler.SendSysMessage("{0} waypoints dumped", list.Count); handler.SendSysMessage("{0} waypoints dumped", list.Count);
} }
handler.GetSession().GetPlayer().SendCinematicStart(id); handler.GetSession().GetPlayer().SendCinematicStart(cinematicId);
return true; return true;
} }
@@ -1095,15 +1095,41 @@ namespace Game.Chat
return false; return false;
} }
uint id = args.NextUInt32(); uint movieId = args.NextUInt32();
if (!CliDB.MovieStorage.ContainsKey(id)) if (!CliDB.MovieStorage.ContainsKey(movieId))
{ {
handler.SendSysMessage(CypherStrings.MovieNotExist, id); handler.SendSysMessage(CypherStrings.MovieNotExist, movieId);
return false; return false;
} }
handler.GetSession().GetPlayer().SendMovieStart(id); handler.GetSession().GetPlayer().SendMovieStart(movieId);
return true;
}
[Command("music", RBACPermissions.CommandDebugPlayMusic)]
static bool HandleDebugPlayMusicCommand(StringArguments args, CommandHandler handler)
{
// USAGE: .debug play music #musicId
// #musicId - ID decimal number from SoundEntries.dbc (1st column)
if (args.Empty())
{
handler.SendSysMessage(CypherStrings.BadValue);
return false;
}
uint musicId = args.NextUInt32();
if (!CliDB.SoundKitStorage.ContainsKey(musicId))
{
handler.SendSysMessage(CypherStrings.SoundNotExist, musicId);
return false;
}
Player player = handler.GetSession().GetPlayer();
player.PlayDirectMusic(musicId, player);
handler.SendSysMessage(CypherStrings.YouHearSound, musicId);
return true; return true;
} }
@@ -1127,6 +1153,8 @@ namespace Game.Chat
return false; return false;
} }
Player player = handler.GetSession().GetPlayer();
Unit unit = handler.GetSelectedUnit(); Unit unit = handler.GetSelectedUnit();
if (!unit) if (!unit)
{ {
@@ -1134,10 +1162,10 @@ namespace Game.Chat
return false; return false;
} }
if (!handler.GetSession().GetPlayer().GetTarget().IsEmpty()) if (!player.GetTarget().IsEmpty())
unit.PlayDistanceSound(soundId, handler.GetSession().GetPlayer()); unit.PlayDistanceSound(soundId, player);
else else
unit.PlayDirectSound(soundId, handler.GetSession().GetPlayer()); unit.PlayDirectSound(soundId, player);
handler.SendSysMessage(CypherStrings.YouHearSound, soundId); handler.SendSysMessage(CypherStrings.YouHearSound, soundId);
return true; return true;
+15 -13
View File
@@ -1695,27 +1695,34 @@ namespace Game.Entities
{ {
if (timeMSToDespawn != 0) if (timeMSToDespawn != 0)
{ {
ForcedDespawnDelayEvent pEvent = new ForcedDespawnDelayEvent(this, forceRespawnTimer); m_Events.AddEvent(new ForcedDespawnDelayEvent(this, forceRespawnTimer), m_Events.CalculateTime(timeMSToDespawn));
m_Events.AddEvent(pEvent, m_Events.CalculateTime(timeMSToDespawn));
return; return;
} }
uint corpseDelay = GetCorpseDelay();
uint respawnDelay = GetRespawnDelay();
// do it before killing creature // do it before killing creature
DestroyForNearbyPlayers(); DestroyForNearbyPlayers();
bool overrideRespawnTime = false;
if (IsAlive()) if (IsAlive())
SetDeathState(DeathState.JustDied); {
bool overrideRespawnTime = true;
if (forceRespawnTimer > TimeSpan.Zero) if (forceRespawnTimer > TimeSpan.Zero)
{ {
SetRespawnTime((uint)forceRespawnTimer.TotalSeconds); SetCorpseDelay(0);
SetRespawnDelay((uint)forceRespawnTimer.TotalSeconds);
overrideRespawnTime = false; overrideRespawnTime = false;
} }
SetDeathState(DeathState.JustDied);
}
// Skip corpse decay time // Skip corpse decay time
RemoveCorpse(overrideRespawnTime, false); RemoveCorpse(overrideRespawnTime, false);
SetCorpseDelay(corpseDelay);
SetRespawnDelay(respawnDelay);
} }
public void DespawnOrUnsummon(TimeSpan time, TimeSpan forceRespawnTimer = default) { DespawnOrUnsummon((uint)time.TotalMilliseconds, forceRespawnTimer); } public void DespawnOrUnsummon(TimeSpan time, TimeSpan forceRespawnTimer = default) { DespawnOrUnsummon((uint)time.TotalMilliseconds, forceRespawnTimer); }
@@ -2060,14 +2067,9 @@ namespace Game.Entities
Unit targetVictim = target.GetAttackerForHelper(); Unit targetVictim = target.GetAttackerForHelper();
// if I'm already fighting target, or I'm hostile towards the target, the target is acceptable // if I'm already fighting target, or I'm hostile towards the target, the target is acceptable
if (GetVictim() == target || IsHostileTo(target)) if (IsInCombatWith(target) || IsHostileTo(target))
return true; return true;
// a player is targeting me, but I'm not hostile towards it, and not currently attacking it, the target is not acceptable
// (players may set their victim from a distance, and doesn't mean we should attack)
if (target.GetTypeId() == TypeId.Player && targetVictim == this)
return false;
// if the target's victim is friendly, and the target is neutral, the target is acceptable // if the target's victim is friendly, and the target is neutral, the target is acceptable
if (targetVictim != null && IsFriendlyTo(targetVictim)) if (targetVictim != null && IsFriendlyTo(targetVictim))
return true; return true;
@@ -1824,7 +1824,6 @@ namespace Game.Entities
List<uint> qr; List<uint> qr;
List<uint> qir; List<uint> qir;
PlayerTalkClass.ClearMenus();
switch (questgiver.GetTypeId()) switch (questgiver.GetTypeId())
{ {
case TypeId.GameObject: case TypeId.GameObject:
+37 -30
View File
@@ -3615,19 +3615,24 @@ namespace Game.Entities
void ResurrectUsingRequestDataImpl() void ResurrectUsingRequestDataImpl()
{ {
// save health and mana before resurrecting, _resurrectionData can be erased
uint resurrectHealth = _resurrectionData.Health;
uint resurrectMana = _resurrectionData.Mana;
uint resurrectAura = _resurrectionData.Aura;
ObjectGuid resurrectGUID = _resurrectionData.GUID;
ResurrectPlayer(0.0f, false); ResurrectPlayer(0.0f, false);
SetHealth(_resurrectionData.Health); SetHealth(resurrectHealth);
SetPower(PowerType.Mana, (int)_resurrectionData.Mana); SetPower(PowerType.Mana, (int)resurrectMana);
SetPower(PowerType.Rage, 0); SetPower(PowerType.Rage, 0);
SetFullPower(PowerType.Energy); SetFullPower(PowerType.Energy);
SetFullPower(PowerType.Focus); SetFullPower(PowerType.Focus);
SetPower(PowerType.LunarPower, 0); SetPower(PowerType.LunarPower, 0);
uint aura = _resurrectionData.Aura; if (resurrectAura != 0)
if (aura != 0) CastSpell(this, resurrectAura, true, null, null, resurrectGUID);
CastSpell(this, aura, true, null, null, _resurrectionData.GUID);
SpawnCorpseBones(); SpawnCorpseBones();
} }
@@ -5562,8 +5567,8 @@ namespace Game.Entities
if (creature.GetReactionTo(this) <= ReputationRank.Unfriendly) if (creature.GetReactionTo(this) <= ReputationRank.Unfriendly)
return null; return null;
// not too far // not too far, taken from CGGameUI::SetInteractTarget
if (!creature.IsWithinDistInMap(this, SharedConst.InteractionDistance)) if (!creature.IsWithinDistInMap(this, creature.GetCombatReach() + 4.0f))
return null; return null;
return creature; return creature;
@@ -5571,34 +5576,36 @@ namespace Game.Entities
public GameObject GetGameObjectIfCanInteractWith(ObjectGuid guid) public GameObject GetGameObjectIfCanInteractWith(ObjectGuid guid)
{ {
GameObject go = GetMap().GetGameObject(guid); if (guid.IsEmpty())
if (go)
{
if (go.IsWithinDistInMap(this, go.GetInteractionDistance()))
return go;
Log.outDebug(LogFilter.Maps, "Player.GetGameObjectIfCanInteractWith: GameObject '{0}' ({1}) is too far away from player '{2}' ({3}) to be used by him (Distance: {4}, maximal {5} is allowed)",
go.GetName(), go.GetGUID().ToString(), GetName(), GetGUID().ToString(), go.GetDistance(this), go.GetInteractionDistance());
}
return null; return null;
if (!IsInWorld)
return null;
if (IsInFlight())
return null;
// exist
GameObject go = ObjectAccessor.GetGameObject(this, guid);
if (go == null)
return null;
if (!go.IsWithinDistInMap(this, go.GetInteractionDistance()))
return null;
return go;
} }
public GameObject GetGameObjectIfCanInteractWith(ObjectGuid guid, GameObjectTypes type) public GameObject GetGameObjectIfCanInteractWith(ObjectGuid guid, GameObjectTypes type)
{ {
GameObject go = GetMap().GetGameObject(guid); GameObject go = GetGameObjectIfCanInteractWith(guid);
if (go != null) if (!go)
{
if (go.GetGoType() == type)
{
if (go.IsWithinDistInMap(this, go.GetInteractionDistance()))
return go;
Log.outDebug(LogFilter.Maps, "Player.GetGameObjectIfCanInteractWith: GameObject '{0}' ({1}) is too far away from player '{2}' ({3}) to be used by him (Distance: {4}, maximal {5} is allowed)",
go.GetName(), go.GetGUID().ToString(), GetName(), GetGUID().ToString(), go.GetDistance(this), go.GetInteractionDistance());
}
}
return null; return null;
if (go.GetGoType() != type)
return null;
return go;
} }
public void SendInitialPacketsBeforeAddToMap() public void SendInitialPacketsBeforeAddToMap()
+27 -6
View File
@@ -376,6 +376,11 @@ namespace Game.Entities
if (IsTypeId(TypeId.Player) && IsMounted()) if (IsTypeId(TypeId.Player) && IsMounted())
return false; return false;
Creature creature = ToCreature();
// creatures cannot attack while evading
if (creature != null && creature.IsInEvadeMode())
return false;
if (HasUnitFlag(UnitFlags.Pacified)) if (HasUnitFlag(UnitFlags.Pacified))
return false; return false;
@@ -436,7 +441,7 @@ namespace Game.Entities
if (meleeAttack) if (meleeAttack)
AddUnitState(UnitState.MeleeAttacking); AddUnitState(UnitState.MeleeAttacking);
if (IsTypeId(TypeId.Unit) && !IsPet()) if (creature != null && !IsPet())
{ {
// should not let player enter combat by right clicking target - doesn't helps // should not let player enter combat by right clicking target - doesn't helps
AddThreat(victim, 0.0f); AddThreat(victim, 0.0f);
@@ -445,8 +450,8 @@ namespace Game.Entities
if (victim.IsTypeId(TypeId.Player)) if (victim.IsTypeId(TypeId.Player))
victim.SetInCombatWith(this); victim.SetInCombatWith(this);
ToCreature().SendAIReaction(AiReaction.Hostile); creature.SendAIReaction(AiReaction.Hostile);
ToCreature().CallAssistance(); creature.CallAssistance();
// Remove emote state - will be restored on creature reset // Remove emote state - will be restored on creature reset
SetEmoteState(Emote.OneshotNone); SetEmoteState(Emote.OneshotNone);
@@ -536,12 +541,28 @@ namespace Game.Entities
} }
public Unit GetAttackerForHelper() public Unit GetAttackerForHelper()
{ {
if (GetVictim() != null) Unit victim = GetVictim();
return GetVictim(); if (victim != null)
if (!IsControlledByPlayer() || IsInCombatWith(victim) || victim.IsInCombatWith(this))
return victim;
if (attackerList.Count != 0) if (!attackerList.Empty())
return attackerList[0]; return attackerList[0];
Player owner = GetCharmerOrOwnerPlayerOrPlayerItself();
if (owner != null)
{
HostileReference refe = owner.GetHostileRefManager().GetFirst();
while (refe != null)
{
Unit hostile = refe.GetSource().GetOwner();
if (hostile != null)
return hostile;
refe = refe.Next();
}
}
return null; return null;
} }
public List<Unit> GetAttackers() public List<Unit> GetAttackers()
+24 -1
View File
@@ -3965,9 +3965,22 @@ namespace Game.Entities
ToTotem().SetDeathState(DeathState.JustDied); ToTotem().SetDeathState(DeathState.JustDied);
} }
// Remove aurastates only if were not found // Remove aurastates only if needed and were not found
if (auraState != 0)
{
if (!auraStateFound) if (!auraStateFound)
ModifyAuraState(auraState, false); ModifyAuraState(auraState, false);
else
{
// update for casters, some shouldn't 'see' the aura state
uint aStateMask = (1u << ((int)auraState - 1));
if ((aStateMask & (uint)AuraStateType.PerCasterAuraStateMask) != 0)
{
m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.AuraState);
ForceUpdateFieldChange();
}
}
}
aura.HandleAuraSpecificMods(aurApp, caster, false, false); aura.HandleAuraSpecificMods(aurApp, caster, false, false);
} }
@@ -4099,7 +4112,17 @@ namespace Game.Entities
// Update target aura state flag // Update target aura state flag
AuraStateType aState = aura.GetSpellInfo().GetAuraState(); AuraStateType aState = aura.GetSpellInfo().GetAuraState();
if (aState != 0) if (aState != 0)
{
uint aStateMask = (1u << ((int)aState - 1));
// force update so the new caster registers it
if (aStateMask.HasAnyFlag((uint)AuraStateType.PerCasterAuraStateMask) && (m_unitData.AuraState & aStateMask) != 0)
{
m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.AuraState);
ForceUpdateFieldChange();
}
else
ModifyAuraState(aState, true); ModifyAuraState(aState, true);
}
if (aurApp.HasRemoveMode()) if (aurApp.HasRemoveMode())
return; return;
-2
View File
@@ -1626,8 +1626,6 @@ namespace Game.Entities
if (s == DeathState.JustDied) if (s == DeathState.JustDied)
{ {
ModifyAuraState(AuraStateType.HealthLess20Percent, false);
ModifyAuraState(AuraStateType.HealthLess35Percent, false);
// remove aurastates allowing special moves // remove aurastates allowing special moves
ClearAllReactives(); ClearAllReactives();
m_Diminishing.Clear(); m_Diminishing.Clear();
+6 -1
View File
@@ -689,7 +689,12 @@ namespace Game.Scripting
CreatureTemplate baseTemplate = Global.ObjectMgr.GetCreatureTemplate(entry); CreatureTemplate baseTemplate = Global.ObjectMgr.GetCreatureTemplate(entry);
if (baseTemplate == null) if (baseTemplate == null)
baseTemplate = actTemplate; baseTemplate = actTemplate;
return RunScriptRet<CreatureScript, bool>(p => p.CanSpawn(spawnId, entry, baseTemplate, actTemplate, cData, map), cData != null ? cData.ScriptId : baseTemplate.ScriptID, true);
uint scriptId = baseTemplate.ScriptID;
if (cData != null && cData.ScriptId != 0)
scriptId = cData.ScriptId;
return RunScriptRet<CreatureScript, bool>(p => p.CanSpawn(spawnId, entry, baseTemplate, actTemplate, cData, map), scriptId, true);
} }
public CreatureAI GetCreatureAI(Creature creature) public CreatureAI GetCreatureAI(Creature creature)
{ {
+10 -4
View File
@@ -266,6 +266,14 @@ namespace Game.Spells
if (m_spellInfo.IsChanneled()) if (m_spellInfo.IsChanneled())
{ {
// maybe do this for all spells?
if (m_UniqueTargetInfo.Empty() && m_UniqueGOTargetInfo.Empty() && m_UniqueItemInfo.Empty() && !m_targets.HasDst())
{
SendCastResult(SpellCastResult.BadImplicitTargets);
Finish(false);
return;
}
uint mask = (1u << (int)effect.EffectIndex); uint mask = (1u << (int)effect.EffectIndex);
foreach (var ihit in m_UniqueTargetInfo) foreach (var ihit in m_UniqueTargetInfo)
{ {
@@ -736,9 +744,6 @@ namespace Game.Spells
return; return;
float radius = effect.CalcRadius(m_caster) * m_spellValue.RadiusMod; float radius = effect.CalcRadius(m_caster) * m_spellValue.RadiusMod;
// if this is a proximity based aoe (Frost Nova, Psychic Scream, ...), include the caster's own combat reach
if (targetType.IsProximityBasedAoe())
radius += GetCaster().GetCombatReach();
SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), effect.ImplicitTargetConditions); SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), effect.ImplicitTargetConditions);
@@ -1816,7 +1821,8 @@ namespace Game.Spells
{ {
for (byte i = 0; i < SpellConst.MaxEffects; ++i) for (byte i = 0; i < SpellConst.MaxEffects; ++i)
{ {
if (!Convert.ToBoolean(target.effectMask & (1 << i))) // in case of immunity, check all effects to choose correct procFlags, as none has technically hit
if (target.effectMask != 0 && !Convert.ToBoolean(target.effectMask & (1 << i)))
continue; continue;
if (!m_spellInfo.IsPositiveEffect(i)) if (!m_spellInfo.IsPositiveEffect(i))
+1 -2
View File
@@ -2452,8 +2452,7 @@ namespace Game.Spells
// this effect use before aura Taunt apply for prevent taunt already attacking target // this effect use before aura Taunt apply for prevent taunt already attacking target
// for spell as marked "non effective at already attacking target" // for spell as marked "non effective at already attacking target"
if (unitTarget == null || !unitTarget.CanHaveThreatList() if (!unitTarget.CanHaveThreatList() || unitTarget.GetVictim() == m_caster)
|| unitTarget.GetVictim() == m_caster)
{ {
SendCastResult(SpellCastResult.DontReport); SendCastResult(SpellCastResult.DontReport);
return; return;
-28
View File
@@ -4398,34 +4398,6 @@ namespace Game.Spells
return GetSelectionCategory() == SpellTargetSelectionCategories.Area || GetSelectionCategory() == SpellTargetSelectionCategories.Cone; return GetSelectionCategory() == SpellTargetSelectionCategories.Area || GetSelectionCategory() == SpellTargetSelectionCategories.Cone;
} }
public bool IsProximityBasedAoe()
{
switch (_target)
{
case Targets.UnitSrcAreaEntry:
case Targets.UnitSrcAreaEnemy:
case Targets.UnitCasterAreaParty:
case Targets.UnitSrcAreaAlly:
case Targets.UnitSrcAreaParty:
case Targets.UnitLastTargetAreaParty:
case Targets.GameobjectSrcArea:
case Targets.UnitCasterAreaRaid:
case Targets.CorpseSrcAreaEnemy:
return true;
case Targets.UnitDestAreaEntry:
case Targets.UnitDestAreaEnemy:
case Targets.UnitDestAreaAlly:
case Targets.UnitDestAreaParty:
case Targets.GameobjectDestArea:
case Targets.UnitAreaRaidClass:
return false;
default:
Log.outWarn(LogFilter.Spells, "SpellImplicitTargetInfo.IsProximityBasedAoe called a non-aoe spell");
return false;
}
}
public SpellTargetSelectionCategories GetSelectionCategory() public SpellTargetSelectionCategories GetSelectionCategory()
{ {
return _data[(int)_target].SelectionCategory; return _data[(int)_target].SelectionCategory;