bool ChatHandler::HandlePetLearnCommand(const char* args) { if (!*args) return false; Player* player = m_session->GetPlayer(); Pet* pet = player->GetPet(); if (!pet) { PSendSysMessage("You have no pet"); SetSentErrorMessage(true); return false; } uint32 spellId = extractSpellIdFromLink((char*)args); if (!spellId || !sSpellMgr->GetSpellInfo(spellId)) return false; // Check if pet already has it if (pet->HasSpell(spellId)) { PSendSysMessage("Pet already has spell: %u", spellId); SetSentErrorMessage(true); return false; } // Check if spell is valid SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo)) { PSendSysMessage(LANG_COMMAND_SPELL_BROKEN, spellId); SetSentErrorMessage(true); return false; } pet->learnSpell(spellId); PSendSysMessage("Pet has learned spell %u", spellId); return true; }
static bool HandlePetLearnCommand(ChatHandler* handler, char const* args) { if (!*args) return false; Pet* pet = GetSelectedPlayerPetOrOwn(handler); if (!pet) { handler->SendSysMessage(LANG_SELECT_PLAYER_OR_PET); handler->SetSentErrorMessage(true); return false; } uint32 spellId = handler->extractSpellIdFromLink((char*)args); if (!spellId || !sSpellMgr->GetSpellInfo(spellId)) return false; // Check if pet already has it if (pet->HasSpell(spellId)) { handler->PSendSysMessage("Pet already has spell: %u", spellId); handler->SetSentErrorMessage(true); return false; } // Check if spell is valid SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo)) { handler->PSendSysMessage(LANG_COMMAND_SPELL_BROKEN, spellId); handler->SetSentErrorMessage(true); return false; } pet->learnSpell(spellId); handler->PSendSysMessage("Pet has learned spell %u", spellId); return true; }
static bool HandlePetUnlearnCommand(ChatHandler* handler, char const* args) { if (!*args) return false; Pet* pet = GetSelectedPlayerPetOrOwn(handler); if (!pet) { handler->SendSysMessage(LANG_SELECT_PLAYER_OR_PET); handler->SetSentErrorMessage(true); return false; } uint32 spellId = handler->extractSpellIdFromLink((char*)args); if (pet->HasSpell(spellId)) pet->removeSpell(spellId, false); else handler->PSendSysMessage("Pet doesn't have that spell"); return true; }
static bool HandlePetUnlearnCommand(ChatHandler* handler, char const* args) { if (!*args) return false; Player* player = handler->GetSession()->GetPlayer(); Pet* pet = player->GetPet(); if (!pet) { handler->PSendSysMessage("You have no pet"); handler->SetSentErrorMessage(true); return false; } uint32 spellId = handler->extractSpellIdFromLink((char*)args); if (pet->HasSpell(spellId)) pet->removeSpell(spellId, false); else handler->PSendSysMessage("Pet doesn't have that spell"); return true; }
bool ChatHandler::HandlePetUnlearnCommand(const char *args) { if (!*args) return false; Player* player = m_session->GetPlayer(); Pet* pet = player->GetPet(); if (!pet) { PSendSysMessage("You have no pet"); SetSentErrorMessage(true); return false; } uint32 spellId = extractSpellIdFromLink((char*)args); if (pet->HasSpell(spellId)) pet->removeSpell(spellId, false); else PSendSysMessage("Pet doesn't have that spell"); return true; }
void WorldSession::HandlePetLearnTalent( WorldPacket & recv_data ) { sLog.outDebug("WORLD: CMSG_PET_LEARN_TALENT"); recv_data.hexlike(); CHECK_PACKET_SIZE(recv_data, 8+4+4); uint64 guid; uint32 talent_id, requested_rank; recv_data >> guid >> talent_id >> requested_rank; Pet *pet = _player->GetPet(); if(!pet) return; if(guid != pet->GetGUID()) return; uint32 CurTalentPoints = pet->GetFreeTalentPoints(); if(CurTalentPoints == 0) return; if (requested_rank > 4) return; TalentEntry const *talentInfo = sTalentStore.LookupEntry(talent_id); if(!talentInfo) return; TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab); if(!talentTabInfo) return; CreatureInfo const *ci = pet->GetCreatureInfo(); if(!ci) return; CreatureFamilyEntry const *pet_family = sCreatureFamilyStore.LookupEntry(ci->family); if(!pet_family) return; if(pet_family->petTalentType < 0) // not hunter pet return; // prevent learn talent for different family (cheating) if(!((1 << pet_family->petTalentType) & talentTabInfo->petTalentMask)) return; // prevent skip talent ranks (cheating) if(requested_rank > 0 && !pet->HasSpell(talentInfo->RankID[requested_rank-1])) return; // Check if it requires another talent if (talentInfo->DependsOn > 0) { if(TalentEntry const *depTalentInfo = sTalentStore.LookupEntry(talentInfo->DependsOn)) { bool hasEnoughRank = false; for (int i = talentInfo->DependsOnRank; i <= 4; i++) { if (depTalentInfo->RankID[i] != 0) if (pet->HasSpell(depTalentInfo->RankID[i])) hasEnoughRank = true; } if (!hasEnoughRank) return; } } // Find out how many points we have in this field uint32 spentPoints = 0; uint32 tTab = talentInfo->TalentTab; if (talentInfo->Row > 0) { unsigned int numRows = sTalentStore.GetNumRows(); for (unsigned int i = 0; i < numRows; i++) // Loop through all talents. { // Someday, someone needs to revamp const TalentEntry *tmpTalent = sTalentStore.LookupEntry(i); if (tmpTalent) // the way talents are tracked { if (tmpTalent->TalentTab == tTab) { for (int j = 0; j <= 4; j++) { if (tmpTalent->RankID[j] != 0) { if (pet->HasSpell(tmpTalent->RankID[j])) { spentPoints += j + 1; } } } } } } } // not have required min points spent in talent tree if(spentPoints < (talentInfo->Row * 3)) return; // spell not set in talent.dbc uint32 spellid = talentInfo->RankID[requested_rank]; if( spellid == 0 ) { sLog.outError("Talent.dbc have for talent: %u Rank: %u spell id = 0", talent_id, requested_rank); return; } // already known if(pet->HasSpell(spellid)) return; // learn! (other talent ranks will unlearned at learning) pet->learnSpell(spellid); sLog.outDetail("TalentID: %u Rank: %u Spell: %u\n", talent_id, requested_rank, spellid); }
bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target) { if (!spellId) return false; if (!target) target = bot; Pet* pet = bot->GetPet(); if (pet && pet->HasSpell(spellId)) { pet->ToggleAutocast(spellId, true); TellMaster("My pet will auto-cast this spell"); return true; } aiObjectContext->GetValue<LastSpellCast&>("last spell cast")->Get().Set(spellId, target->GetObjectGuid(), time(0)); aiObjectContext->GetValue<LastMovement&>("last movement")->Get().Set(NULL); const SpellEntry* const pSpellInfo = sSpellStore.LookupEntry(spellId); MotionMaster &mm = *bot->GetMotionMaster(); if (bot->isMoving() && GetSpellCastTime(pSpellInfo, NULL)) { return false; } if (bot->IsTaxiFlying()) return false; bot->clearUnitState( UNIT_STAT_CHASE ); bot->clearUnitState( UNIT_STAT_FOLLOW ); ObjectGuid oldSel = bot->GetSelectionGuid(); bot->SetSelectionGuid(target->GetObjectGuid()); Spell *spell = new Spell(bot, pSpellInfo, false); SpellCastTargets targets; targets.setUnitTarget(target); WorldObject* faceTo = target; if (pSpellInfo->Targets & TARGET_FLAG_ITEM) { spell->m_CastItem = aiObjectContext->GetValue<Item*>("item for spell", spellId)->Get(); targets.setItemTarget(spell->m_CastItem); } if (pSpellInfo->Effect[0] == SPELL_EFFECT_OPEN_LOCK || pSpellInfo->Effect[0] == SPELL_EFFECT_SKINNING) { LootObject loot = *aiObjectContext->GetValue<LootObject>("loot target"); if (!loot.IsLootPossible(bot)) return false; GameObject* go = GetGameObject(loot.guid); if (go && go->isSpawned()) { WorldPacket* const packetgouse = new WorldPacket(CMSG_GAMEOBJ_USE, 8); *packetgouse << loot.guid; bot->GetSession()->QueuePacket(packetgouse); targets.setGOTarget(go); faceTo = go; } else { Unit* creature = GetUnit(loot.guid); if (creature) { targets.setUnitTarget(creature); faceTo = creature; } } } if (!bot->IsInFront(faceTo, sPlayerbotAIConfig.sightDistance)) { bot->SetFacingTo(bot->GetAngle(faceTo)); SetNextCheckDelay(sPlayerbotAIConfig.globalCoolDown); return false; } WaitForSpellCast(spellId); spell->prepare(&targets); bot->SetSelectionGuid(oldSel); LastSpellCast& lastSpell = aiObjectContext->GetValue<LastSpellCast&>("last spell cast")->Get(); return lastSpell.id == spellId; }
void WorldSession::HandlePetAction(WorldPacket& recv_data) { ObjectGuid petGuid; uint32 data; ObjectGuid targetGuid; recv_data >> petGuid; recv_data >> data; recv_data >> targetGuid; uint32 spellid = UNIT_ACTION_BUTTON_ACTION(data); uint8 flag = UNIT_ACTION_BUTTON_TYPE(data); // delete = 0x07 CastSpell = C1 DETAIL_LOG("HandlePetAction: %s flag is %u, spellid is %u, target %s.", petGuid.GetString().c_str(), uint32(flag), spellid, targetGuid.GetString().c_str()); // used also for charmed creature/player Unit* petUnit = _player->GetMap()->GetUnit(petGuid); if (!petUnit) { sLog.outError("HandlePetAction: %s not exist.", petGuid.GetString().c_str()); return; } if (_player->GetObjectGuid() != petUnit->GetCharmerOrOwnerGuid()) { sLog.outError("HandlePetAction: %s isn't controlled by %s.", petGuid.GetString().c_str(), _player->GetGuidStr().c_str()); return; } if (!petUnit->isAlive()) return; CharmInfo* charmInfo = petUnit->GetCharmInfo(); if (!charmInfo) { sLog.outError("WorldSession::HandlePetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", petUnit->GetGUIDLow(), petUnit->GetTypeId()); return; } Pet* pet = nullptr; Creature* creature = nullptr; if (petUnit->GetTypeId() == TYPEID_UNIT) { creature = static_cast<Creature*>(petUnit); if (creature->IsPet()) { pet = static_cast<Pet*>(petUnit); if (pet->GetModeFlags() & PET_MODE_DISABLE_ACTIONS) return; } } if (!pet && petUnit->hasUnitState(UNIT_STAT_CONTROLLED)) { // possess case if (flag != uint8(ACT_COMMAND)) { sLog.outError("PetHAndler: unknown PET flag Action %i and spellid %i. For possessed %s", uint32(flag), spellid, petUnit->GetGuidStr().c_str()); return; } switch (spellid) { case COMMAND_STAY: case COMMAND_FOLLOW: charmInfo->SetCommandState(CommandStates(spellid)); break; case COMMAND_ATTACK: { Unit* targetUnit = targetGuid ? _player->GetMap()->GetUnit(targetGuid) : nullptr; if (targetUnit && targetUnit != petUnit && targetUnit->isTargetableForAttack()) { _player->SetInCombatState(true, targetUnit); // This is true if pet has no target or has target but targets differs. if (petUnit->getVictim() != targetUnit) petUnit->Attack(targetUnit, true); } break; } case COMMAND_ABANDON: _player->Uncharm(); break; default: sLog.outError("PetHandler: Not allowed action %i and spellid %i. Pet %s owner is %s", uint32(flag), spellid, petUnit->GetGuidStr().c_str(), _player->GetGuidStr().c_str()); break; } return; } // only real pet should go there if (!pet) { sLog.outError("PetHandler: A not pet trying to do unknown Action %i and spellid %i. Pet %s owner is %s", uint32(flag), spellid, petUnit->GetGuidStr().c_str(), _player->GetGuidStr().c_str()); return; } 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); pet->SetIsRetreating(); pet->SetStayPosition(true); pet->SetSpellOpener(); charmInfo->SetCommandState(COMMAND_STAY); break; } case COMMAND_FOLLOW: // spellid=1792 // FOLLOW { if (!petUnit->hasUnitState(UNIT_STAT_CONTROLLED)) { petUnit->StopMoving(); petUnit->GetMotionMaster()->Clear(); pet->SetIsRetreating(true); } petUnit->AttackStop(true, true); pet->SetStayPosition(); pet->SetSpellOpener(); charmInfo->SetCommandState(COMMAND_FOLLOW); break; } case COMMAND_ATTACK: // spellid=1792 // ATTACK { pet->SetIsRetreating(); pet->SetSpellOpener(); Unit* targetUnit = targetGuid ? _player->GetMap()->GetUnit(targetGuid) : nullptr; if (targetUnit && targetUnit != petUnit && targetUnit->isTargetableForAttack() && targetUnit->isInAccessablePlaceFor((Creature*)petUnit)) { _player->SetInCombatState(true, targetUnit); // 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(); pet->AI()->AttackStart(targetUnit); // 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->getPetType() == HUNTER_PET) pet->Unsummon(PET_SAVE_AS_DELETED, _player); else // dismissing a summoned pet is like killing them (this prevents returning a soulshard...) pet->SetDeathState(CORPSE); pet->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 { pet->AttackStop(true, true); pet->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 { pet->SetIsRetreating(); pet->SetSpellOpener(); Unit* unit_target = targetGuid ? _player->GetMap()->GetUnit(targetGuid) : nullptr; // do not cast unknown spells 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; 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 (!pet->HasSpell(spellid) || IsPassiveSpell(spellInfo)) return; _player->SetInCombatState(true, unit_target); pet->clearUnitState(UNIT_STAT_MOVING); Spell* spell = new Spell(pet, spellInfo, false); SpellCastResult result = spell->CheckPetCast(unit_target); const SpellRangeEntry* sRange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex); if (unit_target && !(pet->IsWithinDistInMap(unit_target, sRange->maxRange) && pet->IsWithinLOSInMap(unit_target)) && !(GetPlayer()->IsFriendlyTo(unit_target) || pet->HasAuraType(SPELL_AURA_MOD_POSSESS))) { pet->SetSpellOpener(spellid, sRange->minRange, sRange->maxRange); spell->finish(false); delete spell; pet->AttackStop(); if (!pet->hasUnitState(UNIT_STAT_CONTROLLED)) { pet->GetMotionMaster()->Clear(); pet->AI()->AttackStart(unit_target); // 10% chance to play special warlock pet attack talk, else growl if (pet->IsPet() && pet->getPetType() == SUMMON_PET && pet != unit_target && roll_chance_i(10)) pet->SendPetTalk((uint32)PET_TALK_ATTACK); pet->SendPetAIReaction(); } else petUnit->Attack(unit_target, true); return; } // auto turn to target unless possessed if (result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->hasUnitState(UNIT_STAT_CONTROLLED)) { if (unit_target) { pet->SetInFront(unit_target); if (unit_target->GetTypeId() == TYPEID_PLAYER) pet->SendCreateUpdateToPlayer((Player*)unit_target); } else if (Unit* unit_target2 = spell->m_targets.getUnitTarget()) { pet->SetInFront(unit_target2); if (unit_target2->GetTypeId() == TYPEID_PLAYER) pet->SendCreateUpdateToPlayer((Player*)unit_target2); } if (Unit* powner = pet->GetCharmerOrOwner()) if (powner->GetTypeId() == TYPEID_PLAYER) pet->SendCreateUpdateToPlayer((Player*)powner); result = SPELL_CAST_OK; } if (result == SPELL_CAST_OK) { pet->AddCreatureSpellCooldown(spellid); unit_target = spell->m_targets.getUnitTarget(); pet->SetSpellOpener(); spell->SpellStart(&(spell->m_targets)); } else { if (pet->hasUnitState(UNIT_STAT_CONTROLLED)) Spell::SendCastResult(GetPlayer(), spellInfo, 0, result); 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); pet->SetSpellOpener(); spell->finish(false); delete spell; } break; } default: sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid); } }