void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) { Player* p_User = GetPlayer(); Log::getSingleton( ).outDetail("WORLD: got use Item packet, data length = %i\n",recvPacket.size()); uint8 tmp1,slot,tmp3; uint32 spellId; recvPacket >> tmp1 >> slot >> tmp3; Item* tmpItem = new Item; tmpItem = p_User->GetItemBySlot(slot); ItemPrototype *itemProto = tmpItem->GetProto(); spellId = itemProto->SpellId[0]; // check for spell id SpellEntry *spellInfo = sSpellStore.LookupEntry( spellId ); if(!spellInfo) { Log::getSingleton( ).outError("WORLD: unknown spell id %i\n", spellId); return; } Spell *spell = new Spell(GetPlayer(), spellInfo,false, 0); WPAssert(spell); SpellCastTargets targets; targets.read(&recvPacket,GetPlayer()->GetGUID()); spell->m_CastItem = tmpItem; spell->prepare(&targets); }
void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) { uint32 spellId; recvPacket >> spellId; sLog.outDetail("WORLD: got cast spell packet, spellId - %i, data length = %i", spellId, recvPacket.size()); SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId ); if(!spellInfo) { sLog.outError("WORLD: unknown spell id %i\n", spellId); return; } if ( !_player->HasSpell (spellId) ) { //cheater? kick? ban? return; } Spell *spell ; spell = new Spell(_player, spellInfo, false, 0); SpellCastTargets targets; targets.read(&recvPacket,_player); spell->prepare(&targets); }
void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) { uint32 spellId; recvPacket >> spellId; Log::getSingleton( ).outDetail("WORLD: got cast spell packet, spellId - %i, data length = %i\n", spellId, recvPacket.size()); // check for spell id SpellEntry *spellInfo = sSpellStore.LookupEntry(spellId ); if(!spellInfo) { Log::getSingleton( ).outError("WORLD: unknown spell id %i\n", spellId); return; } Spell *spell = new Spell(GetPlayer(), spellInfo, false, 0); WPAssert(spell); SpellCastTargets targets; targets.read(&recvPacket,GetPlayer()->GetGUID()); spell->prepare(&targets); }
void WorldSession::HandleAddDynamicTargetOpcode(WorldPacket & recvPacket) { DEBUG_LOG( "WORLD"," got CMSG_PET_CAST_SPELL." ); uint64 guid; uint8 counter; uint32 spellid; uint8 flags; UnitPointer caster; SpellCastTargets targets; SpellEntry *sp; SpellPointer pSpell; list<AI_Spell*>::iterator itr; recvPacket >> guid >> counter >> spellid >> flags; sp = dbcSpell.LookupEntry(spellid); // Summoned Elemental's Freeze if (spellid == 33395) { caster = _player->m_Summon; if( caster && TO_PET(caster)->GetAISpellForSpellId(spellid) == NULL ) return; } else { caster = _player->m_CurrentCharm; if( caster != NULL ) { for(itr = caster->GetAIInterface()->m_spells.begin(); itr != caster->GetAIInterface()->m_spells.end(); ++itr) { if( (*itr)->spell->Id == spellid ) break; } if( itr == caster->GetAIInterface()->m_spells.end() ) return; } } if( caster == NULL || guid != caster->GetGUID() ) return; targets.read(recvPacket, _player->GetGUID()); pSpell = SpellPointer(new Spell(caster, sp, false, NULLAURA)); pSpell->prepare(&targets); }
void WorldSession::HandlePetCastSpell(WorldPacket & recvPacket) { CHECK_INWORLD_RETURN uint64 guid = 0; uint8 castCount = 0; uint32 spellid = 0; uint8 castflags = 0; uint32 targetmask = 0; recvPacket >> guid; recvPacket >> castCount; recvPacket >> spellid; recvPacket >> castflags; SpellEntry* sp = dbcSpell.LookupEntryForced(spellid); if(sp == NULL) return; // Summoned Elemental's Freeze if(spellid == 33395) { if(!_player->GetSummon()) return; } else if(guid != _player->m_CurrentCharm) { if( _player->GetCharmedUnitGUID() != guid ) return; } SpellCastTargets targets; targets.read( recvPacket, guid ); float missilepitch = 0.0f; float missilespeed = 0; uint32 traveltime = 0; if( castflags & 2 ){ recvPacket >> missilepitch; recvPacket >> missilespeed; float dx = targets.m_destX - targets.m_srcX; float dy = targets.m_destY - targets.m_srcY; if( ( missilepitch != M_PI / 4 ) && ( missilepitch != -M_PI / 4 ) ) //lets not divide by 0 lul traveltime = ( sqrtf( dx * dx + dy * dy ) / ( cosf( missilepitch ) * missilespeed ) ) * 1000; }
void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) { CHECK_PACKET_SIZE(recvPacket,1+4+1); uint32 spellId; uint8 cast_count, unk_flags; recvPacket >> cast_count; recvPacket >> spellId; recvPacket >> unk_flags; // flags (if 0x02 - some additional data are received) sLog.outDebug("WORLD: got cast spell packet, spellId - %u, cast_count: %u, unk_flags %u, data length = %i", spellId, cast_count, unk_flags, recvPacket.size()); SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId ); if(!spellInfo) { sLog.outError("WORLD: unknown spell id %u", spellId); return; } // not have spell or spell passive and not casted by client if ( !_player->HasSpell (spellId) || IsPassiveSpell(spellId) ) { //cheater? kick? ban? return; } // client provided targets SpellCastTargets targets; if(!targets.read(&recvPacket,_player)) return; // 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(_player, spellInfo, false); spell->m_cast_count = cast_count; // set count of casts spell->prepare(&targets); }
void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket ) { sLog.outDetail("WORLD: CMSG_PET_CAST_SPELL"); uint64 guid; uint32 spellid; uint8 cast_count; uint8 unk_flags; // flags (if 0x02 - some additional data are received) recvPacket >> guid >> cast_count >> spellid >> unk_flags; sLog.outDebug("WORLD: CMSG_PET_CAST_SPELL, cast_count: %u, spellid %u, unk_flags %u", cast_count, spellid, unk_flags); if (!_player->GetPet() && !_player->GetCharm()) return; Creature* pet = _player->GetMap()->GetCreatureOrPetOrVehicle(guid); if (!pet || (pet != _player->GetPet() && pet!= _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; } if (pet->GetCharmInfo() && pet->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) return; // do not cast not learned spells if (!pet->HasSpell(spellid) || IsPassiveSpell(spellInfo)) return; SpellCastTargets targets; if (!targets.read(&recvPacket,pet)) return; pet->DoPetCastSpell(GetPlayer(), cast_count, targets, spellInfo ); }
void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket) { sLog->outDetail("WORLD: CMSG_PET_CAST_SPELL"); uint64 guid; uint8 castCount; uint32 spellId; uint8 castFlags; recvPacket >> guid >> castCount >> spellId >> castFlags; sLog->outDebug("WORLD: CMSG_PET_CAST_SPELL, guid: " UI64FMTD ", castCount: %u, spellId %u, castFlags %u", guid, castCount, spellId, castFlags); // This opcode is also sent from charmed and possessed units (players and creatures) if (!_player->GetGuardianPet() && !_player->GetCharm()) return; Unit* caster = ObjectAccessor::GetUnit(*_player, guid); if (!caster || (caster != _player->GetGuardianPet() && 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; } 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; } // do not cast not learned spells if (!caster->HasSpell(spellId) || IsPassiveSpell(spellId)) return; SpellCastTargets targets; targets.read(recvPacket, caster); HandleClientCastFlags(recvPacket, castFlags, targets); caster->ClearUnitState(UNIT_STAT_FOLLOW); Spell *spell = new Spell(caster, spellInfo, false); 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); if (result == SPELL_CAST_OK) { if (caster->GetTypeId() == TYPEID_UNIT) { Creature* pet = caster->ToCreature(); pet->AddCreatureSpellCooldown(spellId); if (pet->isPet()) { 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); else pet->SendPetAIReaction(guid); } } spell->prepare(&(spell->m_targets)); } else { caster->SendPetCastFail(spellId, result); if (caster->GetTypeId() == TYPEID_PLAYER) { if (!caster->ToPlayer()->HasSpellCooldown(spellId)) GetPlayer()->SendClearCooldown(spellId, caster); } else { if (!caster->ToCreature()->HasSpellCooldown(spellId)) GetPlayer()->SendClearCooldown(spellId, caster); } spell->finish(false); delete spell; } }
void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) { // TODO: add targets.read() check Player* pUser = _player; // ignore for remote control state if (pUser->m_mover != pUser) return; uint8 bagIndex, slot; uint8 unk_flags; // flags (if 0x02 - some additional data are received) uint8 cast_count; // next cast if exists (single or not) uint64 item_guid; uint32 glyphIndex; // something to do with glyphs? uint32 spellid; // casted spell id recvPacket >> bagIndex >> slot >> cast_count >> spellid >> item_guid >> glyphIndex >> unk_flags; Item *pItem = pUser->GetUseableItemByPos(bagIndex, slot); if (!pItem) { pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); return; } if (pItem->GetGUID() != item_guid) { pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); return; } sLog.outDetail("WORLD: CMSG_USE_ITEM packet, bagIndex: %u, slot: %u, cast_count: %u, spellid: %u, Item: %u, glyphIndex: %u, unk_flags: %u, data length = %i", bagIndex, slot, cast_count, spellid, pItem->GetEntry(), glyphIndex, unk_flags, (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; } // only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB) if ( proto->Class == ITEM_CLASS_CONSUMABLE && !(proto->Flags & ITEM_FLAGS_USEABLE_IN_ARENA) && pUser->InArena()) { pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH,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); // send spell error if (SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid)) { // for implicit area/coord target spells if (!targets.getUnitTarget()) Spell::SendCastResult(_player,spellInfo,cast_count,SPELL_FAILED_NO_VALID_TARGETS); // for explicit target spells else Spell::SendCastResult(_player,spellInfo,cast_count,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 pUser->CastItemUseSpell(pItem,targets,cast_count,glyphIndex); } }
void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket ) { sLog.outDetail("WORLD: CMSG_PET_CAST_SPELL"); CHECK_PACKET_SIZE(recvPacket,8+1+4+1); uint64 guid; uint32 spellid; uint8 cast_count; uint8 unk_flags; // flags (if 0x02 - some additional data are received) recvPacket >> guid >> cast_count >> spellid >> unk_flags; sLog.outDebug("WORLD: CMSG_PET_CAST_SPELL, cast_count: %u, spellid %u, unk_flags %u", cast_count, spellid, unk_flags); if(!_player->GetPet() && !_player->GetCharm()) return; if (GUID_HIPART(guid) == HIGHGUID_PLAYER) return; Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player,guid); if(!pet || (pet != _player->GetPet() && pet!= _player->GetCharm())) { sLog.outError( "HandlePetCastSpellOpcode: Pet %u isn't pet of player %s .\n", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() ); return; } if (pet->GetGlobalCooldown() > 0) return; SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid); if(!spellInfo) { sLog.outError("WORLD: unknown PET spell id %i\n", spellid); return; } // do not cast not learned spells if(!pet->HasSpell(spellid) || IsPassiveSpell(spellid)) return; SpellCastTargets targets; if(!targets.read(&recvPacket,pet)) return; pet->clearUnitState(UNIT_STAT_FOLLOW); Spell *spell = new Spell(pet, spellInfo, false); spell->m_cast_count = cast_count; // probably pending spell cast spell->m_targets = targets; int16 result = spell->PetCanCast(NULL); if(result == -1) { 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 { pet->SendPetCastFail(spellid, result); if(!pet->HasSpellCooldown(spellid)) pet->SendPetClearCooldown(spellid); spell->finish(false); delete spell; } }
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; } //remove invisibility on casted hack if(spellId != 32612) if(mover->HasAura(32612)) mover->RemoveAurasDueToSpell(32612); 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? uint8 unk1; recvPacket >> unk1; // >> 1 or 0 if(unk1) { recvPacket.read_skip<uint32>(); // >> MSG_MOVE_STOP uint64 guid; // guid - unused if(!recvPacket.readPackGUID(guid)) return; MovementInfo movementInfo; ReadMovementInfo(recvPacket, &movementInfo); } }
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; } 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 is resending autoshot cast opcode when other spell is casted during shoot rotation // Skip it to prevent "interrupt" message if (IsAutoRepeatRangedSpell(spellInfo) && _player->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL) && _player->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)->m_spellInfo == spellInfo) return; // can't use our own spells when we're in possession of another unit, if (_player->isPossessing()) 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? uint8 unk1; recvPacket >> unk1; // >> 1 or 0 if (unk1) { recvPacket.read_skip<uint32>(); // >> MSG_MOVE_STOP uint64 guid; // guid - unused if (!recvPacket.readPackGUID(guid)) return; MovementInfo movementInfo; ReadMovementInfo(recvPacket, &movementInfo); } }
void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) { // TODO: add targets.read() check CHECK_PACKET_SIZE(recvPacket,1+1+1); sLog.outDetail("WORLD: CMSG_USE_ITEM packet, data length = %i",recvPacket.size()); Player* pUser = _player; uint8 bagIndex, slot, tmp3; recvPacket >> bagIndex >> slot >> tmp3; Item *pItem = pUser->GetItemByPos(bagIndex, slot); if(!pItem) { pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); return; } ItemPrototype const *proto = pItem->GetProto(); if(!proto) { 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 <5; ++i) { if (IsNonCombatSpell(proto->Spells[i].SpellId)) { pUser->SendEquipError(EQUIP_ERR_NOT_IN_COMBAT,pItem,NULL); return; } } } // check also BIND_WHEN_PICKED_UP 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) { if (!pItem->IsSoulBound()) { pItem->SetState(ITEM_CHANGED, pUser); pItem->SetBinding( true ); } } SpellCastTargets targets; if(!targets.read(&recvPacket, pUser)) 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 // use triggered flag only for items with many spell casts and for not first cast int count = 0; for(int i = 0; i <5; ++i) { _Spell const& spellData = pItem->GetProto()->Spells[i]; // no spell if(!spellData.SpellId) continue; // wrong triggering type if( spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_USE && spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_NO_DELAY_USE) continue; SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellData.SpellId); if(!spellInfo) { sLog.outError("Item (Entry: %u) in have wrong spell id %u, ignoring ",proto->ItemId, spellData.SpellId); continue; } Spell *spell = new Spell(pUser, spellInfo, (count > 0) , 0); spell->m_CastItem = pItem; spell->prepare(&targets); ++count; } } }
void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) { CHECK_PACKET_SIZE(recvPacket,4+2); uint32 spellId; recvPacket >> spellId; sLog.outDetail("WORLD: got cast spell packet, spellId - %i, data length = %i", spellId, recvPacket.size()); SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId ); if(!spellInfo) { sLog.outError("WORLD: unknown spell id %i\n", spellId); return; } // not have spell or spell passive and not casted by client if ( !_player->HasSpell (spellId) || IsPassiveSpell(spellId) ) { //cheater? kick? ban? return; } // client provided targets SpellCastTargets targets; if(!targets.read(&recvPacket,_player)) return; // auto-selection buff level base at target level (in spellInfo) if(!IsPassiveSpell(spellId) && targets.getUnitTarget()) { bool needRankSelection = false; for(int i=0;i<3;i++) { if(IsPositiveEffect(spellId, i) && spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA) { needRankSelection = true; break; } } if(needRankSelection) { for(uint32 nextSpellId = spellId; nextSpellId!=0; nextSpellId = objmgr.GetPrevSpellInChain(nextSpellId)) { SpellEntry const *nextSpellInfo = sSpellStore.LookupEntry(nextSpellId); if(!nextSpellInfo) break; // if found appropriate level if(targets.getUnitTarget()->getLevel() + 10 >= nextSpellInfo->spellLevel) { SpellEntry const *spellInfo = sSpellStore.LookupEntry(nextSpellId); break; } } // if appropriate spell rank not found spellInfo store original casted spell and will output error in Spell::CanCast } } Spell *spell = new Spell(_player, spellInfo, false, 0); spell->prepare(&targets); }
void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket ) { sLog.outDetail("WORLD: CMSG_PET_CAST_SPELL"); CHECK_PACKET_SIZE(recvPacket,8+4); 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 .\n", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() ); return; } SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid); if(!spellInfo) { sLog.outError("WORLD: unknown PET spell id %i\n", 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 && ((Creature*)caster)->GetGlobalCooldown() > 0) { caster->SendPetCastFail(spellid, SPELL_FAILED_NOT_READY); return; } SpellCastTargets targets; if(!targets.read(&recvPacket,caster)) return; 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 = (Creature*)caster; 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(!((Player*)caster)->HasSpellCooldown(spellid)) caster->SendPetClearCooldown(spellid); } else { if(!((Creature*)caster)->HasSpellCooldown(spellid)) caster->SendPetClearCooldown(spellid); } spell->finish(false); delete spell; } }
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); }
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) { uint32 learning_spell_id = pItem->GetProto()->Spells[1].SpellId; SpellEntry const *spellInfo = sSpellStore.LookupEntry(SPELL_ID_GENERIC_LEARN); if(!spellInfo) { sLog.outError("Item (Entry: %u) in have wrong spell id %u, ignoring ",proto->ItemId, SPELL_ID_GENERIC_LEARN); pUser->SendEquipError(EQUIP_ERR_NONE,pItem,NULL); return; } Spell *spell = new Spell(pUser, spellInfo, false); spell->m_CastItem = pItem; spell->m_currentBasePoints[0] = learning_spell_id; spell->prepare(&targets); return; } // use triggered flag only for items with many spell casts and for not first cast int count = 0; for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) { _Spell const& spellData = pItem->GetProto()->Spells[i]; // no spell if(!spellData.SpellId) continue; // wrong triggering type if( spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_USE && spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_NO_DELAY_USE) continue; SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellData.SpellId); if(!spellInfo) { sLog.outError("Item (Entry: %u) in have wrong spell id %u, ignoring ",proto->ItemId, spellData.SpellId); continue; } Spell *spell = new Spell(pUser, spellInfo, (count > 0)); spell->m_CastItem = pItem; spell->prepare(&targets); ++count; } } }
void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) { sLog.outDetail("WORLD: CMSG_USE_ITEM packet, data length = %i",recvPacket.size()); Player* pUser = _player; uint8 bagIndex, slot, tmp3; recvPacket >> bagIndex >> slot >> tmp3; Item *pItem = pUser->GetItemByPos(bagIndex, slot); if(!pItem) { pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); return; } ItemPrototype const *proto = pItem->GetProto(); if(!proto) { 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()) { uint8 consumable = proto->Class == ITEM_CLASS_CONSUMABLE && proto->SubClass != ITEM_SUBCLASS_POTION && proto->SubClass != ITEM_SUBCLASS_SCROLL && proto->SubClass != ITEM_SUBCLASS_BANDAGE && proto->SubClass != ITEM_SUBCLASS_HEALTHSTONE && proto->SubClass != ITEM_SUBCLASS_COMBAT_EFFECT; uint8 trade_goods = proto->Class == ITEM_CLASS_TRADE_GOODS && proto->SubClass != ITEM_SUBCLASS_EXPLOSIVES; if (consumable || trade_goods || proto->Class == ITEM_CLASS_KEY || proto->Class == ITEM_CLASS_JUNK) { pUser->SendEquipError(EQUIP_ERR_CANT_DO_IN_COMBAT,pItem,NULL); return; } } // check also BIND_WHEN_PICKED_UP 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) { if (!pItem->IsSoulBound()) { pItem->SetState(ITEM_CHANGED, pUser); pItem->SetBinding( true ); } } SpellCastTargets targets; targets.read(&recvPacket, pUser); // use trigerred flag only for items with many spell casts and for not first cast int count = 0; for(int i = 0; i <5; ++i) { if( proto->Spells[i].SpellTrigger != USE ) continue; uint32 spellId = proto->Spells[i].SpellId; if(!spellId) continue; SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); if(!spellInfo) { sLog.outError("Item (Entry: %u) in have wrong spell id %u, ignoring ",proto->ItemId, spellId); continue; } Spell *spell = new Spell(pUser, spellInfo, (count > 0) , 0); spell->m_CastItem = pItem; spell->prepare(&targets); // delete triggered spell if(count > 0) delete spell; ++count; } }
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) return; 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); 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? 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? return; } } // Client is resending autoshot cast opcode when other spell is casted during shoot rotation // Skip it to prevent "interrupt" message if (IsAutoRepeatRangedSpell(spellInfo) && _player->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL) && _player->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)->m_spellInfo == spellInfo) return; // can't use our own spells when we're in possession of another unit, if(_player->isPossessing()) return; // client provided targets SpellCastTargets targets; if(!targets.read(&recvPacket,mover)) return; // 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); }
void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) { // TODO: add targets.read() check CHECK_PACKET_SIZE(recvPacket,1+1+1+1+8); Player* pUser = _player; uint8 bagIndex, slot; uint8 spell_count; // number of spells at item, not used uint8 cast_count; // next cast if exists (single or not) uint64 item_guid; recvPacket >> bagIndex >> slot >> spell_count >> cast_count >> item_guid; Item *pItem = pUser->GetItemByPos(bagIndex, slot); if(!pItem) { pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); return; } if(pItem->GetGUID() != item_guid) { pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); return; } sLog.outDetail("WORLD: CMSG_USE_ITEM packet, bagIndex: %u, slot: %u, spell_count: %u , cast_count: %u, Item: %u, data length = %i", bagIndex, slot, spell_count, cast_count, pItem->GetEntry(), 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; } // only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB) if( proto->Class == ITEM_CLASS_CONSUMABLE && !(proto->Flags & ITEM_FLAGS_USEABLE_IN_ARENA) && pUser->InArena()) { pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH,pItem,NULL); return; } if (pUser->isInCombat()) { for(int i = 0; i < 5; ++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; //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) { uint32 learning_spell_id = pItem->GetProto()->Spells[1].SpellId; SpellEntry const *spellInfo = sSpellStore.LookupEntry(SPELL_ID_GENERIC_LEARN); if(!spellInfo) { sLog.outError("Item (Entry: %u) in have wrong spell id %u, ignoring ",proto->ItemId, SPELL_ID_GENERIC_LEARN); pUser->SendEquipError(EQUIP_ERR_NONE,pItem,NULL); return; } Spell *spell = new Spell(pUser, spellInfo, false); spell->m_CastItem = pItem; spell->m_cast_count = cast_count; //set count of casts spell->m_currentBasePoints[0] = learning_spell_id; spell->prepare(&targets); return; } // use triggered flag only for items with many spell casts and for not first cast int count = 0; for(int i = 0; i < 5; ++i) { _Spell const& spellData = pItem->GetProto()->Spells[i]; // no spell if(!spellData.SpellId) continue; // wrong triggering type if( spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_USE && spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_NO_DELAY_USE) continue; SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellData.SpellId); if(!spellInfo) { sLog.outError("Item (Entry: %u) in have wrong spell id %u, ignoring ",proto->ItemId, spellData.SpellId); continue; } Spell *spell = new Spell(pUser, spellInfo, (count > 0)); spell->m_CastItem = pItem; spell->m_cast_count = cast_count; //set count of casts spell->prepare(&targets); ++count; } } }
void WorldSession::HandleCharmForceCastSpell(WorldPacket & recvPacket) { DEBUG_LOG( "WORLD"," got CMSG_PET_CAST_SPELL." ); uint64 guid; uint32 spellid; uint8 counter, flags; Unit* caster; SpellCastTargets targets; list<AI_Spell*>::iterator itr; recvPacket >> guid >> counter >> spellid >> flags; SpellEntry *sp = dbcSpell.LookupEntry(spellid); // Summoned Elemental's Freeze if(spellid == 33395) { caster = _player->m_Summon; if( caster && TO_PET(caster)->GetAISpellForSpellId(spellid) == NULL ) return; } else { if(_player->m_CurrentVehicle) caster = _player->m_CurrentVehicle; else caster = _player->m_CurrentCharm; if( caster != NULL ) { if(caster->IsVehicle() && !caster->IsPlayer()) { CreatureProtoVehicle* vehpro = CreatureProtoVehicleStorage.LookupEntry(caster->GetEntry()); bool hasspell = false; for(int i = 0; i < 6; ++i) { if(vehpro->VehicleSpells[i] = spellid) { hasspell = true; break; } } if(!hasspell) { WorldPacket data(SMSG_PET_CAST_FAILED, 1 + 4 + 1); data << uint8(0); data << uint32(spellid); data << uint8(SPELL_FAILED_NOT_KNOWN); SendPacket(&data); // Send packet to owner return; } } else { for(itr = caster->GetAIInterface()->m_spells.begin(); itr != caster->GetAIInterface()->m_spells.end(); ++itr) { if( (*itr)->spell->Id == spellid ) break; } if( itr == caster->GetAIInterface()->m_spells.end() ) return; } } } if( caster == NULL || guid != caster->GetGUID()) { WorldPacket data(SMSG_PET_CAST_FAILED, 1 + 4 + 1); data << uint8(0); data << uint32(spellid); data << uint8(SPELL_FAILED_SPELL_UNAVAILABLE); SendPacket(&data); // Send packet to owner return; } if( caster->IsVehicle() && !_player->m_CurrentVehicle) { WorldPacket data(SMSG_PET_CAST_FAILED, 1 + 4 + 1); data << uint8(0); data << uint32(spellid); data << uint8(SPELL_FAILED_NOT_ON_TRANSPORT); SendPacket(&data); // Send packet to owner return; } targets.read(recvPacket, _player->GetGUID()); Spell* pSpell = new Spell(caster, sp, false, NULL); pSpell->prepare(&targets); }