aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp3
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp74
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.h1
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp26
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h23
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp3
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp4
-rw-r--r--src/server/game/Entities/Pet/Pet.cpp10
-rw-r--r--src/server/game/Entities/Totem/Totem.cpp2
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp44
-rw-r--r--src/server/game/Entities/Unit/Unit.h12
-rw-r--r--src/server/game/Handlers/PetHandler.cpp38
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp6
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.h2
-rw-r--r--src/server/game/Spells/Spell.cpp133
-rw-r--r--src/server/game/Spells/Spell.h6
-rw-r--r--src/server/game/Spells/SpellInfo.cpp23
-rw-r--r--src/server/game/Spells/SpellInfo.h4
-rw-r--r--src/server/game/Spells/SpellMgr.cpp14
-rw-r--r--src/server/game/Spells/SpellScript.cpp2
-rw-r--r--src/server/scripts/Northrend/DraktharonKeep/boss_tharon_ja.cpp343
-rw-r--r--src/server/scripts/Spells/spell_warrior.cpp3
22 files changed, 447 insertions, 329 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index f43a7f91f32..c5b5cd5dfef 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -433,11 +433,12 @@ void SmartAI::MovementInform(uint32 MovementType, uint32 Data)
void SmartAI::RemoveAuras()
{
+ /// @fixme: duplicated logic in CreatureAI::_EnterEvadeMode (could use RemoveAllAurasExceptType)
Unit::AuraApplicationMap& appliedAuras = me->GetAppliedAuras();
for (Unit::AuraApplicationMap::iterator iter = appliedAuras.begin(); iter != appliedAuras.end();)
{
Aura const* aura = iter->second->GetBase();
- if (!aura->IsPassive() && !aura->HasEffectType(SPELL_AURA_CONTROL_VEHICLE) && aura->GetCasterGUID() != me->GetGUID())
+ if (!aura->IsPassive() && !aura->HasEffectType(SPELL_AURA_CONTROL_VEHICLE) && !aura->HasEffectType(SPELL_AURA_CLONE_CASTER) && aura->GetCasterGUID() != me->GetGUID())
me->RemoveAura(iter);
else
++iter;
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index 65b1e6c331e..b4e18b66a69 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -1401,7 +1401,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
e.GetTargetType() == SMART_TARGET_GAMEOBJECT_GUID || e.GetTargetType() == SMART_TARGET_GAMEOBJECT_DISTANCE ||
e.GetTargetType() == SMART_TARGET_CLOSEST_CREATURE || e.GetTargetType() == SMART_TARGET_CLOSEST_GAMEOBJECT ||
e.GetTargetType() == SMART_TARGET_OWNER_OR_SUMMONER || e.GetTargetType() == SMART_TARGET_ACTION_INVOKER ||
- e.GetTargetType() == SMART_TARGET_CLOSEST_ENEMY)
+ e.GetTargetType() == SMART_TARGET_CLOSEST_ENEMY || e.GetTargetType() == SMART_TARGET_CLOSEST_FRIENDLY)
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
@@ -2506,6 +2506,14 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /*
break;
}
+ case SMART_TARGET_CLOSEST_FRIENDLY:
+ {
+ if (me)
+ if (Unit* target = DoFindClosestFriendlyInRange(e.target.closestFriendly.maxDist))
+ l->push_back(target);
+
+ break;
+ }
case SMART_TARGET_POSITION:
default:
break;
@@ -2623,7 +2631,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
return;
Unit* target = DoSelectLowestHpFriendly((float)e.event.friendlyHealt.radius, e.event.friendlyHealt.hpDeficit);
- if (!target)
+ if (!target || !target->IsInCombat())
return;
ProcessTimedAction(e, e.event.friendlyHealt.repeatMin, e.event.friendlyHealt.repeatMax, target);
break;
@@ -2940,6 +2948,55 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
ProcessAction(e, unit, var0);
break;
}
+ case SMART_EVENT_FRIENDLY_HEALTH_PCT:
+ {
+ if (!me || !me->IsInCombat())
+ return;
+
+ ObjectList* _targets = NULL;
+
+ switch (e.GetTargetType())
+ {
+ case SMART_TARGET_CREATURE_RANGE:
+ case SMART_TARGET_CREATURE_GUID:
+ case SMART_TARGET_CREATURE_DISTANCE:
+ case SMART_TARGET_CLOSEST_CREATURE:
+ case SMART_TARGET_CLOSEST_PLAYER:
+ case SMART_TARGET_PLAYER_RANGE:
+ case SMART_TARGET_PLAYER_DISTANCE:
+ _targets = GetTargets(e);
+ break;
+ default:
+ return;
+ }
+
+ if (!_targets)
+ return;
+
+ Unit* target = NULL;
+
+ for (ObjectList::const_iterator itr = _targets->begin(); itr != _targets->end(); ++itr)
+ {
+ if (IsUnit(*itr) && me->IsFriendlyTo((*itr)->ToUnit()) && (*itr)->ToUnit()->IsAlive() && (*itr)->ToUnit()->IsInCombat())
+ {
+ uint32 healthPct = uint32((*itr)->ToUnit()->GetHealthPct());
+
+ if (healthPct > e.event.friendlyHealtPct.maxHpPct || healthPct < e.event.friendlyHealtPct.minHpPct)
+ continue;
+
+ target = (*itr)->ToUnit();
+ break;
+ }
+ }
+
+ delete _targets;
+
+ if (!target)
+ return;
+
+ ProcessTimedAction(e, e.event.friendlyHealtPct.repeatMin, e.event.friendlyHealtPct.repeatMax, target);
+ break;
+ }
default:
TC_LOG_ERROR(LOG_FILTER_SQL, "SmartScript::ProcessEvent: Unhandled Event type %u", e.GetEventType());
break;
@@ -3019,6 +3076,7 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff)
case SMART_EVENT_HAS_AURA:
case SMART_EVENT_TARGET_BUFFED:
case SMART_EVENT_IS_BEHIND_TARGET:
+ case SMART_EVENT_FRIENDLY_HEALTH_PCT:
{
ProcessEvent(e);
if (e.GetScriptType() == SMART_SCRIPT_TYPE_TIMED_ACTIONLIST)
@@ -3324,6 +3382,18 @@ void SmartScript::DoFindFriendlyMissingBuff(std::list<Creature*>& list, float ra
cell.Visit(p, grid_creature_searcher, *me->GetMap(), *me, range);
}
+Unit* SmartScript::DoFindClosestFriendlyInRange(float range)
+{
+ if (!me)
+ return NULL;
+
+ Unit* unit = NULL;
+ Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(me, me, range);
+ Trinity::UnitLastSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(me, unit, u_check);
+ me->VisitNearbyObject(range, searcher);
+ return unit;
+}
+
void SmartScript::SetScript9(SmartScriptHolder& e, uint32 entry)
{
mTimedActionList.clear();
diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h
index 6801c132331..b22f2d81b26 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.h
+++ b/src/server/game/AI/SmartScripts/SmartScript.h
@@ -89,6 +89,7 @@ class SmartScript
Unit* DoSelectLowestHpFriendly(float range, uint32 MinHPDiff);
void DoFindFriendlyCC(std::list<Creature*>& _list, float range);
void DoFindFriendlyMissingBuff(std::list<Creature*>& list, float range, uint32 spellid);
+ Unit* DoFindClosestFriendlyInRange(float range);
void StoreTargetList(ObjectList* targets, uint32 id)
{
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index 99693355d70..1e20d2e6fbb 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -301,6 +301,7 @@ bool SmartAIMgr::IsTargetValid(SmartScriptHolder const& e)
case SMART_TARGET_CLOSEST_GAMEOBJECT:
case SMART_TARGET_CLOSEST_CREATURE:
case SMART_TARGET_CLOSEST_ENEMY:
+ case SMART_TARGET_CLOSEST_FRIENDLY:
case SMART_TARGET_STORED:
break;
default:
@@ -544,6 +545,31 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
}
break;
}
+ case SMART_EVENT_FRIENDLY_HEALTH_PCT:
+ if (!IsMinMaxValid(e, e.event.friendlyHealtPct.repeatMin, e.event.friendlyHealtPct.repeatMax))
+ return false;
+
+ if (e.event.friendlyHealtPct.maxHpPct > 100 || e.event.friendlyHealtPct.minHpPct > 100)
+ {
+ TC_LOG_ERROR(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u has pct value above 100, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
+ return false;
+ }
+
+ switch (e.GetTargetType())
+ {
+ case SMART_TARGET_CREATURE_RANGE:
+ case SMART_TARGET_CREATURE_GUID:
+ case SMART_TARGET_CREATURE_DISTANCE:
+ case SMART_TARGET_CLOSEST_CREATURE:
+ case SMART_TARGET_CLOSEST_PLAYER:
+ case SMART_TARGET_PLAYER_RANGE:
+ case SMART_TARGET_PLAYER_DISTANCE:
+ break;
+ default:
+ TC_LOG_ERROR(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses invalid target_type %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType());
+ return false;
+ }
+ break;
case SMART_EVENT_GO_STATE_CHANGED:
case SMART_EVENT_GO_EVENT_INFORM:
case SMART_EVENT_TIMED_EVENT_TRIGGERED:
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index 740be9276b2..05880c07ff4 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -155,8 +155,9 @@ enum SMART_EVENT
SMART_EVENT_GO_EVENT_INFORM = 71, // eventId
SMART_EVENT_ACTION_DONE = 72, // eventId (SharedDefines.EventId)
SMART_EVENT_ON_SPELLCLICK = 73, // clicker (unit)
+ SMART_EVENT_FRIENDLY_HEALTH_PCT = 74, // minHpPct, maxHpPct, repeatMin, repeatMax
- SMART_EVENT_END = 74
+ SMART_EVENT_END = 75
};
struct SmartEvent
@@ -363,6 +364,14 @@ struct SmartEvent
struct
{
+ uint32 minHpPct;
+ uint32 maxHpPct;
+ uint32 repeatMin;
+ uint32 repeatMax;
+ } friendlyHealtPct;
+
+ struct
+ {
uint32 param1;
uint32 param2;
uint32 param3;
@@ -1001,7 +1010,9 @@ enum SMARTAI_TARGETS
SMART_TARGET_OWNER_OR_SUMMONER = 23, // Unit's owner or summoner
SMART_TARGET_THREAT_LIST = 24, // All units on creature's threat list
SMART_TARGET_CLOSEST_ENEMY = 25, // maxDist
- SMART_TARGET_END = 26
+ SMART_TARGET_CLOSEST_FRIENDLY = 26, // maxDist
+
+ SMART_TARGET_END = 27
};
struct SmartTarget
@@ -1090,6 +1101,11 @@ struct SmartTarget
struct
{
+ uint32 maxDist;
+ } closestFriendly;
+
+ struct
+ {
uint32 param1;
uint32 param2;
uint32 param3;
@@ -1225,7 +1241,8 @@ const uint32 SmartAIEventMask[SMART_EVENT_END][2] =
{SMART_EVENT_GO_STATE_CHANGED, SMART_SCRIPT_TYPE_MASK_GAMEOBJECT },
{SMART_EVENT_GO_EVENT_INFORM, SMART_SCRIPT_TYPE_MASK_GAMEOBJECT },
{SMART_EVENT_ACTION_DONE, SMART_SCRIPT_TYPE_MASK_CREATURE },
- {SMART_EVENT_ON_SPELLCLICK, SMART_SCRIPT_TYPE_MASK_CREATURE }
+ {SMART_EVENT_ON_SPELLCLICK, SMART_SCRIPT_TYPE_MASK_CREATURE },
+ {SMART_EVENT_FRIENDLY_HEALTH_PCT, SMART_SCRIPT_TYPE_MASK_CREATURE },
};
enum SmartEventFlags
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp
index d13fc6d697b..03c4b84b817 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp
@@ -973,8 +973,7 @@ bool BattlegroundSA::CheckAchievementCriteriaMeet(uint32 criteriaId, Player cons
case BG_CRITERIA_CHECK_NOT_EVEN_A_SCRATCH:
return _allVehiclesAlive[GetTeamIndexByTeamId(source->GetTeam())];
case BG_CRITERIA_CHECK_DEFENSE_OF_THE_ANCIENTS:
- if (source->GetTeamId() != Attackers && !gateDestroyed)
- return true;
+ return source->GetTeamId() != Attackers && !gateDestroyed;
}
return Battleground::CheckAchievementCriteriaMeet(criteriaId, source, target, miscValue);
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp
index 419a4eff84c..5e0cade9b37 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp
@@ -877,9 +877,7 @@ bool BattlegroundWS::CheckAchievementCriteriaMeet(uint32 criteriaId, Player cons
switch (criteriaId)
{
case BG_CRITERIA_CHECK_SAVE_THE_DAY:
- if (GetFlagState(player->GetTeam()) == BG_WS_FLAG_STATE_ON_BASE)
- return true;
- break;
+ return GetFlagState(player->GetTeam()) == BG_WS_FLAG_STATE_ON_BASE;
}
return Battleground::CheckAchievementCriteriaMeet(criteriaId, player, target, miscValue);
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index 4c8d48222e5..69a381ceb3d 100644
--- a/src/server/game/Entities/Pet/Pet.cpp
+++ b/src/server/game/Entities/Pet/Pet.cpp
@@ -1548,16 +1548,16 @@ void Pet::InitLevelupSpellsForLevel()
{
for (uint8 i = 0; i < MAX_CREATURE_SPELL_DATA_SLOT; ++i)
{
- SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(defSpells->spellid[i]);
- if (!spellEntry)
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(defSpells->spellid[i]);
+ if (!spellInfo)
continue;
// will called first if level down
- if (spellEntry->SpellLevel > level)
- unlearnSpell(spellEntry->Id, true);
+ if (spellInfo->SpellLevel > level)
+ unlearnSpell(spellInfo->Id, true);
// will called if level up
else
- learnSpell(spellEntry->Id);
+ learnSpell(spellInfo->Id);
}
}
}
diff --git a/src/server/game/Entities/Totem/Totem.cpp b/src/server/game/Entities/Totem/Totem.cpp
index 3b283ca39c2..ddea24c6439 100644
--- a/src/server/game/Entities/Totem/Totem.cpp
+++ b/src/server/game/Entities/Totem/Totem.cpp
@@ -109,7 +109,7 @@ void Totem::UnSummon(uint32 msTime)
RemoveAurasDueToSpell(GetSpell(), GetGUID());
// clear owner's totem slot
- for (int i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
+ for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
{
if (GetOwner()->m_SummonSlot[i] == GetGUID())
{
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index ef695bb1eea..629b202470d 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -162,7 +162,7 @@ ProcEventInfo::ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget,
#endif
Unit::Unit(bool isWorldObject) :
WorldObject(isWorldObject), m_movedPlayer(NULL), m_lastSanctuaryTime(0),
- m_TempSpeed(0.0f), IsAIEnabled(false), NeedChangeAI(false),
+ IsAIEnabled(false), NeedChangeAI(false),
m_ControlledByPlayer(false), movespline(new Movement::MoveSpline()),
i_AI(NULL), i_disabledAI(NULL), m_AutoRepeatFirstCast(false), m_procDeep(0),
m_removedAurasCount(0), i_motionMaster(this), m_ThreatManager(this),
@@ -195,8 +195,6 @@ Unit::Unit(bool isWorldObject) :
for (uint8 i = 0; i < CURRENT_MAX_SPELL; ++i)
m_currentSpells[i] = NULL;
- m_addDmgOnce = 0;
-
for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
m_SummonSlot[i] = 0;
@@ -2970,11 +2968,11 @@ void Unit::SetCurrentCastedSpell(Spell* pSpell)
if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
{
// break autorepeat if not Auto Shot
- if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != 75)
+ if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetSpellInfo()->Id != 75)
InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
m_AutoRepeatFirstCast = true;
}
- if (pSpell->m_spellInfo->CalcCastTime(this) > 0)
+ if (pSpell->GetCastTime() > 0)
AddUnitState(UNIT_STATE_CASTING);
break;
@@ -2987,7 +2985,7 @@ void Unit::SetCurrentCastedSpell(Spell* pSpell)
// it also does break autorepeat if not Auto Shot
if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL] &&
- m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != 75)
+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetSpellInfo()->Id != 75)
InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
AddUnitState(UNIT_STATE_CASTING);
@@ -2996,7 +2994,7 @@ void Unit::SetCurrentCastedSpell(Spell* pSpell)
case CURRENT_AUTOREPEAT_SPELL:
{
// only Auto Shoot does not break anything
- if (pSpell->m_spellInfo->Id != 75)
+ if (pSpell->GetSpellInfo()->Id != 75)
{
// generic autorepeats break generic non-delayed and channeled non-delayed spells
InterruptSpell(CURRENT_GENERIC_SPELL, false);
@@ -7588,7 +7586,8 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, Sp
// Blood of the North
// Reaping
// Death Rune Mastery
- if (dummySpell->SpellIconID == 3041 || dummySpell->SpellIconID == 22 || dummySpell->SpellIconID == 2622)
+ /// @todo move those to spell scripts
+ if (dummySpell->SpellIconID == 3041 || (dummySpell->SpellIconID == 22 && dummySpell->Id != 62459) || dummySpell->SpellIconID == 2622)
{
*handled = true;
// Convert recently used Blood Rune to Death Rune
@@ -8143,12 +8142,6 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
return false;
break;
}
- // Rogue T10 4P bonus, should proc on victim
- case 70803:
- {
- target = victim;
- break;
- }
}
break;
}
@@ -14072,11 +14065,10 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
if (spellInfo->AttributesEx3 & SPELL_ATTR3_DISABLE_PROC)
SetCantProc(true);
- i->aura->CallScriptProcHandlers(aurApp, eventInfo);
+ bool handled = i->aura->CallScriptProcHandlers(aurApp, eventInfo);
- // This bool is needed till separate aura effect procs are still here
- bool handled = false;
- if (HandleAuraProc(target, damage, i->aura, procSpell, procFlag, procExtra, cooldown, &handled))
+ // "handled" is needed as long as proc can be handled in multiple places
+ if (!handled && HandleAuraProc(target, damage, i->aura, procSpell, procFlag, procExtra, cooldown, &handled))
{
TC_LOG_DEBUG(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell %u (triggered with value by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), Id);
takeCharges = true;
@@ -14359,22 +14351,6 @@ Player* Unit::GetSpellModOwner() const
}
///----------Pet responses methods-----------------
-void Unit::SendPetCastFail(uint32 spellid, SpellCastResult result)
-{
- if (result == SPELL_CAST_OK)
- return;
-
- Unit* owner = GetCharmerOrOwner();
- if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
- return;
-
- WorldPacket data(SMSG_PET_CAST_FAILED, 1 + 4 + 1);
- data << uint8(0); // cast count
- data << uint32(spellid);
- data << uint8(result);
- owner->ToPlayer()->GetSession()->SendPacket(&data);
-}
-
void Unit::SendPetActionFeedback(uint8 msg)
{
Unit* owner = GetOwner();
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 5e2e746ae63..14a4decb390 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -951,7 +951,8 @@ struct CalcDamageInfo
};
// Spell damage info structure based on structure sending in SMSG_SPELLNONMELEEDAMAGELOG opcode
-struct SpellNonMeleeDamage{
+struct SpellNonMeleeDamage
+{
SpellNonMeleeDamage(Unit* _attacker, Unit* _target, uint32 _SpellID, uint32 _schoolMask)
: target(_target), attacker(_attacker), SpellID(_SpellID), damage(0), overkill(0), schoolMask(_schoolMask),
absorb(0), resist(0), physicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0)
@@ -1647,8 +1648,8 @@ class Unit : public WorldObject
Player* GetSpellModOwner() const;
Unit* GetOwner() const;
- Guardian *GetGuardianPet() const;
- Minion *GetFirstMinion() const;
+ Guardian* GetGuardianPet() const;
+ Minion* GetFirstMinion() const;
Unit* GetCharmer() const;
Unit* GetCharm() const;
Unit* GetCharmerOrOwner() const;
@@ -1839,7 +1840,6 @@ class Unit : public WorldObject
Spell* FindCurrentSpellBySpellId(uint32 spell_id) const;
int32 GetCurrentSpellCastTime(uint32 spell_id) const;
- uint32 m_addDmgOnce;
uint64 m_SummonSlot[MAX_SUMMON_SLOT];
uint64 m_ObjectSlot[MAX_GAMEOBJECT_SLOT];
@@ -1995,9 +1995,6 @@ class Unit : public WorldObject
float GetSpeed(UnitMoveType mtype) const;
float GetSpeedRate(UnitMoveType mtype) const { return m_speed_rate[mtype]; }
void SetSpeed(UnitMoveType mtype, float rate, bool forced = false);
- float m_TempSpeed;
-
- bool isHover() const { return HasAuraType(SPELL_AURA_HOVER); }
float ApplyEffectModifiers(SpellInfo const* spellProto, uint8 effect_index, float value) const;
int32 CalculateSpellDamage(Unit const* target, SpellInfo const* spellProto, uint8 effect_index, int32 const* basePoints = NULL) const;
@@ -2039,7 +2036,6 @@ class Unit : public WorldObject
void ClearComboPointHolders();
///----------Pet responses methods-----------------
- void SendPetCastFail(uint32 spellid, SpellCastResult msg);
void SendPetActionFeedback (uint8 msg);
void SendPetTalk (uint32 pettalk);
void SendPetAIReaction(uint64 guid);
diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp
index 84bdaf4104f..32cd7ee4725 100644
--- a/src/server/game/Handlers/PetHandler.cpp
+++ b/src/server/game/Handlers/PetHandler.cpp
@@ -295,10 +295,6 @@ void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint32 spellid
return;
}
- if (spellInfo->StartRecoveryCategory > 0)
- if (pet->GetCharmInfo() && pet->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo))
- return;
-
for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
if (spellInfo->Effects[i].TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENEMY || spellInfo->Effects[i].TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENEMY || spellInfo->Effects[i].TargetA.GetTarget() == TARGET_DEST_DYNOBJ_ENEMY)
@@ -378,10 +374,10 @@ void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint32 spellid
}
else
{
- if (pet->isPossessed() || pet->IsVehicle())
+ if (pet->isPossessed() || pet->IsVehicle()) /// @todo: confirm this check
Spell::SendCastResult(GetPlayer(), spellInfo, 0, result);
else
- pet->SendPetCastFail(spellid, result);
+ spell->SendPetCastResult(result);
if (!pet->ToCreature()->HasSpellCooldown(spellid))
GetPlayer()->SendClearCooldown(spellid, pet);
@@ -771,13 +767,6 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
return;
}
- if (spellInfo->StartRecoveryCategory > 0) // Check if spell is affected by GCD
- if (caster->GetTypeId() == TYPEID_UNIT && caster->GetCharmInfo() && caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo))
- {
- caster->SendPetCastFail(spellId, SPELL_FAILED_NOT_READY);
- return;
- }
-
// do not cast not learned spells
if (!caster->HasSpell(spellId) || spellInfo->IsPassive())
return;
@@ -792,25 +781,19 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
spell->m_cast_count = castCount; // probably pending spell cast
spell->m_targets = targets;
- /// @todo need to check victim?
- SpellCastResult result;
- if (caster->m_movedPlayer)
- result = spell->CheckPetCast(caster->m_movedPlayer->GetSelectedUnit());
- else
- result = spell->CheckPetCast(NULL);
+ SpellCastResult result = spell->CheckPetCast(NULL);
+
if (result == SPELL_CAST_OK)
{
- if (caster->GetTypeId() == TYPEID_UNIT)
+ if (Creature* creature = caster->ToCreature())
{
- Creature* pet = caster->ToCreature();
- pet->AddCreatureSpellCooldown(spellId);
- if (pet->IsPet())
+ creature->AddCreatureSpellCooldown(spellId);
+ if (Pet* pet = creature->ToPet())
{
- Pet* p = (Pet*)pet;
// 10% chance to play special pet attack talk, else growl
// actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
- if (p->getPetType() == SUMMON_PET && (urand(0, 100) < 10))
- pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL);
+ if (pet->getPetType() == SUMMON_PET && (urand(0, 100) < 10))
+ pet->SendPetTalk(PET_TALK_SPECIAL_SPELL);
else
pet->SendPetAIReaction(guid);
}
@@ -820,7 +803,8 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
}
else
{
- caster->SendPetCastFail(spellId, result);
+ spell->SendPetCastResult(result);
+
if (caster->GetTypeId() == TYPEID_PLAYER)
{
if (!caster->ToPlayer()->HasSpellCooldown(spellId))
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 2846137ad95..51a04749c30 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -2269,8 +2269,9 @@ bool Aura::CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEven
return prepare;
}
-void Aura::CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
+bool Aura::CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
{
+ bool handled = false;
for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_PROC, aurApp);
@@ -2278,8 +2279,11 @@ void Aura::CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo&
for (; hookItr != hookItrEnd; ++hookItr)
hookItr->Call(*scritr, eventInfo);
+ handled |= (*scritr)->_IsDefaultActionPrevented();
(*scritr)->_FinishScriptCall();
}
+
+ return handled;
}
void Aura::CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h
index e865d415438..9e7d0cce82c 100644
--- a/src/server/game/Spells/Auras/SpellAuras.h
+++ b/src/server/game/Spells/Auras/SpellAuras.h
@@ -229,7 +229,7 @@ class Aura
// Spell Proc Hooks
bool CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
bool CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
- void CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
+ bool CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
void CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
bool CallScriptEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo);
void CallScriptAfterEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo);
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 13a6cffeb12..be88179b168 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -2038,6 +2038,15 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar
}
}
+GameObject* Spell::SearchSpellFocus()
+{
+ GameObject* focus = NULL;
+ Trinity::GameObjectFocusCheck check(m_caster, m_spellInfo->RequiresSpellFocus);
+ Trinity::GameObjectSearcher<Trinity::GameObjectFocusCheck> searcher(m_caster, focus, check);
+ SearchTargets<Trinity::GameObjectSearcher<Trinity::GameObjectFocusCheck> > (searcher, GRID_MAP_TYPE_MASK_GAMEOBJECT, m_caster, m_caster, m_caster->GetVisibilityRange());
+ return focus;
+}
+
void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
{
//==========================================================================================
@@ -3041,18 +3050,20 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered
// Prepare data for triggers
prepareDataForTriggerSystem(triggeredByAura);
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
- m_caster->ToPlayer()->SetSpellModTakingSpell(this, true);
- // calculate cast time (calculated after first CheckCast check to prevent charge counting for first CheckCast fail)
- m_casttime = m_spellInfo->CalcCastTime(m_caster, this);
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
+ if (Player* player = m_caster->ToPlayer())
{
- m_caster->ToPlayer()->SetSpellModTakingSpell(this, false);
-
- // Set casttime to 0 if .cheat casttime is enabled.
- if (m_caster->ToPlayer()->GetCommandStatus(CHEAT_CASTTIME))
- m_casttime = 0;
+ if (!m_caster->ToPlayer()->GetCommandStatus(CHEAT_CASTTIME))
+ {
+ m_caster->ToPlayer()->SetSpellModTakingSpell(this, true);
+ // calculate cast time (calculated after first CheckCast check to prevent charge counting for first CheckCast fail)
+ m_casttime = m_spellInfo->CalcCastTime(this);
+ m_caster->ToPlayer()->SetSpellModTakingSpell(this, false);
+ }
+ else
+ m_casttime = 0; // Set cast time to 0 if .cheat casttime is enabled.
}
+ else
+ m_casttime = m_spellInfo->CalcCastTime(this);
// don't allow channeled spells / spells with cast time to be casted while moving
// (even if they are interrupted on moving, spells with almost immediate effect get to have their effect processed before movement interrupter kicks in)
@@ -3314,7 +3325,7 @@ void Spell::cast(bool skipCheck)
SendSpellGo();
// Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
- if ((m_spellInfo->Speed > 0.0f && !m_spellInfo->IsChanneled()) || m_spellInfo->Id == 14157)
+ if ((m_spellInfo->Speed > 0.0f && !m_spellInfo->IsChanneled()) || m_spellInfo->AttributesEx4 & SPELL_ATTR4_UNK4)
{
// Remove used for cast item if need (it can be already NULL after TakeReagents call
// in case delayed spell remove item at cast delay start
@@ -3755,27 +3766,9 @@ void Spell::finish(bool ok)
m_caster->AttackStop();
}
-void Spell::SendCastResult(SpellCastResult result)
-{
- if (result == SPELL_CAST_OK)
- return;
-
- if (m_caster->GetTypeId() != TYPEID_PLAYER)
- return;
-
- if (m_caster->ToPlayer()->GetSession()->PlayerLoading()) // don't send cast results at loading time
- return;
-
- SendCastResult(m_caster->ToPlayer(), m_spellInfo, m_cast_count, result, m_customError);
-}
-
-void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cast_count, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/)
+void Spell::WriteCastResultInfo(WorldPacket& data, Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError)
{
- if (result == SPELL_CAST_OK)
- return;
-
- WorldPacket data(SMSG_CAST_FAILED, (4+1+1));
- data << uint8(cast_count); // single cast or multi 2.3 (0/1)
+ data << uint8(castCount); // single cast or multi 2.3 (0/1)
data << uint32(spellInfo->Id);
data << uint8(result); // problem
switch (result)
@@ -3876,9 +3869,52 @@ void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cas
default:
break;
}
+}
+
+void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/)
+{
+ if (result == SPELL_CAST_OK)
+ return;
+
+ WorldPacket data(SMSG_CAST_FAILED, 1 + 4 + 1);
+ WriteCastResultInfo(data, caster, spellInfo, castCount, result, customError);
+
caster->GetSession()->SendPacket(&data);
}
+void Spell::SendCastResult(SpellCastResult result)
+{
+ if (result == SPELL_CAST_OK)
+ return;
+
+ if (m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ if (m_caster->ToPlayer()->GetSession()->PlayerLoading()) // don't send cast results at loading time
+ return;
+
+ SendCastResult(m_caster->ToPlayer(), m_spellInfo, m_cast_count, result, m_customError);
+}
+
+void Spell::SendPetCastResult(SpellCastResult result)
+{
+ if (result == SPELL_CAST_OK)
+ return;
+
+ Unit* owner = m_caster->GetCharmerOrOwner();
+ if (!owner)
+ return;
+
+ Player* player = owner->ToPlayer();
+ if (!player)
+ return;
+
+ WorldPacket data(SMSG_PET_CAST_FAILED, 1 + 4 + 1);
+ WriteCastResultInfo(data, player, m_spellInfo, m_cast_count, result, m_customError);
+
+ player->GetSession()->SendPacket(&data);
+}
+
void Spell::SendSpellStart()
{
if (!IsNeedSendToClient())
@@ -4981,9 +5017,17 @@ SpellCastResult Spell::CheckCast(bool strict)
return SPELL_FAILED_NOT_MOUNTED;
}
+ // check spell focus object
+ if (m_spellInfo->RequiresSpellFocus)
+ {
+ focusObject = SearchSpellFocus();
+ if (!focusObject)
+ return SPELL_FAILED_REQUIRES_SPELL_FOCUS;
+ }
+
SpellCastResult castResult = SPELL_CAST_OK;
- // always (except passive spells) check items (focus object can be required for any type casts)
+ // always (except passive spells) check items (only player related checks)
if (!m_spellInfo->IsPassive())
{
castResult = CheckItems();
@@ -5585,6 +5629,11 @@ SpellCastResult Spell::CheckPetCast(Unit* target)
if (creatureCaster->HasSpellCooldown(m_spellInfo->Id))
return SPELL_FAILED_NOT_READY;
+ // Check if spell is affected by GCD
+ if (m_spellInfo->StartRecoveryCategory > 0)
+ if (m_caster->GetCharmInfo() && m_caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(m_spellInfo))
+ return SPELL_FAILED_NOT_READY;
+
return CheckCast(true);
}
@@ -5947,26 +5996,6 @@ SpellCastResult Spell::CheckItems()
return SPELL_FAILED_EQUIPPED_ITEM_CLASS;
}
- // check spell focus object
- if (m_spellInfo->RequiresSpellFocus)
- {
- CellCoord p(Trinity::ComputeCellCoord(m_caster->GetPositionX(), m_caster->GetPositionY()));
- Cell cell(p);
-
- GameObject* ok = NULL;
- Trinity::GameObjectFocusCheck go_check(m_caster, m_spellInfo->RequiresSpellFocus);
- Trinity::GameObjectSearcher<Trinity::GameObjectFocusCheck> checker(m_caster, ok, go_check);
-
- TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectFocusCheck>, GridTypeMapContainer > object_checker(checker);
- Map& map = *m_caster->GetMap();
- cell.Visit(p, object_checker, map, *m_caster, m_caster->GetVisibilityRange());
-
- if (!ok)
- return SPELL_FAILED_REQUIRES_SPELL_FOCUS;
-
- focusObject = ok; // game object found in range
- }
-
// do not take reagents for these item casts
if (!(m_CastItem && m_CastItem->GetTemplate()->Flags & ITEM_PROTO_FLAG_TRIGGERED_CAST))
{
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 191a7461fe9..927ecd32f29 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -370,6 +370,8 @@ class Spell
void SearchAreaTargets(std::list<WorldObject*>& targets, float range, Position const* position, Unit* referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionList* condList);
void SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, ConditionList* condList, bool isChainHeal);
+ GameObject* SearchSpellFocus();
+
void prepare(SpellCastTargets const* targets, AuraEffect const* triggeredByAura = NULL);
void cancel();
void update(uint32 difftime);
@@ -415,8 +417,10 @@ class Spell
void CheckSrc() { if (!m_targets.HasSrc()) m_targets.SetSrc(*m_caster); }
void CheckDst() { if (!m_targets.HasDst()) m_targets.SetDst(*m_caster); }
- static void SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cast_count, SpellCastResult result, SpellCustomErrors customError = SPELL_CUSTOM_ERROR_NONE);
+ static void WriteCastResultInfo(WorldPacket& data, Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError);
+ static void SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError = SPELL_CUSTOM_ERROR_NONE);
void SendCastResult(SpellCastResult result);
+ void SendPetCastResult(SpellCastResult result);
void SendSpellStart();
void SendSpellGo();
void SendSpellCooldown();
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index a58c2ee19e4..04437b82f2d 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -1006,8 +1006,12 @@ bool SpellInfo::NeedsExplicitUnitTarget() const
bool SpellInfo::NeedsToBeTriggeredByCaster() const
{
+ if (AttributesCu & SPELL_ATTR0_CU_TRIGGERED_BY_CASTER)
+ return true;
+
if (NeedsExplicitUnitTarget())
return true;
+
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
if (Effects[i].IsEffect())
@@ -1017,6 +1021,7 @@ bool SpellInfo::NeedsToBeTriggeredByCaster() const
return true;
}
}
+
return false;
}
@@ -1714,7 +1719,7 @@ uint32 SpellInfo::GetAllEffectsMechanicMask() const
uint32 mask = 0;
if (Mechanic)
mask |= 1 << Mechanic;
- for (int i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if (Effects[i].IsEffect() && Effects[i].Mechanic)
mask |= 1 << Effects[i].Mechanic;
return mask;
@@ -1724,9 +1729,9 @@ uint32 SpellInfo::GetEffectMechanicMask(uint8 effIndex) const
{
uint32 mask = 0;
if (Mechanic)
- mask |= 1<< Mechanic;
+ mask |= 1 << Mechanic;
if (Effects[effIndex].IsEffect() && Effects[effIndex].Mechanic)
- mask |= 1<< Effects[effIndex].Mechanic;
+ mask |= 1 << Effects[effIndex].Mechanic;
return mask;
}
@@ -1734,10 +1739,10 @@ uint32 SpellInfo::GetSpellMechanicMaskByEffectMask(uint32 effectMask) const
{
uint32 mask = 0;
if (Mechanic)
- mask |= 1<< Mechanic;
- for (int i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ mask |= 1 << Mechanic;
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if ((effectMask & (1 << i)) && Effects[i].Mechanic)
- mask |= 1<< Effects[i].Mechanic;
+ mask |= 1 << Effects[i].Mechanic;
return mask;
}
@@ -2052,7 +2057,7 @@ int32 SpellInfo::GetMaxDuration() const
return (DurationEntry->Duration[2] == -1) ? -1 : abs(DurationEntry->Duration[2]);
}
-uint32 SpellInfo::CalcCastTime(Unit* caster, Spell* spell) const
+uint32 SpellInfo::CalcCastTime(Spell* spell /*= NULL*/) const
{
// not all spells have cast time index and this is all is pasiive abilities
if (!CastTimeEntry)
@@ -2060,8 +2065,8 @@ uint32 SpellInfo::CalcCastTime(Unit* caster, Spell* spell) const
int32 castTime = CastTimeEntry->CastTime;
- if (caster)
- caster->ModSpellCastTime(this, castTime, spell);
+ if (spell)
+ spell->GetCaster()->ModSpellCastTime(this, castTime, spell);
if (Attributes & SPELL_ATTR0_REQ_AMMO && (!IsAutoRepeatRangedSpell()))
castTime += 500;
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index 6ed742a3b8e..6acde5afa74 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -176,7 +176,7 @@ enum SpellCustomAttributes
SPELL_ATTR0_CU_CONE_LINE = 0x00000004,
SPELL_ATTR0_CU_SHARE_DAMAGE = 0x00000008,
SPELL_ATTR0_CU_NO_INITIAL_THREAT = 0x00000010,
- SPELL_ATTR0_CU_NONE2 = 0x00000020, // UNUSED
+ SPELL_ATTR0_CU_TRIGGERED_BY_CASTER = 0x00000020, // @todo: need generic solution, some triggered spells will be casted by target instead of caster
SPELL_ATTR0_CU_AURA_CC = 0x00000040,
SPELL_ATTR0_CU_DIRECT_DAMAGE = 0x00000100,
SPELL_ATTR0_CU_CHARGE = 0x00000200,
@@ -444,7 +444,7 @@ public:
uint32 GetMaxTicks() const;
- uint32 CalcCastTime(Unit* caster = NULL, Spell* spell = NULL) const;
+ uint32 CalcCastTime(Spell* spell = NULL) const;
uint32 GetRecoveryTime() const;
int32 CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) const;
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 24bd19d2d24..94454e8440d 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -2972,6 +2972,9 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
case 72293: // Mark of the Fallen Champion (Deathbringer Saurfang)
spellInfo->AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF0;
break;
+ case 38729: // Rod of Purification
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_TRIGGERED_BY_CASTER;
+ break;
default:
break;
}
@@ -3103,6 +3106,17 @@ void SpellMgr::LoadSpellInfoCorrections()
// Entries were not updated after spell effect change, we have to do that manually :/
spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED;
break;
+ case 5308: // Execute (Rank 1)
+ case 20658: // Execute (Rank 2)
+ case 20660: // Execute (Rank 3)
+ case 20661: // Execute (Rank 4)
+ case 20662: // Execute (Rank 5)
+ case 25234: // Execute (Rank 6)
+ case 25236: // Execute (Rank 7)
+ case 47470: // Execute (Rank 8)
+ case 47471: // Execute (Rank 9)
+ spellInfo->AttributesEx3 |= SPELL_ATTR3_CANT_TRIGGER_PROC;
+ break;
case 59725: // Improved Spell Reflection - aoe aura
// Target entry seems to be wrong for this spell :/
spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER_AREA_PARTY);
diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp
index 5fb4d69cd02..bb9aab023af 100644
--- a/src/server/game/Spells/SpellScript.cpp
+++ b/src/server/game/Spells/SpellScript.cpp
@@ -909,6 +909,7 @@ bool AuraScript::_IsDefaultActionPrevented()
case AURA_SCRIPT_HOOK_EFFECT_ABSORB:
case AURA_SCRIPT_HOOK_EFFECT_SPLIT:
case AURA_SCRIPT_HOOK_PREPARE_PROC:
+ case AURA_SCRIPT_HOOK_PROC:
case AURA_SCRIPT_HOOK_EFFECT_PROC:
return m_defaultActionPrevented;
default:
@@ -927,6 +928,7 @@ void AuraScript::PreventDefaultAction()
case AURA_SCRIPT_HOOK_EFFECT_ABSORB:
case AURA_SCRIPT_HOOK_EFFECT_SPLIT:
case AURA_SCRIPT_HOOK_PREPARE_PROC:
+ case AURA_SCRIPT_HOOK_PROC:
case AURA_SCRIPT_HOOK_EFFECT_PROC:
m_defaultActionPrevented = true;
break;
diff --git a/src/server/scripts/Northrend/DraktharonKeep/boss_tharon_ja.cpp b/src/server/scripts/Northrend/DraktharonKeep/boss_tharon_ja.cpp
index e090f3db7c0..efca060b67c 100644
--- a/src/server/scripts/Northrend/DraktharonKeep/boss_tharon_ja.cpp
+++ b/src/server/scripts/Northrend/DraktharonKeep/boss_tharon_ja.cpp
@@ -17,29 +17,48 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
-#include "drak_tharon_keep.h"
+#include "SpellScript.h"
+#include "SpellAuraEffects.h"
#include "Player.h"
+#include "drak_tharon_keep.h"
+
+/*
+ * Known Issues: Spell 49356 and 53463 will be interrupted for an unknown reason
+ */
enum Spells
{
- //skeletal spells (phase 1)
+ // Skeletal Spells (phase 1)
SPELL_CURSE_OF_LIFE = 49527,
- H_SPELL_CURSE_OF_LIFE = 59972,
SPELL_RAIN_OF_FIRE = 49518,
- H_SPELL_RAIN_OF_FIRE = 59971,
SPELL_SHADOW_VOLLEY = 49528,
- H_SPELL_SHADOW_VOLLEY = 59973,
- SPELL_DECAY_FLESH = 49356, //casted at end of phase 1, starts phase 2
- //flesh spells (phase 2)
+ SPELL_DECAY_FLESH = 49356, // casted at end of phase 1, starts phase 2
+ // Flesh Spells (phase 2)
SPELL_GIFT_OF_THARON_JA = 52509,
+ SPELL_CLEAR_GIFT_OF_THARON_JA = 53242,
SPELL_EYE_BEAM = 49544,
- H_SPELL_EYE_BEAM = 59965,
SPELL_LIGHTNING_BREATH = 49537,
- H_SPELL_LIGHTNING_BREATH = 59963,
SPELL_POISON_CLOUD = 49548,
- H_SPELL_POISON_CLOUD = 59969,
- SPELL_RETURN_FLESH = 53463, //Channeled spell ending phase two and returning to phase 1. This ability will stun the party for 6 seconds.
+ SPELL_RETURN_FLESH = 53463, // Channeled spell ending phase two and returning to phase 1. This ability will stun the party for 6 seconds.
SPELL_ACHIEVEMENT_CHECK = 61863,
+ SPELL_FLESH_VISUAL = 52582,
+ SPELL_DUMMY = 49551
+};
+
+enum Events
+{
+ EVENT_CURSE_OF_LIFE = 1,
+ EVENT_RAIN_OF_FIRE,
+ EVENT_SHADOW_VOLLEY,
+
+ EVENT_EYE_BEAM,
+ EVENT_LIGHTNING_BREATH,
+ EVENT_POISON_CLOUD,
+
+ EVENT_DECAY_FLESH,
+ EVENT_GOING_FLESH,
+ EVENT_RETURN_FLESH,
+ EVENT_GOING_SKELETAL
};
enum Yells
@@ -50,204 +69,178 @@ enum Yells
SAY_SKELETON = 3,
SAY_DEATH = 4
};
+
enum Models
{
- MODEL_FLESH = 27073,
- MODEL_SKELETON = 27511
-};
-enum CombatPhase
-{
- SKELETAL,
- GOING_FLESH,
- FLESH,
- GOING_SKELETAL
+ MODEL_FLESH = 27073
};
class boss_tharon_ja : public CreatureScript
{
-public:
- boss_tharon_ja() : CreatureScript("boss_tharon_ja") { }
+ public:
+ boss_tharon_ja() : CreatureScript("boss_tharon_ja") { }
- struct boss_tharon_jaAI : public ScriptedAI
- {
- boss_tharon_jaAI(Creature* creature) : ScriptedAI(creature)
+ struct boss_tharon_jaAI : public BossAI
{
- instance = creature->GetInstanceScript();
- }
-
- uint32 uiPhaseTimer;
- uint32 uiCurseOfLifeTimer;
- uint32 uiRainOfFireTimer;
- uint32 uiShadowVolleyTimer;
- uint32 uiEyeBeamTimer;
- uint32 uiLightningBreathTimer;
- uint32 uiPoisonCloudTimer;
+ boss_tharon_jaAI(Creature* creature) : BossAI(creature, DATA_THARON_JA) { }
- CombatPhase Phase;
-
- InstanceScript* instance;
-
- void Reset() OVERRIDE
- {
- uiPhaseTimer = 20*IN_MILLISECONDS;
- uiCurseOfLifeTimer = 1*IN_MILLISECONDS;
- uiRainOfFireTimer = urand(14*IN_MILLISECONDS, 18*IN_MILLISECONDS);
- uiShadowVolleyTimer = urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS);
- Phase = SKELETAL;
- me->SetDisplayId(me->GetNativeDisplayId());
- instance->SetBossState(DATA_THARON_JA, NOT_STARTED);
- }
+ void Reset() OVERRIDE
+ {
+ _Reset();
+ me->RestoreDisplayId();
+ }
- void EnterCombat(Unit* /*who*/) OVERRIDE
- {
- Talk(SAY_AGGRO);
- instance->SetBossState(DATA_THARON_JA, IN_PROGRESS);
- }
+ void EnterCombat(Unit* /*who*/) OVERRIDE
+ {
+ Talk(SAY_AGGRO);
+ _EnterCombat();
- void UpdateAI(uint32 diff) OVERRIDE
- {
- //Return since we have no target
- if (!UpdateVictim())
- return;
+ events.ScheduleEvent(EVENT_DECAY_FLESH, 20000);
+ events.ScheduleEvent(EVENT_CURSE_OF_LIFE, 1000);
+ events.ScheduleEvent(EVENT_RAIN_OF_FIRE, urand(14000, 18000));
+ events.ScheduleEvent(EVENT_SHADOW_VOLLEY, urand(8000, 10000));
+ }
- switch (Phase)
+ void KilledUnit(Unit* who) OVERRIDE
{
- case SKELETAL:
- if (uiCurseOfLifeTimer < diff)
- {
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
- DoCast(target, SPELL_CURSE_OF_LIFE);
- uiCurseOfLifeTimer = urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS);
- } else uiCurseOfLifeTimer -= diff;
+ if (who->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_KILL);
+ }
- if (uiShadowVolleyTimer < diff)
- {
- DoCastVictim(SPELL_SHADOW_VOLLEY);
- uiShadowVolleyTimer = urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS);
- } else uiShadowVolleyTimer -= diff;
+ void JustDied(Unit* /*killer*/) OVERRIDE
+ {
+ _JustDied();
- if (uiRainOfFireTimer < diff)
- {
- DoCastAOE(SPELL_RAIN_OF_FIRE);
- uiRainOfFireTimer = urand(14*IN_MILLISECONDS, 18*IN_MILLISECONDS);
- } else uiRainOfFireTimer -= diff;
+ Talk(SAY_DEATH);
+ DoCastAOE(SPELL_CLEAR_GIFT_OF_THARON_JA, true);
+ DoCastAOE(SPELL_ACHIEVEMENT_CHECK, true);
+ }
- if (uiPhaseTimer < diff)
- {
- DoCast(SPELL_DECAY_FLESH);
- Phase = GOING_FLESH;
- uiPhaseTimer = 6*IN_MILLISECONDS;
- } else uiPhaseTimer -= diff;
-
- DoMeleeAttackIfReady();
- break;
- case GOING_FLESH:
- if (uiPhaseTimer < diff)
- {
- Talk(SAY_FLESH);
- me->SetDisplayId(MODEL_FLESH);
-
- std::list<Unit*> playerList;
- SelectTargetList(playerList, 5, SELECT_TARGET_TOPAGGRO, 0, true);
- for (std::list<Unit*>::const_iterator itr = playerList.begin(); itr != playerList.end(); ++itr)
- {
- Unit* temp = (*itr);
- me->AddAura(SPELL_GIFT_OF_THARON_JA, temp);
- temp->SetDisplayId(MODEL_SKELETON);
- }
- uiPhaseTimer = 20*IN_MILLISECONDS;
- uiLightningBreathTimer = urand(3*IN_MILLISECONDS, 4*IN_MILLISECONDS);
- uiEyeBeamTimer = urand(4*IN_MILLISECONDS, 8*IN_MILLISECONDS);
- uiPoisonCloudTimer = urand(6*IN_MILLISECONDS, 7*IN_MILLISECONDS);
- Phase = FLESH;
- } else uiPhaseTimer -= diff;
- break;
- case FLESH:
- if (uiLightningBreathTimer < diff)
- {
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
- DoCast(target, SPELL_LIGHTNING_BREATH);
- uiLightningBreathTimer = urand(6*IN_MILLISECONDS, 7*IN_MILLISECONDS);
- } else uiLightningBreathTimer -= diff;
+ void UpdateAI(uint32 diff) OVERRIDE
+ {
+ if (!UpdateVictim())
+ return;
- if (uiEyeBeamTimer < diff)
- {
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
- DoCast(target, SPELL_EYE_BEAM);
- uiEyeBeamTimer = urand(4*IN_MILLISECONDS, 6*IN_MILLISECONDS);
- } else uiEyeBeamTimer -= diff;
+ events.Update(diff);
- if (uiPoisonCloudTimer < diff)
- {
- DoCastAOE(SPELL_POISON_CLOUD);
- uiPoisonCloudTimer = urand(10*IN_MILLISECONDS, 12*IN_MILLISECONDS);
- } else uiPoisonCloudTimer -= diff;
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- if (uiPhaseTimer < diff)
- {
- DoCast(SPELL_RETURN_FLESH);
- Phase = GOING_SKELETAL;
- uiPhaseTimer = 6*IN_MILLISECONDS;
- } else uiPhaseTimer -= diff;
- DoMeleeAttackIfReady();
- break;
- case GOING_SKELETAL:
- if (uiPhaseTimer < diff)
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
{
- Talk(SAY_SKELETON);
- me->DeMorph();
- Phase = SKELETAL;
- uiPhaseTimer = 20*IN_MILLISECONDS;
- uiCurseOfLifeTimer = 1*IN_MILLISECONDS;
- uiRainOfFireTimer = urand(14*IN_MILLISECONDS, 18*IN_MILLISECONDS);
- uiShadowVolleyTimer = urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS);
-
- std::list<Unit*> playerList;
- SelectTargetList(playerList, 5, SELECT_TARGET_TOPAGGRO, 0, true);
- for (std::list<Unit*>::const_iterator itr = playerList.begin(); itr != playerList.end(); ++itr)
- {
- Unit* temp = (*itr);
- if (temp->HasAura(SPELL_GIFT_OF_THARON_JA))
- temp->RemoveAura(SPELL_GIFT_OF_THARON_JA);
- temp->DeMorph();
- }
- } else uiPhaseTimer -= diff;
- break;
+ case EVENT_CURSE_OF_LIFE:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_CURSE_OF_LIFE);
+ events.ScheduleEvent(EVENT_CURSE_OF_LIFE, urand(10000, 15000));
+ return;
+ case EVENT_SHADOW_VOLLEY:
+ DoCastVictim(SPELL_SHADOW_VOLLEY);
+ events.ScheduleEvent(EVENT_SHADOW_VOLLEY, urand(8000, 10000));
+ return;
+ case EVENT_RAIN_OF_FIRE:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_RAIN_OF_FIRE);
+ events.ScheduleEvent(EVENT_RAIN_OF_FIRE, urand(14000, 18000));
+ return;
+ case EVENT_LIGHTNING_BREATH:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_LIGHTNING_BREATH);
+ events.ScheduleEvent(EVENT_LIGHTNING_BREATH, urand(6000, 7000));
+ return;
+ case EVENT_EYE_BEAM:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_EYE_BEAM);
+ events.ScheduleEvent(EVENT_EYE_BEAM, urand(4000, 6000));
+ return;
+ case EVENT_POISON_CLOUD:
+ DoCastAOE(SPELL_POISON_CLOUD);
+ events.ScheduleEvent(EVENT_POISON_CLOUD, urand(10000, 12000));
+ return;
+ case EVENT_DECAY_FLESH:
+ DoCastAOE(SPELL_DECAY_FLESH);
+ events.ScheduleEvent(EVENT_GOING_FLESH, 6000);
+ return;
+ case EVENT_GOING_FLESH:
+ Talk(SAY_FLESH);
+ me->SetDisplayId(MODEL_FLESH);
+ DoCastAOE(SPELL_GIFT_OF_THARON_JA, true);
+ DoCast(me, SPELL_FLESH_VISUAL, true);
+ DoCast(me, SPELL_DUMMY, true);
+
+ events.Reset();
+ events.ScheduleEvent(EVENT_RETURN_FLESH, 20000);
+ events.ScheduleEvent(EVENT_LIGHTNING_BREATH, urand(3000, 4000));
+ events.ScheduleEvent(EVENT_EYE_BEAM, urand(4000, 8000));
+ events.ScheduleEvent(EVENT_POISON_CLOUD, urand(6000, 7000));
+ break;
+ case EVENT_RETURN_FLESH:
+ DoCastAOE(SPELL_RETURN_FLESH);
+ events.ScheduleEvent(EVENT_GOING_SKELETAL, 6000);
+ return;
+ case EVENT_GOING_SKELETAL:
+ Talk(SAY_SKELETON);
+ me->RestoreDisplayId();
+ DoCastAOE(SPELL_CLEAR_GIFT_OF_THARON_JA, true);
+
+ events.Reset();
+ events.ScheduleEvent(EVENT_DECAY_FLESH, 20000);
+ events.ScheduleEvent(EVENT_CURSE_OF_LIFE, 1000);
+ events.ScheduleEvent(EVENT_RAIN_OF_FIRE, urand(14000, 18000));
+ events.ScheduleEvent(EVENT_SHADOW_VOLLEY, urand(8000, 10000));
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
}
- }
+ };
- void KilledUnit(Unit* /*victim*/) OVERRIDE
+ CreatureAI* GetAI(Creature* creature) const OVERRIDE
{
- Talk(SAY_KILL);
+ return GetDrakTharonKeepAI<boss_tharon_jaAI>(creature);
}
+};
+
+class spell_tharon_ja_clear_gift_of_tharon_ja : public SpellScriptLoader
+{
+ public:
+ spell_tharon_ja_clear_gift_of_tharon_ja() : SpellScriptLoader("spell_tharon_ja_clear_gift_of_tharon_ja") { }
- void JustDied(Unit* /*killer*/) OVERRIDE
+ class spell_tharon_ja_clear_gift_of_tharon_ja_SpellScript : public SpellScript
{
- Talk(SAY_DEATH);
+ PrepareSpellScript(spell_tharon_ja_clear_gift_of_tharon_ja_SpellScript);
- if (instance)
+ bool Validate(SpellInfo const* /*spellInfo*/) OVERRIDE
{
- // clean morph on players
- Map::PlayerList const &PlayerList = instance->instance->GetPlayers();
-
- for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
- if (Player* player = i->GetSource())
- player->DeMorph();
+ if (!sSpellMgr->GetSpellInfo(SPELL_GIFT_OF_THARON_JA))
+ return false;
+ return true;
+ }
- DoCast(me, SPELL_ACHIEVEMENT_CHECK);
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* target = GetHitUnit())
+ target->RemoveAura(SPELL_GIFT_OF_THARON_JA);
+ }
- instance->SetBossState(DATA_THARON_JA, DONE);
+ void Register() OVERRIDE
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_tharon_ja_clear_gift_of_tharon_ja_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
- }
- };
+ };
- CreatureAI* GetAI(Creature* creature) const OVERRIDE
- {
- return GetDrakTharonKeepAI<boss_tharon_jaAI>(creature);
- }
+ SpellScript* GetSpellScript() const OVERRIDE
+ {
+ return new spell_tharon_ja_clear_gift_of_tharon_ja_SpellScript();
+ }
};
void AddSC_boss_tharon_ja()
{
- new boss_tharon_ja;
+ new boss_tharon_ja();
+ new spell_tharon_ja_clear_gift_of_tharon_ja();
}
diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp
index 78dcaaa669c..d022eef65b9 100644
--- a/src/server/scripts/Spells/spell_warrior.cpp
+++ b/src/server/scripts/Spells/spell_warrior.cpp
@@ -578,9 +578,8 @@ class spell_warr_slam : public SpellScriptLoader
void HandleDummy(SpellEffIndex /*effIndex*/)
{
- int32 bp0 = GetEffectValue();
if (GetHitUnit())
- GetCaster()->CastCustomSpell(GetHitUnit(), SPELL_WARRIOR_SLAM, &bp0, NULL, NULL, true, 0);
+ GetCaster()->CastCustomSpell(SPELL_WARRIOR_SLAM, SPELLVALUE_BASE_POINT0, GetEffectValue(), GetHitUnit(), TRIGGERED_FULL_MASK);
}
void Register() OVERRIDE