本文整理汇总了C++中Spell类的典型用法代码示例。如果您正苦于以下问题:C++ Spell类的具体用法?C++ Spell怎么用?C++ Spell使用的例子?那么, 这里精选的类代码示例或许可以为您提供帮助。
在下文中一共展示了Spell类的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: uint32
void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
{
sLog.outDetail("WORLD: CMSG_PET_CAST_SPELL");
uint64 guid;
uint32 spellid;
recvPacket >> guid >> spellid;
// This opcode is also sent from charmed and possessed units (players and creatures)
if (!_player->GetPet() && !_player->GetCharm())
return;
Unit* caster = ObjectAccessor::GetUnit(*_player, guid);
if (!caster || (caster != _player->GetPet() && caster != _player->GetCharm()))
{
sLog.outError("HandlePetCastSpellOpcode: Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)),GetPlayer()->GetName());
return;
}
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid);
if (!spellInfo)
{
sLog.outError("WORLD: unknown PET spell id %i", spellid);
return;
}
// do not cast not learned spells
if (!caster->HasSpell(spellid) || IsPassiveSpell(spellid))
return;
if (spellInfo->StartRecoveryCategory > 0) //Check if spell is affected by GCD
if (caster->GetTypeId() == TYPEID_UNIT && caster->ToCreature()->GetGlobalCooldown() > 0)
{
caster->SendPetCastFail(spellid, SPELL_FAILED_NOT_READY);
return;
}
SpellCastTargets targets;
recvPacket >> targets.ReadForCaster(caster);
caster->clearUnitState(UNIT_STAT_FOLLOW);
Spell *spell = new Spell(caster, spellInfo, spellid == 33395); // water elemental can cast freeze as triggered
spell->m_targets = targets;
int16 result = spell->PetCanCast(NULL);
if (result == -1)
{
if (caster->GetTypeId() == TYPEID_UNIT)
{
Creature* pet = caster->ToCreature();
pet->AddCreatureSpellCooldown(spellid);
if (pet->isPet())
{
Pet* p = (Pet*)pet;
p->CheckLearning(spellid);
// 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);
else
pet->SendPetAIReaction(guid);
}
}
spell->prepare(&(spell->m_targets));
}
else
{
caster->SendPetCastFail(spellid, result);
if (caster->GetTypeId() == TYPEID_PLAYER)
{
if (!caster->ToPlayer()->HasSpellCooldown(spellid))
caster->SendPetClearCooldown(spellid);
}
else
{
if (!caster->ToCreature()->HasSpellCooldown(spellid))
caster->SendPetClearCooldown(spellid);
}
spell->finish(false);
delete spell;
}
}
示例2: CHECK_PACKET_SIZE
void WorldSession::HandlePetAction( WorldPacket & recv_data )
{
CHECK_PACKET_SIZE(recv_data, 8+2+2+8);
uint64 guid1;
uint32 data;
uint64 guid2;
recv_data >> guid1; //pet guid
recv_data >> data;
recv_data >> guid2; //tag guid
uint32 spellid = UNIT_ACTION_BUTTON_ACTION(data);
uint8 flag = UNIT_ACTION_BUTTON_TYPE(data); //delete = 0x07 CastSpell = C1
// used also for charmed creature
Unit* pet= ObjectAccessor::GetUnit(*_player, guid1);
sLog.outDetail("HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.", uint32(GUID_LOPART(guid1)), uint32(flag), spellid, uint32(GUID_LOPART(guid2)) );
if(!pet)
{
sLog.outError( "Pet %u not exist.", uint32(GUID_LOPART(guid1)) );
return;
}
if(pet != GetPlayer()->GetPet() && pet != GetPlayer()->GetCharm())
{
sLog.outError("HandlePetAction.Pet %u isn't pet of player %s.", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName() );
return;
}
if(!pet->isAlive())
return;
if(pet->GetTypeId() == TYPEID_PLAYER && !(flag == ACT_COMMAND && spellid == COMMAND_ATTACK))
return;
CharmInfo *charmInfo = pet->GetCharmInfo();
if(!charmInfo)
{
sLog.outError("WorldSession::HandlePetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId());
return;
}
switch(flag)
{
case ACT_COMMAND: //0x07
switch(spellid)
{
case COMMAND_STAY: //flat=1792 //STAY
pet->StopMoving();
pet->GetMotionMaster()->Clear();
pet->GetMotionMaster()->MoveIdle();
charmInfo->SetCommandState( COMMAND_STAY );
break;
case COMMAND_FOLLOW: //spellid=1792 //FOLLOW
pet->AttackStop();
pet->GetMotionMaster()->MoveFollow(_player,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE);
charmInfo->SetCommandState( COMMAND_FOLLOW );
break;
case COMMAND_ATTACK: //spellid=1792 //ATTACK
{
const uint64& selguid = _player->GetSelection();
Unit *TargetUnit = ObjectAccessor::GetUnit(*_player, selguid);
if(!TargetUnit)
return;
// not let attack friendly units.
if(GetPlayer()->IsFriendlyTo(TargetUnit))
return;
// Not let attack through obstructions
if(!pet->IsWithinLOSInMap(TargetUnit))
return;
// This is true if pet has no target or has target but targets differs.
if(pet->getVictim() != TargetUnit)
{
if (pet->getVictim())
pet->AttackStop();
if(pet->GetTypeId() != TYPEID_PLAYER)
{
pet->GetMotionMaster()->Clear();
if (((Creature*)pet)->AI())
((Creature*)pet)->AI()->AttackStart(TargetUnit);
//10% chance to play special pet attack talk, else growl
if(((Creature*)pet)->isPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != TargetUnit && urand(0, 100) < 10)
pet->SendPetTalk((uint32)PET_TALK_ATTACK);
else
{
// 90% chance for pet and 100% chance for charmed creature
pet->SendPetAIReaction(guid1);
}
}
else // charmed player
{
pet->Attack(TargetUnit,true);
pet->SendPetAIReaction(guid1);
}
}
break;
//.........这里部分代码省略.........
示例3: object
void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid, uint16 flag, uint64 guid2)
{
CharmInfo *charmInfo = pet->GetCharmInfo();
if (!charmInfo)
{
sLog->outError("WorldSession::HandlePetAction(petGuid: " UI64FMTD ", tagGuid: " UI64FMTD ", spellId: %u, flag: %u): object (entry: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!",
guid1, guid2, spellid, flag, pet->GetGUIDLow(), pet->GetTypeId());
return;
}
switch(flag)
{
case ACT_COMMAND: //0x07
switch(spellid)
{
case COMMAND_STAY: //flat=1792 //STAY
pet->AttackStop();
pet->InterruptNonMeleeSpells(false);
pet->GetMotionMaster()->MoveIdle();
charmInfo->SetCommandState(COMMAND_STAY);
charmInfo->SetIsCommandAttack(false);
charmInfo->SetIsAtStay(true);
charmInfo->SetIsFollowing(false);
charmInfo->SetIsReturning(false);
charmInfo->SaveStayPosition();
break;
case COMMAND_FOLLOW: //spellid=1792 //FOLLOW
pet->AttackStop();
pet->InterruptNonMeleeSpells(false);
pet->GetMotionMaster()->MoveFollow(_player, PET_FOLLOW_DIST, pet->GetFollowAngle());
charmInfo->SetCommandState(COMMAND_FOLLOW);
charmInfo->SetIsCommandAttack(false);
charmInfo->SetIsAtStay(false);
charmInfo->SetIsReturning(true);
charmInfo->SetIsFollowing(false);
break;
case COMMAND_ATTACK: //spellid=1792 //ATTACK
{
// Can't attack if owner is pacified
if (_player->HasAuraType(SPELL_AURA_MOD_PACIFY))
{
//pet->SendPetCastFail(spellid, SPELL_FAILED_PACIFIED);
//TODO: Send proper error message to client
return;
}
// only place where pet can be player
Unit *TargetUnit = ObjectAccessor::GetUnit(*_player, guid2);
if (!TargetUnit)
return;
if (Unit *owner = pet->GetOwner())
if (!owner->canAttack(TargetUnit))
return;
// Not let attack through obstructions
if (sWorld->getBoolConfig(CONFIG_PET_LOS))
{
if (!pet->IsWithinLOSInMap(TargetUnit))
return;
}
pet->ClearUnitState(UNIT_STAT_FOLLOW);
// This is true if pet has no target or has target but targets differs.
if (pet->getVictim() != TargetUnit || (pet->getVictim() == TargetUnit && !pet->GetCharmInfo()->IsCommandAttack()))
{
if (pet->getVictim())
pet->AttackStop();
if (pet->GetTypeId() != TYPEID_PLAYER && pet->ToCreature()->IsAIEnabled)
{
charmInfo->SetIsCommandAttack(true);
charmInfo->SetIsAtStay(false);
charmInfo->SetIsFollowing(false);
charmInfo->SetIsReturning(false);
pet->ToCreature()->AI()->AttackStart(TargetUnit);
//10% chance to play special pet attack talk, else growl
if (pet->ToCreature()->isPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != TargetUnit && urand(0, 100) < 10)
pet->SendPetTalk((uint32)PET_TALK_ATTACK);
else
{
// 90% chance for pet and 100% chance for charmed creature
pet->SendPetAIReaction(guid1);
}
}
else // charmed player
{
if (pet->getVictim() && pet->getVictim() != TargetUnit)
pet->AttackStop();
charmInfo->SetIsCommandAttack(true);
charmInfo->SetIsAtStay(false);
charmInfo->SetIsFollowing(false);
charmInfo->SetIsReturning(false);
pet->Attack(TargetUnit, true);
//.........这里部分代码省略.........
示例4: DEBUG_LOG
void WorldSession::HandleTrainerBuySpellOpcode( WorldPacket & recv_data )
{
uint64 guid;
uint32 spellId = 0;
recv_data >> guid >> spellId;
DEBUG_LOG( "WORLD: Received CMSG_TRAINER_BUY_SPELL NpcGUID=%u, learn spell id is: %u",uint32(GUID_LOPART(guid)), spellId );
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER);
if (!unit)
{
DEBUG_LOG( "WORLD: HandleTrainerBuySpellOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
return;
}
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
if(!unit->isCanTrainingOf(_player,true))
return;
// check present spell in trainer spell list
TrainerSpellData const* trainer_spells = unit->GetTrainerSpells();
if(!trainer_spells)
return;
// not found, cheat?
TrainerSpell const* trainer_spell = trainer_spells->Find(spellId);
if(!trainer_spell)
return;
// can't be learn, cheat? Or double learn with lags...
if(_player->GetTrainerSpellState(trainer_spell) != TRAINER_SPELL_GREEN)
return;
SpellEntry const *proto = sSpellStore.LookupEntry(trainer_spell->spell);
SpellEntry const *spellInfo = sSpellStore.LookupEntry(proto->EffectTriggerSpell[0]);
// apply reputation discount
uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(unit)));
// check money requirement
if(_player->GetMoney() < nSpellCost )
return;
_player->ModifyMoney( -int32(nSpellCost) );
WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12); // visual effect on trainer
data << uint64(guid);
data << uint32(0xB3); // index from SpellVisualKit.dbc
SendPacket(&data);
data.Initialize(SMSG_PLAY_SPELL_IMPACT, 12); // visual effect on player
data << _player->GetObjectGuid();
data << uint32(0x016A); // index from SpellVisualKit.dbc
SendPacket(&data);
// learn explicitly to prevent lost money at lags, learning spell will be only show spell animation
//[-ZERO] _player->learnSpell(trainer_spell->spell, false);
data.Initialize(SMSG_TRAINER_BUY_SUCCEEDED, 12);
data << uint64(guid);
data << uint32(spellId); // should be same as in packet from client
SendPacket(&data);
Spell *spell;
if(proto->SpellVisual == 222)
spell = new Spell(_player, proto, false);
else
spell = new Spell(unit, proto, false);
SpellCastTargets targets;
targets.setUnitTarget( _player );
spell->prepare(&targets);
}
示例5: UpdateAllies
void PetAI::UpdateAI(const uint32 diff)
{
if (!me->isAlive())
return;
if(me->GetIAmABot())
{
//don't do anything if eating or drinking, otherwise call UpdateAI
if(!me->HasAura(10256) && !me->HasAura(1137) && me->GetBotAI()) me->GetBotAI()->UpdateAI(diff);
}
Unit* owner = me->GetCharmerOrOwner();
if (m_updateAlliesTimer <= diff)
// UpdateAllies self set update timer
UpdateAllies();
else
m_updateAlliesTimer -= diff;
// me->getVictim() can't be used for check in case stop fighting, me->getVictim() clear at Unit death etc.
if (me->getVictim())
{
if (_needToStop())
{
sLog->outStaticDebug("Pet AI stopped attacking [guid=%u]", me->GetGUIDLow());
_stopAttack();
return;
}
targetHasCC = _CheckTargetCC(me->getVictim());
DoMeleeAttackIfReady();
}
else if (owner && me->GetCharmInfo()) //no victim
{
Unit *nextTarget = SelectNextTarget();
if (me->HasReactState(REACT_PASSIVE))
_stopAttack();
else if (nextTarget)
AttackStart(nextTarget);
else
HandleReturnMovement();
}
else if (owner && !me->HasUnitState(UNIT_STAT_FOLLOW)) // no charm info and no victim
me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle());
if (!me->GetCharmInfo())
return;
// Autocast (casted only in combat or persistent spells in any state)
if (!me->HasUnitState(UNIT_STAT_CASTING))
{
typedef std::vector<std::pair<Unit*, Spell*> > TargetSpellList;
TargetSpellList targetSpellStore;
for (uint8 i = 0; i < me->GetPetAutoSpellSize(); ++i)
{
uint32 spellID = me->GetPetAutoSpellOnPos(i);
if (!spellID)
continue;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID);
if (!spellInfo)
continue;
if (me->GetCharmInfo() && me->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo))
continue;
// ignore some combinations of combat state and combat/noncombat spells
if (!me->getVictim())
{
// ignore attacking spells, and allow only self/around spells
if (!IsPositiveSpell(spellInfo->Id))
continue;
// non combat spells allowed
// only pet spells have IsNonCombatSpell and not fit this reqs:
// Consume Shadows, Lesser Invisibility, so ignore checks for its
if (!IsNonCombatSpell(spellInfo))
{
// allow only spell without spell cost or with spell cost but not duration limit
int32 duration = GetSpellDuration(spellInfo);
if ((spellInfo->manaCost || spellInfo->ManaCostPercentage || spellInfo->manaPerSecond) && duration > 0)
continue;
// allow only spell without cooldown > duration
int32 cooldown = GetSpellRecoveryTime(spellInfo);
if (cooldown >= 0 && duration >= 0 && cooldown > duration)
continue;
}
}
else
{
// just ignore non-combat spells
if (IsNonCombatSpell(spellInfo))
continue;
}
Spell *spell = new Spell(me, spellInfo, false, 0);
//.........这里部分代码省略.........
示例6: UpdateAllies
void PetAI::UpdateAI(const uint32 diff)
{
if (!m_creature->isAlive() || !m_creature->GetCharmInfo())
return;
Unit* owner = m_creature->GetCharmerOrOwner();
if (m_updateAlliesTimer <= diff)
// UpdateAllies self set update timer
UpdateAllies();
else
m_updateAlliesTimer -= diff;
// First checking if we have some taunt on us
Unit* tauntTarget = NULL;
const Unit::AuraList& tauntAuras = m_creature->GetAurasByType(SPELL_AURA_MOD_TAUNT);
if (!tauntAuras.empty())
{
Unit* caster = NULL;
// Auras are pushed_back, last caster will be on the end
Unit::AuraList::const_iterator aura = tauntAuras.end();
while (aura != tauntAuras.begin())
{
--aura;
caster = (*aura)->GetCaster();
if (caster && caster->isTargetableForAttack())
{
tauntTarget = caster;
break;
}
}
if (tauntTarget)
DoAttack(tauntTarget, true);
}
if (m_creature->getVictim() && m_creature->getVictim()->isAlive())
{
if (_needToStop())
{
_stopAttack();
return;
}
if (hasMelee)
{
// Check before attacking to prevent pets from leaving stay position
bool attacked = false;
if (m_creature->GetCharmInfo()->HasCommandState(COMMAND_STAY))
{
if (m_creature->GetCharmInfo()->IsCommandAttack() || (m_creature->GetCharmInfo()->IsAtStay() && m_creature->CanReachWithMeleeAttack(m_creature->getVictim())))
attacked = DoMeleeAttackIfReady();
}
else
attacked = DoMeleeAttackIfReady();
if (attacked && owner)
if (Unit* v = m_creature->getVictim()) // Victim may have died between
owner->SetInCombatWith(v);
}
}
else
{
if (m_creature->HasReactState(REACT_AGGRESSIVE) || m_creature->GetCharmInfo()->IsAtStay())
{
// Every update we need to check targets only in certain cases
// Aggressive - Allow auto select if owner or pet don't have a target
// Stay - Only pick from pet or owner targets / attackers so targets won't run by
// while chasing our owner. Don't do auto select.
// All other cases (ie: defensive) - Targets are assigned by AttackedBy(), OwnerAttackedBy(), OwnerAttacked(), etc.
Unit* nextTarget = SelectNextTarget(m_creature->HasReactState(REACT_AGGRESSIVE));
if (nextTarget)
AttackStart(nextTarget);
else
HandleReturnMovement();
}
else
HandleReturnMovement();
}
// Autocast (casted only in combat or persistent spells in any state)
if (!m_creature->IsNonMeleeSpellCasted(false))
{
typedef std::vector<std::pair<Unit*, Spell*> > TargetSpellList;
TargetSpellList targetSpellStore;
for (uint8 i = 0; i < m_creature->GetPetAutoSpellSize(); ++i)
{
uint32 spellID = m_creature->GetPetAutoSpellOnPos(i);
if (!spellID)
continue;
SpellEntry const *spellInfo = sSpellMgr.GetSpellEntry(spellID);
if (!spellInfo)
continue;
if (m_creature->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo))
//.........这里部分代码省略.........
示例7: DEBUG_LOG
void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recv_data)
{
ObjectGuid guid;
uint32 spellId = 0;
recv_data >> guid >> spellId;
DEBUG_LOG("WORLD: Received opcode CMSG_TRAINER_BUY_SPELL Trainer: %s, learn spell id is: %u", guid.GetString().c_str(), spellId);
Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER);
if (!unit)
{
DEBUG_LOG("WORLD: HandleTrainerBuySpellOpcode - %s not found or you can't interact with him.", guid.GetString().c_str());
return;
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
{ GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); }
if (!unit->IsTrainerOf(_player, true))
{ return; }
// check present spell in trainer spell list
TrainerSpellData const* cSpells = unit->GetTrainerSpells();
TrainerSpellData const* tSpells = unit->GetTrainerTemplateSpells();
if (!cSpells && !tSpells)
{ return; }
// Try find spell in npc_trainer
TrainerSpell const* trainer_spell = cSpells ? cSpells->Find(spellId) : NULL;
// Not found, try find in npc_trainer_template
if (!trainer_spell && tSpells)
{ trainer_spell = tSpells->Find(spellId); }
// Not found anywhere, cheating?
if (!trainer_spell)
{ return; }
// can't be learn, cheat? Or double learn with lags...
uint32 reqLevel = 0;
if (!_player->IsSpellFitByClassAndRace(trainer_spell->spell, &reqLevel))
{ return; }
reqLevel = trainer_spell->isProvidedReqLevel ? trainer_spell->reqLevel : std::max(reqLevel, trainer_spell->reqLevel);
if (_player->GetTrainerSpellState(trainer_spell, reqLevel) != TRAINER_SPELL_GREEN)
{ return; }
SpellEntry const* proto = sSpellStore.LookupEntry(trainer_spell->spell);
SpellEntry const* spellInfo = sSpellStore.LookupEntry(proto->EffectTriggerSpell[0]);
// apply reputation discount
uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(unit)));
// check money requirement
if (_player->GetMoney() < nSpellCost)
{ return; }
_player->ModifyMoney(-int32(nSpellCost));
SendPlaySpellVisual(guid, 0xB3); // visual effect on trainer
WorldPacket data(SMSG_PLAY_SPELL_IMPACT, 8 + 4); // visual effect on player
data << _player->GetObjectGuid();
data << uint32(0x016A); // index from SpellVisualKit.dbc
SendPacket(&data);
// learn explicitly to prevent lost money at lags, learning spell will be only show spell animation
//[-ZERO] _player->learnSpell(trainer_spell->spell, false);
data.Initialize(SMSG_TRAINER_BUY_SUCCEEDED, 12);
data << ObjectGuid(guid);
data << uint32(spellId); // should be same as in packet from client
SendPacket(&data);
Spell* spell;
if (proto->SpellVisual == 222)
{ spell = new Spell(_player, proto, false); }
else
{ spell = new Spell(unit, proto, false); }
SpellCastTargets targets;
targets.setUnitTarget(_player);
spell->prepare(&targets);
}
示例8: DETAIL_LOG
void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
{
DETAIL_LOG("WORLD: CMSG_PET_CAST_SPELL");
ObjectGuid guid;
uint32 spellid;
uint8 cast_count;
uint8 unk_flags; // flags (if 0x02 - some additional data are received)
recvPacket >> guid >> cast_count >> spellid >> unk_flags;
DEBUG_LOG("WORLD: CMSG_PET_CAST_SPELL, %s, cast_count: %u, spellid %u, unk_flags %u", guid.GetString().c_str(), cast_count, spellid, unk_flags);
Creature* pet = _player->GetMap()->GetAnyTypeCreature(guid);
if (!pet || (guid != _player->GetPetGuid() && guid != _player->GetCharmGuid()))
{
sLog.outError("HandlePetCastSpellOpcode: %s isn't pet of %s .", guid.GetString().c_str(), _player->GetGuidStr().c_str());
return;
}
SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid);
if (!spellInfo)
{
sLog.outError("WORLD: unknown PET spell id %i", spellid);
return;
}
if (pet->GetCharmInfo() && pet->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo))
return;
Aura* triggeredByAura = pet->GetTriggeredByClientAura(spellid);
// do not cast not learned spells
if ((!triggeredByAura && !pet->HasSpell(spellid)) || IsPassiveSpell(spellInfo))
return;
SpellCastTargets targets;
recvPacket >> targets.ReadForCaster(pet);
pet->clearUnitState(UNIT_STAT_MOVING);
Spell* spell = new Spell(pet, spellInfo, triggeredByAura ? true : false, pet->GetObjectGuid(), triggeredByAura ? triggeredByAura->GetSpellProto() : nullptr);
spell->m_cast_count = cast_count; // probably pending spell cast
spell->m_targets = targets;
SpellCastResult result = triggeredByAura ? SPELL_CAST_OK : spell->CheckPetCast(nullptr);
if (result == SPELL_CAST_OK)
{
pet->AddCreatureSpellCooldown(spellid);
spell->SpellStart(&(spell->m_targets), triggeredByAura);
}
else
{
Unit* owner = pet->GetCharmerOrOwner();
if (owner && owner->GetTypeId() == TYPEID_PLAYER && !triggeredByAura)
Spell::SendCastResult((Player*)owner, spellInfo, 0, result, true);
if (!pet->HasSpellCooldown(spellid) && !triggeredByAura)
GetPlayer()->SendClearCooldown(spellid, pet);
spell->finish(false);
delete spell;
}
}
示例9: flags
void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
{
uint32 spellId, glyphIndex;
uint8 cast_count, cast_flags;
recvPacket >> cast_count;
recvPacket >> spellId >> glyphIndex;
recvPacket >> cast_flags; // flags (if 0x02 - some additional data are received)
// ignore for remote control state (for player case)
Unit* _mover = GetPlayer()->GetMover();
if (_mover != GetPlayer() && _mover->GetTypeId()==TYPEID_PLAYER)
{
recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet
return;
}
DEBUG_LOG("WORLD: got cast spell packet, spellId - %u, cast_count: %u, cast_flags %u, data length = " SIZEFMTD,
spellId, cast_count, cast_flags, recvPacket.size());
/* process anticheat check */
if (!GetPlayer()->GetAntiCheat()->DoAntiCheatCheck(CHECK_SPELL, spellId, CMSG_CAST_SPELL))
return;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
if(!spellInfo)
{
sLog.outError("WORLD: unknown spell id %u", spellId);
recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet
return;
}
// Players on vehicles may cast many simple spells (like knock) from self
Unit* mover = NULL;
if (spellInfo->HasAttribute(SPELL_ATTR_EX6_CASTABLE_ON_VEHICLE) && _mover->IsCharmerOrOwnerPlayerOrPlayerItself())
mover = _mover->GetCharmerOrOwnerPlayerOrPlayerItself();
else
mover = _mover;
// casting own spells on some vehicles
if (mover->IsVehicle() && mover->GetCharmerOrOwnerPlayerOrPlayerItself())
{
Player *plr = mover->GetCharmerOrOwnerPlayerOrPlayerItself();
if (mover->GetVehicleKit()->GetSeatInfo(plr) &&
((mover->GetVehicleKit()->GetSeatInfo(plr)->m_flags & SEAT_FLAG_CAN_ATTACK) ||
(mover->GetVehicleKit()->GetSeatInfo(plr)->m_flags & SEAT_FLAG_CAN_CAST) ))
mover = plr;
}
bool triggered = false;
SpellEntry const* triggeredBy = NULL;
Aura const* triggeredByAura = mover->GetTriggeredByClientAura(spellId);
if (triggeredByAura)
{
triggered = true;
triggeredBy = triggeredByAura->GetSpellProto();
cast_count = 0;
}
if (mover->GetTypeId()==TYPEID_PLAYER)
{
// not have spell in spellbook or spell passive and not casted by client
if (((((Player*)mover)->GetUInt16Value(PLAYER_FIELD_BYTES2, 0) == 0 &&
(!((Player*)mover)->HasActiveSpell(spellId) && !triggered))
|| IsPassiveSpell(spellInfo)) && spellId != 1843)
{
sLog.outError("WorldSession::HandleCastSpellOpcode: %s casts spell %u which he shouldn't have", mover->GetObjectGuid().GetString().c_str(), spellId);
//cheater? kick? ban?
recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet
return;
}
}
else
{
// not have spell in spellbook or spell passive and not casted by client
if ((!((Creature*)mover)->HasSpell(spellId) && !triggered)
|| IsPassiveSpell(spellInfo))
{
sLog.outError("WorldSession::HandleCastSpellOpcode: %s try casts spell %u which he shouldn't have", mover->GetObjectGuid().GetString().c_str(), spellId);
//cheater? kick? ban?
recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet
return;
}
}
Unit::AuraList swaps = mover->GetAurasByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS);
Unit::AuraList const& swaps2 = mover->GetAurasByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_2);
if (!swaps2.empty())
swaps.insert(swaps.end(), swaps2.begin(), swaps2.end());
for (Unit::AuraList::const_iterator itr = swaps.begin(); itr != swaps.end(); ++itr)
{
if ((*itr)->isAffectedOnSpell(spellInfo))
{
if (SpellEntry const* newInfo = sSpellStore.LookupEntry((*itr)->GetModifier()->m_amount))
{
spellInfo = newInfo;
spellId = newInfo->Id;
//.........这里部分代码省略.........
示例10: UNIT_ACTION_BUTTON_ACTION
void WorldSession::HandlePetAction(WorldPacket& recv_data)
{
ObjectGuid petGuid;
uint32 data;
ObjectGuid targetGuid;
recv_data >> petGuid;
recv_data >> data;
recv_data >> targetGuid;
uint32 spellid = UNIT_ACTION_BUTTON_ACTION(data);
uint8 flag = UNIT_ACTION_BUTTON_TYPE(data); // delete = 0x07 CastSpell = C1
DETAIL_LOG("HandlePetAction: %s flag is %u, spellid is %u, target %s.", petGuid.GetString().c_str(), uint32(flag), spellid, targetGuid.GetString().c_str());
// used also for charmed creature/player
Unit* petUnit = _player->GetMap()->GetUnit(petGuid);
if (!petUnit)
{
sLog.outError("HandlePetAction: %s not exist.", petGuid.GetString().c_str());
return;
}
if (_player->GetObjectGuid() != petUnit->GetCharmerOrOwnerGuid())
{
sLog.outError("HandlePetAction: %s isn't controlled by %s.", petGuid.GetString().c_str(), _player->GetGuidStr().c_str());
return;
}
if (!petUnit->isAlive())
return;
CharmInfo* charmInfo = petUnit->GetCharmInfo();
if (!charmInfo)
{
sLog.outError("WorldSession::HandlePetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", petUnit->GetGUIDLow(), petUnit->GetTypeId());
return;
}
Pet* pet = nullptr;
Creature* creature = nullptr;
if (petUnit->GetTypeId() == TYPEID_UNIT)
{
creature = static_cast<Creature*>(petUnit);
if (creature->IsPet())
{
pet = static_cast<Pet*>(petUnit);
if (pet->GetModeFlags() & PET_MODE_DISABLE_ACTIONS)
return;
}
}
if (!pet && petUnit->hasUnitState(UNIT_STAT_CONTROLLED))
{
// possess case
if (flag != uint8(ACT_COMMAND))
{
sLog.outError("PetHAndler: unknown PET flag Action %i and spellid %i. For possessed %s", uint32(flag), spellid, petUnit->GetGuidStr().c_str());
return;
}
switch (spellid)
{
case COMMAND_STAY:
case COMMAND_FOLLOW:
charmInfo->SetCommandState(CommandStates(spellid));
break;
case COMMAND_ATTACK:
{
Unit* targetUnit = targetGuid ? _player->GetMap()->GetUnit(targetGuid) : nullptr;
if (targetUnit && targetUnit != petUnit && targetUnit->isTargetableForAttack())
{
_player->SetInCombatState(true, targetUnit);
// This is true if pet has no target or has target but targets differs.
if (petUnit->getVictim() != targetUnit)
petUnit->Attack(targetUnit, true);
}
break;
}
case COMMAND_ABANDON:
_player->Uncharm();
break;
default:
sLog.outError("PetHandler: Not allowed action %i and spellid %i. Pet %s owner is %s", uint32(flag), spellid, petUnit->GetGuidStr().c_str(), _player->GetGuidStr().c_str());
break;
}
return;
}
// only real pet should go there
if (!pet)
{
sLog.outError("PetHandler: A not pet trying to do unknown Action %i and spellid %i. Pet %s owner is %s", uint32(flag), spellid, petUnit->GetGuidStr().c_str(), _player->GetGuidStr().c_str());
return;
}
//.........这里部分代码省略.........
示例11: flags
void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
{
uint32 spellId;
uint8 cast_count, unk_flags;
recvPacket >> cast_count;
recvPacket >> spellId;
recvPacket >> unk_flags; // flags (if 0x02 - some additional data are received)
// ignore for remote control state (for player case)
Unit* mover = _player->m_mover;
if(mover != _player && mover->GetTypeId()==TYPEID_PLAYER)
{
recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet
return;
}
// vehicle spells are handled by CMSG_PET_CAST_SPELL,
// but player is still able to cast own spells
if(_player->GetCharmGUID() && _player->GetCharmGUID() == _player->GetVehicleGUID())
mover = _player;
sLog.outDebug("WORLD: got cast spell packet, spellId - %u, cast_count: %u, unk_flags %u, data length = %i",
spellId, cast_count, unk_flags, (uint32)recvPacket.size());
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
if(!spellInfo)
{
sLog.outError("WORLD: unknown spell id %u", spellId);
recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet
return;
}
if(mover->GetTypeId()==TYPEID_PLAYER)
{
// not have spell in spellbook or spell passive and not casted by client
if (!((Player*)mover)->HasActiveSpell (spellId) || IsPassiveSpell(spellId) )
{
//cheater? kick? ban?
recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet
return;
}
}
else
{
// not have spell in spellbook or spell passive and not casted by client
if (!((Creature*)mover)->HasSpell(spellId) || IsPassiveSpell(spellId) )
{
//cheater? kick? ban?
recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet
return;
}
}
// client provided targets
SpellCastTargets targets;
if(!targets.read(&recvPacket,mover))
{
recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet
return;
}
// some spell cast packet including more data (for projectiles?)
if (unk_flags & 0x02)
{
recvPacket.read_skip<float>(); // unk1, coords?
recvPacket.read_skip<float>(); // unk1, coords?
recvPacket.read_skip<uint8>(); // >> 1
recvPacket.read_skip<uint32>(); // >> MSG_MOVE_STOP
MovementInfo movementInfo;
ReadMovementInfo(recvPacket, &movementInfo);
}
// auto-selection buff level base at target level (in spellInfo)
if(targets.getUnitTarget())
{
SpellEntry const *actualSpellInfo = spellmgr.SelectAuraRankForPlayerLevel(spellInfo,targets.getUnitTarget()->getLevel());
// if rank not found then function return NULL but in explicit cast case original spell can be casted and later failed with appropriate error message
if(actualSpellInfo)
spellInfo = actualSpellInfo;
}
Spell *spell = new Spell(mover, spellInfo, false);
spell->m_cast_count = cast_count; // set count of casts
spell->prepare(&targets);
}
示例12: Spell
void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
{
// TODO: add targets.read() check
Player* pUser = _player;
uint8 bagIndex, slot;
uint8 spell_count; // number of spells at item, not used
recvPacket >> bagIndex >> slot >> spell_count;
Item *pItem = pUser->GetItemByPos(bagIndex, slot);
if(!pItem)
{
pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
return;
}
sLog.outDetail("WORLD: CMSG_USE_ITEM packet, bagIndex: %u, slot: %u, spell_count: %u , Item: %u, data length = %i", bagIndex, slot, spell_count, pItem->GetEntry(), (uint32)recvPacket.size());
ItemPrototype const *proto = pItem->GetProto();
if(!proto)
{
pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL );
return;
}
// some item classes can be used only in equipped state
if(proto->InventoryType != INVTYPE_NON_EQUIP && !pItem->IsEquipped())
{
pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL );
return;
}
uint8 msg = pUser->CanUseItem(pItem);
if( msg != EQUIP_ERR_OK )
{
pUser->SendEquipError( msg, pItem, NULL );
return;
}
if (pUser->isInCombat())
{
for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(proto->Spells[i].SpellId))
{
if (IsNonCombatSpell(spellInfo))
{
pUser->SendEquipError(EQUIP_ERR_NOT_IN_COMBAT,pItem,NULL);
return;
}
}
}
}
// check also BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory)
if( pItem->GetProto()->Bonding == BIND_WHEN_USE || pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP || pItem->GetProto()->Bonding == BIND_QUEST_ITEM )
{
if (!pItem->IsSoulBound())
{
pItem->SetState(ITEM_CHANGED, pUser);
pItem->SetBinding( true );
}
}
SpellCastTargets targets;
if (!targets.read(&recvPacket, pUser))
return;
targets.Update(pUser);
if (!pItem->IsTargetValidForItemUse(targets.getUnitTarget()))
{
// free gray item after use fail
pUser->SendEquipError(EQUIP_ERR_NONE, pItem, NULL);
// search spell for spell error
uint32 spellid = 0;
for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
if( proto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE || proto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE)
{
spellid = proto->Spells[i].SpellId;
break;
}
}
// send spell error
if (SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid))
Spell::SendCastResult(_player,spellInfo,SPELL_FAILED_BAD_TARGETS);
return;
}
//Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state.
if(!Script->ItemUse(pUser,pItem,targets))
{
// no script or script not process request by self
// special learning case
if(pItem->GetProto()->Spells[0].SpellId==SPELL_ID_GENERIC_LEARN)
{
//.........这里部分代码省略.........
示例13: UpdateAllies
void PetAI::UpdateAI(uint32 diff)
{
if (!me->IsAlive() || !me->GetCharmInfo())
return;
Unit* owner = me->GetCharmerOrOwner();
if (_updateAlliesTimer <= diff)
// UpdateAllies self set update timer
UpdateAllies();
else
_updateAlliesTimer -= diff;
if (me->GetVictim() && me->EnsureVictim()->IsAlive())
{
// is only necessary to stop casting, the pet must not exit combat
if (!me->GetCurrentSpell(CURRENT_CHANNELED_SPELL) && // ignore channeled spells (Pin, Seduction)
me->EnsureVictim()->HasBreakableByDamageCrowdControlAura(me))
{
me->InterruptNonMeleeSpells(false);
return;
}
if (NeedToStop())
{
TC_LOG_TRACE("scripts.ai.petai", "PetAI::UpdateAI: AI stopped attacking %s", me->GetGUID().ToString().c_str());
StopAttack();
return;
}
// Check before attacking to prevent pets from leaving stay position
if (me->GetCharmInfo()->HasCommandState(COMMAND_STAY))
{
if (me->GetCharmInfo()->IsCommandAttack() || (me->GetCharmInfo()->IsAtStay() && me->IsWithinMeleeRange(me->GetVictim())))
DoMeleeAttackIfReady();
}
else
DoMeleeAttackIfReady();
}
else
{
if (me->HasReactState(REACT_AGGRESSIVE) || me->GetCharmInfo()->IsAtStay())
{
// Every update we need to check targets only in certain cases
// Aggressive - Allow auto select if owner or pet don't have a target
// Stay - Only pick from pet or owner targets / attackers so targets won't run by
// while chasing our owner. Don't do auto select.
// All other cases (ie: defensive) - Targets are assigned by DamageTaken(), OwnerAttackedBy(), OwnerAttacked(), etc.
Unit* nextTarget = SelectNextTarget(me->HasReactState(REACT_AGGRESSIVE));
if (nextTarget)
AttackStart(nextTarget);
else
HandleReturnMovement();
}
else
HandleReturnMovement();
}
// Autocast (cast only in combat or persistent spells in any state)
if (!me->HasUnitState(UNIT_STATE_CASTING))
{
TargetSpellList targetSpellStore;
for (uint8 i = 0; i < me->GetPetAutoSpellSize(); ++i)
{
uint32 spellID = me->GetPetAutoSpellOnPos(i);
if (!spellID)
continue;
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID);
if (!spellInfo)
continue;
if (me->GetSpellHistory()->HasGlobalCooldown(spellInfo))
continue;
// check spell cooldown
if (!me->GetSpellHistory()->IsReady(spellInfo))
continue;
if (spellInfo->IsPositive())
{
if (spellInfo->CanBeUsedInCombat())
{
// Check if we're in combat or commanded to attack
if (!me->IsInCombat() && !me->GetCharmInfo()->IsCommandAttack())
continue;
}
Spell* spell = new Spell(me, spellInfo, TRIGGERED_NONE);
bool spellUsed = false;
// Some spells can target enemy or friendly (DK Ghoul's Leap)
// Check for enemy first (pet then owner)
Unit* target = me->getAttackerForHelper();
if (!target && owner)
target = owner->getAttackerForHelper();
if (target)
//.........这里部分代码省略.........
示例14: UpdateAllies
void PetAI::UpdateAI(const uint32 diff)
{
if (!me->isAlive() || !me->GetCharmInfo())
return;
Unit* owner = me->GetCharmerOrOwner();
if (m_updateAlliesTimer <= diff)
// UpdateAllies self set update timer
UpdateAllies();
else
m_updateAlliesTimer -= diff;
if (me->getVictim() && me->getVictim()->isAlive())
{
// is only necessary to stop casting, the pet must not exit combat
if (me->getVictim()->HasBreakableByDamageCrowdControlAura(me))
{
me->InterruptNonMeleeSpells(false);
return;
}
if (_needToStop())
{
sLog->outDebug(LOG_FILTER_GENERAL, "Pet AI stopped attacking [guid=%u]", me->GetGUIDLow());
_stopAttack();
return;
}
// Check before attacking to prevent pets from leaving stay position
if (me->GetCharmInfo()->HasCommandState(COMMAND_STAY))
{
if (me->GetCharmInfo()->IsCommandAttack() || (me->GetCharmInfo()->IsAtStay() && me->IsWithinMeleeRange(me->getVictim())))
DoMeleeAttackIfReady();
}
else
DoMeleeAttackIfReady();
}
else
{
if (me->HasReactState(REACT_AGGRESSIVE) || me->GetCharmInfo()->IsAtStay())
{
// Every update we need to check targets only in certain cases
// Aggressive - Allow auto select if owner or pet don't have a target
// Stay - Only pick from pet or owner targets / attackers so targets won't run by
// while chasing our owner. Don't do auto select.
// All other cases (ie: defensive) - Targets are assigned by AttackedBy(), OwnerAttackedBy(), OwnerAttacked(), etc.
Unit* nextTarget = SelectNextTarget(me->HasReactState(REACT_AGGRESSIVE));
if (nextTarget)
AttackStart(nextTarget);
else
HandleReturnMovement();
}
else
HandleReturnMovement();
}
// Autocast (casted only in combat or persistent spells in any state)
if (!me->HasUnitState(UNIT_STATE_CASTING))
{
typedef std::vector<std::pair<Unit*, Spell*> > TargetSpellList;
TargetSpellList targetSpellStore;
for (uint8 i = 0; i < me->GetPetAutoSpellSize(); ++i)
{
uint32 spellID = me->GetPetAutoSpellOnPos(i);
if (!spellID)
continue;
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID);
if (!spellInfo)
continue;
if (me->GetCharmInfo() && me->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo))
continue;
if (spellInfo->IsPositive())
{
if (spellInfo->CanBeUsedInCombat())
{
// check spell cooldown
if (me->HasSpellCooldown(spellInfo->Id))
continue;
// Check if we're in combat or commanded to attack
if (!me->isInCombat() && !me->GetCharmInfo()->IsCommandAttack())
continue;
}
Spell* spell = new Spell(me, spellInfo, TRIGGERED_NONE, 0);
bool spellUsed = false;
// Some spells can target enemy or friendly (DK Ghoul's Leap)
// Check for enemy first (pet then owner)
Unit* target = me->getAttackerForHelper();
if (!target && owner)
target = owner->getAttackerForHelper();
//.........这里部分代码省略.........
示例15: UpdateAllies
void PetAI::UpdateAI(const uint32 diff)
{
if (!me->IsAlive())
return;
Unit* owner = me->GetCharmerOrOwner();
if (m_updateAlliesTimer <= diff)
// UpdateAllies self set update timer
UpdateAllies();
else
m_updateAlliesTimer -= diff;
// me->GetVictim() can't be used for check in case stop fighting, me->GetVictim() clear at Unit death etc.
if (me->GetVictim())
{
// is only necessary to stop casting, the pet must not exit combat
if (me->GetVictim()->HasCrowdControlAura(me))
{
me->InterruptNonMeleeSpells(false);
return;
}
if (_needToStop())
{
TC_LOG_DEBUG("misc", "Pet AI stopped attacking [guid=%u]", me->GetGUIDLow());
_stopAttack();
return;
}
if (owner && !owner->IsInCombat())
owner->SetInCombatWith(me->GetVictim());
DoMeleeAttackIfReady();
}
else if (owner && me->GetCharmInfo()) //no victim
{
// Only aggressive pets do target search every update.
// Defensive pets do target search only in these cases:
// * Owner attacks something - handled by OwnerAttacked()
// * Owner receives damage - handled by OwnerDamagedBy()
// * Pet is in combat and current target dies - handled by KilledUnit()
if (me->HasReactState(REACT_AGGRESSIVE))
{
Unit* nextTarget = SelectNextTarget();
if (nextTarget)
AttackStart(nextTarget);
else
HandleReturnMovement();
}
else
HandleReturnMovement();
}
else if (owner && !me->HasUnitState(UNIT_STATE_FOLLOW)) // no charm info and no victim
me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle());
if (!me->GetCharmInfo())
return;
// Autocast (casted only in combat or persistent spells in any state)
if (!me->HasUnitState(UNIT_STATE_CASTING))
{
typedef std::vector<std::pair<Unit*, Spell*> > TargetSpellList;
TargetSpellList targetSpellStore;
for (uint8 i = 0; i < me->GetPetAutoSpellSize(); ++i)
{
uint32 spellID = me->GetPetAutoSpellOnPos(i);
if (!spellID)
continue;
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID);
if (!spellInfo)
continue;
if (me->GetCharmInfo() && me->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(me, spellInfo))
continue;
if (spellInfo->IsPositive())
{
if (spellInfo->CanBeUsedInCombat())
{
// check spell cooldown
if (me->HasSpellCooldown(spellInfo->Id))
continue;
// Check if we're in combat or commanded to attack
if (!me->IsInCombat() && !me->GetCharmInfo()->IsCommandAttack())
continue;
}
Spell* spell = new Spell(me, spellInfo, TRIGGERED_NONE, 0);
bool spellUsed = false;
spell->LoadScripts();
// Some spells can target enemy or friendly (DK Ghoul's Leap)
// Check for enemy first (pet then owner)
Unit* target = me->getAttackerForHelper();
if (!target && owner)
//.........这里部分代码省略.........