Ejemplo n.º 1
0
void Unit::DoPetCastSpell(Player* owner, uint8 cast_count, SpellCastTargets targets, const SpellEntry* spellInfo)
{
	// chained
    if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
        if (Pet *chainedPet = GetPet())
            if (((Creature*)this)->GetEntry() == chainedPet->GetEntry())
                chainedPet->DoPetCastSpell(owner, cast_count, targets, spellInfo);

	if(GetTypeId() != TYPEID_UNIT)
		return;

	Creature* pet = dynamic_cast<Creature*>(this);
	uint32 spellid = spellInfo->Id;

	clearUnitState(UNIT_STAT_MOVING);

    Spell *spell = new Spell(pet, spellInfo, false);
    spell->m_cast_count = cast_count;                       // probably pending spell cast
    spell->m_targets = targets;

    SpellCastResult result = spell->CheckPetCast(NULL);
    if (result == SPELL_CAST_OK)
    {
        pet->AddCreatureSpellCooldown(spellid);
        if (pet->isPet())
        {
            //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(((Pet*)pet)->getPetType() == SUMMON_PET && (urand(0, 100) < 10))
                pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL);
            else
                pet->SendPetAIReaction(pet->GetGUID());
        }

        spell->prepare(&(spell->m_targets));
    }
    else
    {
        pet->SendPetCastFail(spellid, result);
        if (!pet->HasSpellCooldown(spellid))
            owner->SendClearCooldown(spellid, pet);

        spell->finish(false);
        delete spell;
    }
}
Ejemplo n.º 2
0
void WorldSession::HandlePetCancelAuraOpcode(WorldPacket& recvPacket)
{
    ObjectGuid guid;
    uint32 spellId;

    recvPacket >> guid;
    recvPacket >> spellId;

    // ignore for remote control state
    if (!_player->IsSelfMover())
        return;

    SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId);
    if (!spellInfo)
    {
        sLog.outError("WORLD: unknown PET spell id %u", spellId);
        return;
    }

    Creature* pet = GetPlayer()->GetMap()->GetAnyTypeCreature(guid);

    if (!pet)
    {
        sLog.outError("HandlePetCancelAuraOpcode - %s not exist.", guid.GetString().c_str());
        return;
    }

    if (guid != GetPlayer()->GetPetGuid() && guid != GetPlayer()->GetCharmGuid())
    {
        sLog.outError("HandlePetCancelAura. %s isn't pet of %s", guid.GetString().c_str(), GetPlayer()->GetGuidStr().c_str());
        return;
    }

    if (!pet->isAlive())
    {
        pet->SendPetActionFeedback(FEEDBACK_PET_DEAD);
        return;
    }

    pet->RemoveAurasDueToSpell(spellId);

    pet->AddCreatureSpellCooldown(spellId);
}
Ejemplo n.º 3
0
void WorldSession::HandlePetCancelAuraOpcode( WorldPacket& recvPacket)
{
    uint64 guid;
    uint32 spellId;

    recvPacket >> guid;
    recvPacket >> spellId;

    SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
    if(!spellInfo)
    {
        sLog.outError("WORLD: unknown PET spell id %u", spellId);
        return;
    }

    Creature* pet = GetPlayer()->GetMap()->GetCreatureOrPet(guid);

    if(!pet)
    {
        sLog.outError( "Pet %u not exist.", uint32(GUID_LOPART(guid)) );
        return;
    }

    if(pet != GetPlayer()->GetPet() && pet != GetPlayer()->GetCharm())
    {
        sLog.outError( "HandlePetCancelAura.Pet %u isn't pet of player %s", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() );
        return;
    }

    if(!pet->isAlive())
    {
        pet->SendPetActionFeedback(FEEDBACK_PET_DEAD);
        return;
    }

    pet->RemoveAurasDueToSpell(spellId);

    pet->AddCreatureSpellCooldown(spellId);
}
Ejemplo n.º 4
0
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(LOG_FILTER_NETWORKIO, "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;
    }

    SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(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->GetCharmInfo() && caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo))
        {
            caster->SendPetCastFail(spellId, SPELL_FAILED_NOT_READY);
            return;
        }

    // do not cast not learned spells
    if (!caster->HasSpell(spellId) || spellInfo->IsPassive())
        return;

    SpellCastTargets targets;
    targets.Read(recvPacket, caster);
    HandleClientCastFlags(recvPacket, castFlags, targets);

    caster->ClearUnitState(UNIT_STATE_FOLLOW);

    Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE);
    spell->_cast_count = castCount;                    // probably pending spell cast
    spell->m_targets = targets;

    // TODO: need to check victim?
    SpellCastResult result;
    if (caster->_movedPlayer)
        result = spell->CheckPetCast(caster->_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;
    }
}
Ejemplo n.º 5
0
void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )
{
    DETAIL_LOG("WORLD: CMSG_PET_CAST_SPELL");
    recvPacket.hexlike();
    recvPacket.print_storage();

    //2 - 0 - 0 - 43 - 129 - 0 - 80 - 241 | - 42 - 211 - 253 - 0 | - 0 | - 2 |- 96 - 0 - 0 - 0 | - 0 - 26
    //- 164 - 59 - 196 - 174 - 98 - 131 | - 194 - 182 - 171 - 218| - 67 - 0 - 48 - 93| - 0 - 196 - 32
    //- 177| - 242 - 193 - 22 - 110 - 224 - 67 - 203 - 166 | - 68 - 61 - 133 - 1| - 240 - 66 - 1 - 183 |
    //- 0 - 0 - 0 - 217| - 2 - 43 - 129 - 80 - 241 - 0 - 10 - 0 - 0 - 0 - 0 - 76 - 109 - 175 - 0
    //- 238 - 115 - 58 - 196 - 20 - 110 - 121 - 194 - 187 - 107 - 217 - 67 - 32 - 44 - 27 - 62 - 217
    //- 1 - 36 - 129 - 80 - 241 - 0 - 0 - 160 - 64 - 0 - 0 - 160 - 64 - 0 - 0 - 160 - 64 - 192 - 233
    //- 172 - 62 - 4 - 0 - 0 - 0 - 7 - 230 - 0 - 0 - 0 -

    //5 - 0 - 0 - 43 - 129 - 0 - 80 - 241 | - 85 - 211 - 253 - 0 | - 0 | - 2 | - 96 - 0 - 0 - 0 | - 0 - 69 - 60 - 61
    //- 196 - 171 - 248 - 107| - 194 - 8 - 236 - 218 | - 67 - 0 - 177 - 11 | - 46 - 196 - 89 - 16 | - 14 - 195
    //- 5 - 38 - 231 - 67 - 23 - 221 | - 110 - 62 - 15 - 3 | - 240 - 66 -| 1 - 183 | - 0 - 0 - 0 - 217 | - 5 - 43
    //- 129 - 80 - 241 - 0 - 10 - 0 - 0 - 0 - 0 - 233 - 41 - 203 - 0 - 106 - 207 - 59 - 196 - 179 - 173 - 83
    //- 194 - 8 - 108 - 217 - 67 - 127 - 153 - 170 - 64 - 217 - 4 - 36 - 129 - 80 - 241 - 0 - 0 - 160 - 64
    //- 0 - 0 - 160 - 64 - 0 - 0 - 160 - 64 - 7 - 77 - 175 - 64 - 4 - 0 - 0 - 0 - 7 - 195 - 0 - 0 - 0 -

    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);

    if (guid.IsPlayer())
        return;

    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(), GetPlayer()->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;


    // do not cast not learned spells
    if (!pet->HasSpell(spellid) || IsPassiveSpell(spellInfo))
        return;

    SpellCastTargets targets;

    recvPacket >> targets.ReadForCaster(pet);

    pet->clearUnitState(UNIT_STAT_MOVING);

    Spell *spell = new Spell(pet, spellInfo, false);
    spell->m_cast_count = cast_count;                       // probably pending spell cast
    spell->m_targets = targets;

    SpellCastResult result = spell->CheckPetCast(NULL);
    if (result == SPELL_CAST_OK)
    {
        pet->AddCreatureSpellCooldown(spellid);
        if (pet->IsPet())
        {
            //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(((Pet*)pet)->getPetType() == SUMMON_PET && (urand(0, 100) < 10))
                pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL);
            else
                pet->SendPetAIReaction();
        }

        spell->prepare(&(spell->m_targets));
    }
    else
    {
        pet->SendPetCastFail(spellid, result);
        if (!pet->HasSpellCooldown(spellid))
            GetPlayer()->SendClearCooldown(spellid, pet);

        spell->finish(false);
        delete spell;
    }
}
Ejemplo n.º 6
0
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(), GetPlayer()->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;


    // do not cast not learned spells
    if (!pet->HasSpell(spellid) || IsPassiveSpell(spellInfo))
        return;

    SpellCastTargets targets;

    recvPacket >> targets.ReadForCaster(pet);

    pet->clearUnitState(UNIT_STAT_MOVING);

    Spell* spell = new Spell(pet, spellInfo, false);
    spell->m_cast_count = cast_count;                       // probably pending spell cast
    spell->m_targets = targets;

    SpellCastResult result = spell->CheckPetCast(NULL);
    if (result == SPELL_CAST_OK)
    {
        pet->AddCreatureSpellCooldown(spellid);
        if (pet->IsPet())
        {
            // 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 (((Pet*)pet)->getPetType() == SUMMON_PET && (urand(0, 100) < 10))
                pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL);
            else
                pet->SendPetAIReaction();
        }

        spell->prepare(&(spell->m_targets));
    }
    else
    {
        pet->SendPetCastFail(spellid, result);
        if (!pet->HasSpellCooldown(spellid))
            GetPlayer()->SendClearCooldown(spellid, pet);

        spell->finish(false);
        delete spell;
    }
}
Ejemplo n.º 7
0
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;
    }
}
Ejemplo n.º 8
0
void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )
{
    sLog.outDetail("WORLD: CMSG_PET_CAST_SPELL");

    uint64 guid;
    uint32 spellid;

    recvPacket >> guid >> spellid;

    if (!_player->GetPet() && !_player->GetCharm())
        return;

    Creature* pet = _player->GetMap()->GetCreatureOrPet(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;
    }

    if (pet->GetGlobalCooldown() > 0)
        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 (!pet->HasSpell(spellid) || IsPassiveSpell(spellid))
        return;

    SpellCastTargets targets;

    recvPacket >> targets.ReadForCaster(pet);

    pet->clearUnitState(UNIT_STAT_MOVING);

    Spell *spell = new Spell(pet, spellInfo, false);
    spell->m_targets = targets;

    SpellCastResult result = spell->CheckPetCast(NULL);
    if (result == SPELL_CAST_OK)
    {
        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))
            GetPlayer()->SendClearCooldown(spellid, pet);

        spell->finish(false);
        delete spell;
    }
}
Ejemplo n.º 9
0
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;
    }
}
Ejemplo n.º 10
0
void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )
{
    DETAIL_LOG("WORLD: CMSG_PET_CAST_SPELL");
    recvPacket.hexlike();
    recvPacket.print_storage();

    //2 - 0 - 0 - 43 - 129 - 0 - 80 - 241 | - 42 - 211 - 253 - 0 | - 0 | - 2 |- 96 - 0 - 0 - 0 | - 0 - 26
    //- 164 - 59 - 196 - 174 - 98 - 131 | - 194 - 182 - 171 - 218| - 67 - 0 - 48 - 93| - 0 - 196 - 32
    //- 177| - 242 - 193 - 22 - 110 - 224 - 67 - 203 - 166 | - 68 - 61 - 133 - 1| - 240 - 66 - 1 - 183 |
    //- 0 - 0 - 0 - 217| - 2 - 43 - 129 - 80 - 241 - 0 - 10 - 0 - 0 - 0 - 0 - 76 - 109 - 175 - 0
    //- 238 - 115 - 58 - 196 - 20 - 110 - 121 - 194 - 187 - 107 - 217 - 67 - 32 - 44 - 27 - 62 - 217
    //- 1 - 36 - 129 - 80 - 241 - 0 - 0 - 160 - 64 - 0 - 0 - 160 - 64 - 0 - 0 - 160 - 64 - 192 - 233
    //- 172 - 62 - 4 - 0 - 0 - 0 - 7 - 230 - 0 - 0 - 0 -

    //5 - 0 - 0 - 43 - 129 - 0 - 80 - 241 | - 85 - 211 - 253 - 0 | - 0 | - 2 | - 96 - 0 - 0 - 0 | - 0 - 69 - 60 - 61
    //- 196 - 171 - 248 - 107| - 194 - 8 - 236 - 218 | - 67 - 0 - 177 - 11 | - 46 - 196 - 89 - 16 | - 14 - 195
    //- 5 - 38 - 231 - 67 - 23 - 221 | - 110 - 62 - 15 - 3 | - 240 - 66 -| 1 - 183 | - 0 - 0 - 0 - 217 | - 5 - 43
    //- 129 - 80 - 241 - 0 - 10 - 0 - 0 - 0 - 0 - 233 - 41 - 203 - 0 - 106 - 207 - 59 - 196 - 179 - 173 - 83
    //- 194 - 8 - 108 - 217 - 67 - 127 - 153 - 170 - 64 - 217 - 4 - 36 - 129 - 80 - 241 - 0 - 0 - 160 - 64
    //- 0 - 0 - 160 - 64 - 0 - 0 - 160 - 64 - 7 - 77 - 175 - 64 - 4 - 0 - 0 - 0 - 7 - 195 - 0 - 0 - 0 -

    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;

    DEBUG_LOG("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 .", 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", spellid);
        return;
    }

    // do not cast not learned spells
    if (!pet->HasSpell(spellid) || IsPassiveSpell(spellInfo))
        return;

    SpellCastTargets targets;

    //float elevation, speed;
    //uint8 pos1, pos2;
    recvPacket >> targets.ReadForCaster(pet);
    //recvPacket >> elevation >> speed;
    //recvPacket >> pos1 >> pos2;

    pet->clearUnitState(UNIT_STAT_MOVING);
    
    //mask: 96, elevation: 0.167906, speed: 120.002441, pos1: 1, pos: 183
 
    //sLog.outDebug("mask: %u, elevation: %f, speed: %f, pos1: %u, pos: %u", targets.m_targetMask, elevation, speed, pos1, pos2);
 
    sLog.outDebug("guid: %u, sX: %f, sY:%f, sZ: %f", targets.getUnitTargetGUID(),targets.m_srcX,targets.m_srcY,targets.m_srcZ);
    sLog.outDebug("guid: %u, sX: %f, sY:%f, sZ: %f", targets.getUnitTargetGUID(),targets.m_destX,targets.m_destY,targets.m_destZ);

    Spell *spell = new Spell(pet, spellInfo, false);
    spell->m_cast_count = cast_count;                       // probably pending spell cast
    spell->m_targets = targets;

    SpellCastResult result = spell->CheckPetCast(NULL);
    if (result == SPELL_CAST_OK)
    {
        pet->AddCreatureSpellCooldown(spellid);
        if (pet->isPet())
        {
            //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(((Pet*)pet)->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))
            GetPlayer()->SendClearCooldown(spellid, pet);

        spell->finish(false);
        delete spell;
    }
}
Ejemplo n.º 11
0
void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
{
    DETAIL_LOG("WORLD: CMSG_PET_CAST_SPELL");

    ObjectGuid guid;
    uint32 spellid;
    uint8  cast_count;
    uint8  cast_flags;                                      // flags (if 0x02 - some additional data are received)

    recvPacket >> guid >> cast_count >> spellid >> cast_flags;

    DEBUG_LOG("WORLD: CMSG_PET_CAST_SPELL, %s, cast_count: %u, spellid %u, cast_flags %u", guid.GetString().c_str(), cast_count, spellid, cast_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);

    targets.ReadAdditionalData(recvPacket, cast_flags);

    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;
    }
}
Ejemplo n.º 12
0
void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
{
    DETAIL_LOG("WORLD: CMSG_PET_CAST_SPELL");

    ObjectGuid guid;
    uint32 spellid;

    recvPacket >> guid >> spellid;

    DEBUG_LOG("WORLD: CMSG_PET_CAST_SPELL, %s, spellid %u", guid.GetString().c_str(), spellid);

    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(), GetPlayer()->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;


    // do not cast not learned spells
    if (!pet->HasSpell(spellid) || IsPassiveSpell(spellInfo))
        return;

    SpellCastTargets targets;

    recvPacket >> targets.ReadForCaster(pet);

    pet->clearUnitState(UNIT_STAT_MOVING);

    Spell* spell = new Spell(pet, spellInfo, false);
    spell->m_targets = targets;

    SpellCastResult result = spell->CheckPetCast(nullptr);
    if (result == SPELL_CAST_OK)
    {
        pet->AddCreatureSpellCooldown(spellid);
        if (pet->IsPet())
            ((Pet*)pet)->CheckLearning(spellid);

        spell->SpellStart(&(spell->m_targets));
    }
    else
    {
        Unit* owner = pet->GetCharmerOrOwner();
        if (owner && owner->GetTypeId() == TYPEID_PLAYER)
            Spell::SendCastResult((Player*)owner, spellInfo, 0, result, true);

        if (!pet->HasSpellCooldown(spellid))
            GetPlayer()->SendClearCooldown(spellid, pet);

        spell->finish(false);
        delete spell;
    }
}
Ejemplo n.º 13
0
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)
    {
        if (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())
                    {
                        // 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;
            }
        }

        if (!petUnit->GetCharmerGuid())
            return;
    }

    switch (flag)
    {
        case ACT_COMMAND:                                   // 0x07
            switch (spellid)
            {
                case COMMAND_STAY:                          // flat=1792  // STAY
                {
                    if (!petUnit->hasUnitState(UNIT_STAT_CONTROLLED))
                    {
                        petUnit->StopMoving();
                        petUnit->GetMotionMaster()->Clear();
                    }
                    petUnit->AttackStop(true, true);
                    charmInfo->SetCommandState(COMMAND_STAY);
                    break;
                }
                case COMMAND_FOLLOW:                        // spellid=1792  // FOLLOW
                {
                    if (!petUnit->hasUnitState(UNIT_STAT_CONTROLLED))
                    {
                        petUnit->StopMoving();
                        petUnit->GetMotionMaster()->Clear();
                        charmInfo->SetIsRetreating(true);
                    }
                    petUnit->AttackStop(true, true);
                    charmInfo->SetCommandState(COMMAND_FOLLOW);
                    break;
                }
                case COMMAND_ATTACK:                        // spellid=1792  // ATTACK
                {
                    charmInfo->SetIsRetreating();
                    charmInfo->SetSpellOpener();

                    Unit* targetUnit = targetGuid ? _player->GetMap()->GetUnit(targetGuid) : nullptr;

                    if (targetUnit && targetUnit != petUnit && targetUnit->isTargetableForAttack() && targetUnit->isInAccessablePlaceFor((Creature*)petUnit))
                    {
                        // This is true if pet has no target or has target but targets differs.
                        if (petUnit->getVictim() != targetUnit)
                        {
                            petUnit->AttackStop();
                            if (!petUnit->hasUnitState(UNIT_STAT_CONTROLLED))
                            {
                                petUnit->GetMotionMaster()->Clear();

                                petUnit->AI()->AttackStart(targetUnit);

                                if (pet)
                                {
                                    // 10% chance to play special warlock pet attack talk, else growl
                                    if (pet->getPetType() == SUMMON_PET && roll_chance_i(10))
                                        pet->SendPetTalk((uint32)PET_TALK_ATTACK);

                                    pet->SendPetAIReaction();
                                }
                            }
                            else
                                pet->Attack(targetUnit, true);
                        }
                    }
                    break;
                }
                case COMMAND_ABANDON:                       // abandon (hunter pet) or dismiss (summoned pet)
                {
                    if (pet && pet->getPetType() == HUNTER_PET)
                        pet->Unsummon(PET_SAVE_AS_DELETED, _player);
                    else
                    {
                        // dismissing a summoned pet is like killing them (this prevents returning a soulshard...)
                        if (creature && creature->IsTemporarySummon())
                            petUnit->SetDeathState(CORPSE);
                        else
                            _player->Uncharm();
                    }

                    charmInfo->SetStayPosition();
                    break;
                }
                default:
                    sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid);
            }
            break;
        case ACT_REACTION:                                  // 0x6
            switch (spellid)
            {
                case REACT_PASSIVE:                         // passive
                {
                    petUnit->AttackStop(true, true);
                    charmInfo->SetSpellOpener();
                }
                case REACT_DEFENSIVE:                       // recovery
                case REACT_AGGRESSIVE:                      // activete
                {
                    charmInfo->SetReactState(ReactStates(spellid));
                    break;
                }
            }
            break;
        case ACT_DISABLED:                                  // 0x81    spell (disabled), ignore
        case ACT_PASSIVE:                                   // 0x01
        case ACT_ENABLED:                                   // 0xC1    spell
        {
            charmInfo->SetIsRetreating();
            charmInfo->SetSpellOpener();

            Unit* unit_target = targetGuid ? _player->GetMap()->GetUnit(targetGuid) : nullptr;

            // do not cast unknown spells
            SpellEntry const* spellInfo = sSpellTemplate.LookupEntry<SpellEntry>(spellid);
            if (!spellInfo)
            {
                sLog.outError("WORLD: unknown PET spell id %i", spellid);
                return;
            }

            if (petUnit->GetCharmInfo() && petUnit->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo))
                return;

            for (int i = 0; i < MAX_EFFECT_INDEX; ++i)
            {
                if (spellInfo->EffectImplicitTargetA[i] == TARGET_ALL_ENEMY_IN_AREA
                    || spellInfo->EffectImplicitTargetA[i] == TARGET_ALL_ENEMY_IN_AREA_INSTANT
                    || spellInfo->EffectImplicitTargetA[i] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED)
                    return;
            }

            // do not cast not learned spells
            if (!petUnit->HasSpell(spellid) || IsPassiveSpell(spellInfo))
                return;

            _player->SetInCombatState(true, unit_target);

            petUnit->clearUnitState(UNIT_STAT_MOVING);

            Spell* spell = new Spell(petUnit, spellInfo, false);

            SpellCastResult result = spell->CheckPetCast(unit_target);

            const SpellRangeEntry* sRange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex);

            if (unit_target && !(petUnit->IsWithinDistInMap(unit_target, sRange->maxRange) && petUnit->IsWithinLOSInMap(unit_target))
                && !(GetPlayer()->IsFriendlyTo(unit_target) || petUnit->HasAuraType(SPELL_AURA_MOD_POSSESS)))
            {
                charmInfo->SetSpellOpener(spellid, sRange->minRange, sRange->maxRange);
                spell->finish(false);
                delete spell;

                petUnit->AttackStop();

                if (!petUnit->hasUnitState(UNIT_STAT_CONTROLLED))
                {
                    petUnit->GetMotionMaster()->Clear();

                    petUnit->AI()->AttackStart(unit_target);
                    // 10% chance to play special warlock pet attack talk, else growl
                    if (pet && pet->getPetType() == SUMMON_PET && pet != unit_target && roll_chance_i(10))
                        petUnit->SendPetTalk((uint32)PET_TALK_ATTACK);

                    petUnit->SendPetAIReaction();
                }
                else
                    petUnit->Attack(unit_target, true);

                return;
            }

            // auto turn to target unless possessed
            if (result == SPELL_FAILED_UNIT_NOT_INFRONT && !petUnit->hasUnitState(UNIT_STAT_CONTROLLED))
            {
                if (unit_target)
                {
                    petUnit->SetInFront(unit_target);
                    if (unit_target->GetTypeId() == TYPEID_PLAYER)
                        petUnit->SendCreateUpdateToPlayer((Player*)unit_target);
                }
                else if (Unit* unit_target2 = spell->m_targets.getUnitTarget())
                {
                    petUnit->SetInFront(unit_target2);
                    if (unit_target2->GetTypeId() == TYPEID_PLAYER)
                        petUnit->SendCreateUpdateToPlayer((Player*)unit_target2);
                }
                if (Unit* powner = petUnit->GetCharmerOrOwner())
                    if (powner->GetTypeId() == TYPEID_PLAYER)
                        petUnit->SendCreateUpdateToPlayer((Player*)powner);
                result = SPELL_CAST_OK;
            }

            if (result == SPELL_CAST_OK)
            {
                if (creature)
                    creature->AddCreatureSpellCooldown(spellid);

                unit_target = spell->m_targets.getUnitTarget();

                charmInfo->SetSpellOpener();
                spell->SpellStart(&(spell->m_targets));
            }
            else
            {
                if (petUnit->hasUnitState(UNIT_STAT_CONTROLLED))
                    Spell::SendCastResult(GetPlayer(), spellInfo, 0, result);
                else
                {
                    Unit* owner = petUnit->GetCharmerOrOwner();
                    if (owner && owner->GetTypeId() == TYPEID_PLAYER)
                        Spell::SendCastResult((Player*)owner, spellInfo, 0, result, true);
                }

                if (creature && !creature->HasSpellCooldown(spellid))
                    GetPlayer()->SendClearCooldown(spellid, petUnit);

                charmInfo->SetSpellOpener();
                spell->finish(false);
                delete spell;
            }
            break;
        }
        default:
            sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid);
    }
}
Ejemplo n.º 14
0
void PetAI::UpdateAI(const uint32 diff)
{
    if (!m_unit->isAlive())
        return;
    Creature* creature = (m_unit->GetTypeId() == TYPEID_UNIT) ? static_cast<Creature*>(m_unit) : nullptr;
    Pet* pet = (creature && creature->IsPet()) ? static_cast<Pet*>(m_unit) : nullptr;
    
    Unit* owner = m_unit->GetCharmerOrOwner();
    if (!owner)
        return;

    Unit* victim = (pet && pet->GetModeFlags() & PET_MODE_DISABLE_ACTIONS) ? nullptr : m_unit->getVictim();

    if (m_updateAlliesTimer <= diff)
        // UpdateAllies self set update timer
        UpdateAllies();
    else
        m_updateAlliesTimer -= diff;

    if (inCombat && !victim)
    {
        m_unit->AttackStop(true, true);
        inCombat = false;
    }

    CharmInfo* charminfo = m_unit->GetCharmInfo();
    MANGOS_ASSERT(charminfo);

    if (charminfo->GetIsRetreating())
    {
        if (!owner->IsWithinDistInMap(m_unit, (PET_FOLLOW_DIST * 2)))
        {
            if (!m_unit->hasUnitState(UNIT_STAT_FOLLOW))
                m_unit->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);

            return;
        }
        else
            charminfo->SetIsRetreating();
    }
    else if (charminfo->GetSpellOpener() != 0) // have opener stored
    {
        uint32 minRange = charminfo->GetSpellOpenerMinRange();

        if (!(victim = m_unit->getVictim())
            || (minRange != 0 && m_unit->IsWithinDistInMap(victim, minRange)))
            charminfo->SetSpellOpener();
        else if (m_unit->IsWithinDistInMap(victim, charminfo->GetSpellOpenerMaxRange())
                && m_unit->IsWithinLOSInMap(victim))
        {
            // stop moving
            m_unit->clearUnitState(UNIT_STAT_MOVING);

            // auto turn to target
            m_unit->SetInFront(victim);

            if (victim->GetTypeId() == TYPEID_PLAYER)
                m_unit->SendCreateUpdateToPlayer((Player*)victim);

            if (owner->GetTypeId() == TYPEID_PLAYER)
                m_unit->SendCreateUpdateToPlayer((Player*)owner);

            uint32 spell_id = charminfo->GetSpellOpener();
            SpellEntry const* spellInfo = sSpellTemplate.LookupEntry<SpellEntry>(spell_id);

            Spell* spell = new Spell(m_unit, spellInfo, false);

            SpellCastResult result = spell->CheckPetCast(victim);

            if (result == SPELL_CAST_OK)
            {
                if (creature)
                    creature->AddCreatureSpellCooldown(spell_id);
                spell->SpellStart(&(spell->m_targets));
            }
            else
                delete spell;

            charminfo->SetSpellOpener();
        }
        else
            return;
    }
    // Auto cast (casted only in combat or persistent spells in any state)
    else if (!m_unit->IsNonMeleeSpellCasted(false))
    {
        typedef std::vector<std::pair<Unit*, Spell*> > TargetSpellList;
        TargetSpellList targetSpellStore;
        if (pet)
        {
            for (uint8 i = 0; i < pet->GetPetAutoSpellSize(); ++i)
            {
                uint32 spellID = pet->GetPetAutoSpellOnPos(i);
                if (!spellID)
                    continue;

                SpellEntry const* spellInfo = sSpellTemplate.LookupEntry<SpellEntry>(spellID);
                if (!spellInfo)
                    continue;

                if (m_unit->GetCharmInfo() && m_unit->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo))
                    continue;

                // ignore some combinations of combat state and combat/non combat spells
                if (!inCombat)
                {
                    // 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 requirements:
                    // Consume Shadows, Lesser Invisibility, so ignore checks for its
                    if (!IsNonCombatSpell(spellInfo))
                    {
                        int32 duration = GetSpellDuration(spellInfo);
                        int32 cooldown = GetSpellRecoveryTime(spellInfo);

                        // allow only spell not on cooldown
                        if (cooldown != 0 && duration < cooldown)
                            continue;

                        // not allow instant kill auto casts as full health cost
                        if (IsSpellHaveEffect(spellInfo, SPELL_EFFECT_INSTAKILL))
                            continue;
                    }
                }
                // just ignore non-combat spells
                else if (IsNonCombatSpell(spellInfo))
                    continue;

                Spell* spell = new Spell(m_unit, spellInfo, false);

                if (inCombat && !m_unit->hasUnitState(UNIT_STAT_FOLLOW) && spell->CanAutoCast(victim))
                {
                    targetSpellStore.push_back(TargetSpellList::value_type(victim, spell));
                    continue;
                }
                else
                {
                    bool spellUsed = false;
                    for (GuidSet::const_iterator tar = m_AllySet.begin(); tar != m_AllySet.end(); ++tar)
                    {
                        Unit* Target = m_unit->GetMap()->GetUnit(*tar);

                        // only buff targets that are in combat, unless the spell can only be cast while out of combat
                        if (!Target)
                            continue;

                        if (spell->CanAutoCast(Target))
                        {
                            targetSpellStore.push_back(TargetSpellList::value_type(Target, spell));
                            spellUsed = true;
                            break;
                        }
                    }
                    if (!spellUsed)
                        delete spell;
                }
            }
        }

        // found units to cast on to
        if (!targetSpellStore.empty())
        {
            uint32 index = urand(0, targetSpellStore.size() - 1);

            Spell* spell  = targetSpellStore[index].second;
            Unit*  target = targetSpellStore[index].first;

            targetSpellStore.erase(targetSpellStore.begin() + index);

            SpellCastTargets targets;
            targets.setUnitTarget(target);

            if (!m_unit->HasInArc(M_PI_F, target))
            {
                m_unit->SetInFront(target);
                if (target->GetTypeId() == TYPEID_PLAYER)
                    m_unit->SendCreateUpdateToPlayer((Player*)target);

                if (owner && owner->GetTypeId() == TYPEID_PLAYER)
                    m_unit->SendCreateUpdateToPlayer((Player*)owner);
            }

            if (creature)
                creature->AddCreatureSpellCooldown(spell->m_spellInfo->Id);

            spell->SpellStart(&targets);
        }

        // deleted cached Spell objects
        for (TargetSpellList::const_iterator itr = targetSpellStore.begin(); itr != targetSpellStore.end(); ++itr)
            delete itr->second;
    }

    // Stop here if casting spell (No melee and no movement)
    if (m_unit->IsNonMeleeSpellCasted(false))
        return;

    // we may get our actions disabled during spell casting, so do entire recheck for victim
    victim = (pet && pet->GetModeFlags() & PET_MODE_DISABLE_ACTIONS) ? nullptr : m_unit->getVictim();

    if (victim)
    {
        // i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc.
        // This is needed for charmed creatures, as once their target was reset other effects can trigger threat
        if (!victim->isTargetableForAttack())
        {
            DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "PetAI (guid = %u) is stopping attack.", m_unit->GetGUIDLow());
            m_unit->CombatStop();
            inCombat = false;
            
            return;
        }

        // if pet misses its target, it will also be the first in threat list
        if ((!creature || !(creature->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_MELEE))
            && m_unit->CanReachWithMeleeAttack(victim))
        {
            if (!m_unit->HasInArc(2 * M_PI_F / 3, victim))
            {
                m_unit->SetInFront(victim);
                if (victim->GetTypeId() == TYPEID_PLAYER)
                    m_unit->SendCreateUpdateToPlayer((Player*)victim);

                if (owner && owner->GetTypeId() == TYPEID_PLAYER)
                    m_unit->SendCreateUpdateToPlayer((Player*)owner);
            }

            DoMeleeAttackIfReady();
        }
        else if (!m_unit->hasUnitState(UNIT_STAT_MOVING))
            AttackStart(victim);
    }
    else if (owner)
    {
        CharmInfo* charmInfo = m_unit->GetCharmInfo();

        if (owner->isInCombat() && !(charmInfo && charmInfo->HasReactState(REACT_PASSIVE)))
            AttackStart(owner->getAttackerForHelper());
        else
        {
            if (charmInfo && charmInfo->HasCommandState(COMMAND_STAY))
            {
                //if stay command is set but we don't have stay pos set then we need to establish current pos as stay position
                if (!charminfo->IsStayPosSet())
                    charminfo->SetStayPosition(true);

                float stayPosX = charminfo->GetStayPosX();
                float stayPosY = charminfo->GetStayPosY();
                float stayPosZ = charminfo->GetStayPosZ();

                if (m_unit->GetPositionX() == stayPosX
                    && m_unit->GetPositionY() == stayPosY
                    && m_unit->GetPositionZ() == stayPosZ)
                {
                    float StayPosO = charminfo->GetStayPosO();

                    if (m_unit->hasUnitState(UNIT_STAT_MOVING))
                    {
                        m_unit->GetMotionMaster()->Clear(false);
                        m_unit->GetMotionMaster()->MoveIdle();
                    }
                    else if (m_unit->GetOrientation() != StayPosO)
                        m_unit->SetOrientation(StayPosO);
                }
                else
                    m_unit->GetMotionMaster()->MovePoint(0, stayPosX, stayPosY, stayPosZ, false);
            }
            else if (m_unit->hasUnitState(UNIT_STAT_FOLLOW))
            {
                if (owner->IsWithinDistInMap(m_unit, PET_FOLLOW_DIST))
                {
                    m_unit->GetMotionMaster()->Clear(false);
                    m_unit->GetMotionMaster()->MoveIdle();
                }
            }
            else if (charmInfo && charmInfo->HasCommandState(COMMAND_FOLLOW)
                && !owner->IsWithinDistInMap(m_unit, (PET_FOLLOW_DIST * 2)))
                m_unit->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
        }
    }
}
Ejemplo n.º 15
0
void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
{
    TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: CMSG_PET_CAST_SPELL");

    uint64 guid;
    uint8  castCount;
    uint32 spellId;
    uint8  castFlags;

    recvPacket >> guid >> castCount >> spellId >> castFlags;

    TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "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()))
    {
        TC_LOG_ERROR(LOG_FILTER_NETWORKIO, "HandlePetCastSpellOpcode: Pet %u isn't pet of player %s (GUID: %u).", uint32(GUID_LOPART(guid)), GetPlayer()->GetName().c_str(), GUID_LOPART(GetPlayer()->GetGUID()));
        return;
    }

    SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
    if (!spellInfo)
    {
        TC_LOG_ERROR(LOG_FILTER_NETWORKIO, "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->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;

    SpellCastTargets targets;
    targets.Read(recvPacket, caster);
    HandleClientCastFlags(recvPacket, castFlags, targets);

    caster->ClearUnitState(UNIT_STATE_FOLLOW);

    Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE);
    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;
    }
}
Ejemplo n.º 16
0
void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
{
    TC_LOG_DEBUG("network", "WORLD: CMSG_PET_CAST_SPELL");

    ObjectGuid casterGUID;
    ObjectGuid unkGUID1;
    ObjectGuid transportDstGUID;
    ObjectGuid transportSrcGUID;
    ObjectGuid targetGUID;
    ObjectGuid unkGUID2;
    bool hasDestPos;
    bool hasSrcPos;
    bool hasSpeed;
    bool hasSpell;
    bool hasGlyphIndex;
    bool hasTargetFlags;
    bool hasElevation;
    bool hasString;
    bool hasCastCount;
    bool hasUnk5bits;
    uint32 archeologyCounter = 0;
    WorldLocation dstLoc, srcLoc;
    float speed = 0.0f;
    float elevation = 0.0f;
    uint32 targetFlags = 0;
    uint32 spellID = 0;
    uint32 stringLenght = 0;
    uint8 castCount = 0;

    recvPacket.ReadBitSeq<3, 5>(casterGUID);
    hasDestPos = recvPacket.ReadBit();
    recvPacket.ReadBit();                   // unk bit
    hasSpeed = !recvPacket.ReadBit();
    hasSrcPos = recvPacket.ReadBit();
    hasSpell = !recvPacket.ReadBit();
    recvPacket.ReadBitSeq<0>(casterGUID);
    hasGlyphIndex = !recvPacket.ReadBit();
    recvPacket.ReadBitSeq<7>(casterGUID);
    hasTargetFlags = !recvPacket.ReadBit();
    hasElevation = !recvPacket.ReadBit();
    recvPacket.ReadBit();                   // has movement info
    hasString = !recvPacket.ReadBit();
    recvPacket.ReadBit();                   // !inverse bit, unk
    hasCastCount = !recvPacket.ReadBit();
    recvPacket.ReadBitSeq<2, 4>(casterGUID);
    archeologyCounter = recvPacket.ReadBits(2);
    recvPacket.ReadBitSeq<1>(casterGUID);
    hasUnk5bits = !recvPacket.ReadBit();

    for (uint32 i = 0; i < archeologyCounter; i++)
        recvPacket.ReadBits(2);             // archeology type

    recvPacket.ReadBitSeq<6>(casterGUID);

    if (hasDestPos)
        recvPacket.ReadBitSeq<2, 7, 4, 0, 1, 6, 5, 3>(transportDstGUID);

    // movement block (disabled by patch client-side)

    if (hasSrcPos)
        recvPacket.ReadBitSeq<6, 2, 3, 1, 5, 4, 0, 7>(transportSrcGUID);

    if (hasUnk5bits)
        recvPacket.ReadBits(5);             // unk 5 bits

    // Target GUID
    recvPacket.ReadBitSeq<3, 5, 6, 2, 4, 1, 7, 0>(targetGUID);

    // unkGUID1
    recvPacket.ReadBitSeq<3, 1, 5, 2, 4, 7, 0, 6>(unkGUID1);

    if (hasTargetFlags)
        targetFlags = recvPacket.ReadBits(20);

    if (hasString)
        stringLenght = recvPacket.ReadBits(7);

    recvPacket.ReadByteSeq<0, 4, 5, 1, 2, 3, 7>(casterGUID);

    for (uint32 i = 0; i < archeologyCounter; i++)
    {
        recvPacket.read_skip<uint32>(); // entry
        recvPacket.read_skip<uint32>(); // counter
    }

    recvPacket.ReadByteSeq<6>(casterGUID);
    recvPacket.ReadByteSeq<1, 5, 4, 2, 7, 3, 0>(unkGUID1);

    if (hasSrcPos)
    {
        recvPacket.ReadByteSeq<4>(transportSrcGUID);
        srcLoc.m_positionY = recvPacket.read<float>();
        recvPacket.ReadByteSeq<2, 6>(transportSrcGUID);
        srcLoc.m_positionZ = recvPacket.read<float>();
        srcLoc.m_positionX = recvPacket.read<float>();
        recvPacket.ReadByteSeq<1, 3, 5, 7, 0>(transportSrcGUID);
    }

    // Target GUID
    recvPacket.ReadByteSeq<7, 4, 2, 6, 3, 0, 5, 1>(targetGUID);

    if (hasDestPos)
    {
        dstLoc.m_positionX = recvPacket.read<float>();
        recvPacket.ReadByteSeq<5, 7, 2, 0, 1, 3, 6>(transportDstGUID);
        dstLoc.m_positionZ = recvPacket.read<float>();
        dstLoc.m_positionY = recvPacket.read<float>();
        recvPacket.ReadByteSeq<4>(transportDstGUID);
    }

    if (hasGlyphIndex)
        recvPacket.read_skip<uint32>();     // glyph index

    if (hasElevation)
        elevation = recvPacket.read<float>();

    if (hasSpell)
        spellID = recvPacket.read<uint32>();

    if (hasCastCount)
        castCount = recvPacket.read<uint8>();

    if (hasString)
        recvPacket.ReadString(stringLenght);

    if (hasSpeed)
        speed = recvPacket.read<float>();

    TC_LOG_DEBUG("network", "WORLD: CMSG_PET_CAST_SPELL, castCount: %u, spellId %u, targetFlags %u", castCount, spellID, targetFlags);

    // This opcode is also sent from charmed and possessed units (players and creatures)
    if (!_player->GetGuardianPet() && !_player->GetCharm())
        return;

    Unit* caster = ObjectAccessor::GetUnit(*_player, casterGUID);

    if (!caster || (caster != _player->GetGuardianPet() && caster != _player->GetCharm()))
    {
        TC_LOG_ERROR("network", "HandlePetCastSpellOpcode: Pet %u isn't pet of player %s .", uint32(GUID_LOPART(casterGUID)), GetPlayer()->GetName().c_str());
        return;
    }

    SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID);
    if (!spellInfo)
    {
        TC_LOG_ERROR("network", "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->GetCharmInfo() && caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(caster, spellInfo))
        {
            caster->SendPetCastFail(spellID, SPELL_FAILED_NOT_READY);
            return;
        }

    // do not cast not learned spells
    if (!caster->HasSpell(spellID) || spellInfo->IsPassive())
        return;

    SpellCastTargets targets;
    targets.Initialize(targetFlags, targetGUID, unkGUID1, transportDstGUID, dstLoc, transportSrcGUID, srcLoc);
    targets.SetElevation(elevation);
    targets.SetSpeed(speed);
    targets.Update(caster);

    // Interrupt auto-cast if other spell is forced by player
    if (caster->IsNonMeleeSpellCasted(false, true, true, false, true))
        caster->InterruptNonMeleeSpells(false, 0, false);

    caster->ClearUnitState(UNIT_STATE_FOLLOW);

    Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE, 0, false, true);
    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(spellID);
            }
        }

        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;
    }
}