Core/Spells:
- corrected structure of SMSG_PET_CAST_FAILED (fixes highlighted action buttons) - simplified spell focus check
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -14353,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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -32,9 +32,6 @@
|
||||
#include "Group.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "Player.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "CellImpl.h"
|
||||
|
||||
void WorldSession::HandleDismissCritter(WorldPacket& recvData)
|
||||
{
|
||||
@@ -298,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)
|
||||
@@ -381,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);
|
||||
@@ -774,34 +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;
|
||||
}
|
||||
|
||||
// check spell focus object
|
||||
if (spellInfo->RequiresSpellFocus && caster->IsVehicle())
|
||||
{
|
||||
CellCoord p(Trinity::ComputeCellCoord(caster->GetPositionX(), caster->GetPositionY()));
|
||||
Cell cell(p);
|
||||
|
||||
GameObject* ok = NULL;
|
||||
Trinity::GameObjectFocusCheck goCheck(caster, spellInfo->RequiresSpellFocus);
|
||||
Trinity::GameObjectSearcher<Trinity::GameObjectFocusCheck> checker(caster, ok, goCheck);
|
||||
|
||||
TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectFocusCheck>, GridTypeMapContainer > objectChecker(checker);
|
||||
Map& map = *caster->GetMap();
|
||||
cell.Visit(p, objectChecker, map, *caster, caster->GetVisibilityRange());
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
caster->SendPetCastFail(spellId, SPELL_FAILED_REQUIRES_SPELL_FOCUS);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// do not cast not learned spells
|
||||
if (!caster->HasSpell(spellId) || spellInfo->IsPassive())
|
||||
return;
|
||||
@@ -816,26 +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);
|
||||
}
|
||||
@@ -845,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))
|
||||
|
||||
@@ -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*/)
|
||||
{
|
||||
//==========================================================================================
|
||||
@@ -3755,27 +3764,9 @@ void Spell::finish(bool ok)
|
||||
m_caster->AttackStop();
|
||||
}
|
||||
|
||||
void Spell::SendCastResult(SpellCastResult result)
|
||||
void Spell::WriteCastResultInfo(WorldPacket& data, Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError)
|
||||
{
|
||||
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*/)
|
||||
{
|
||||
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 +3867,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 +5015,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 +5627,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 +5994,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))
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user