void PetAI::MoveInLineOfSight(Unit* u) { if (m_creature->getVictim()) return; if (m_creature->hasUnitState(UNIT_STAT_CAN_NOT_REACT)) return; CharmInfo* charmInfo = m_creature->GetCharmInfo(); if (!charmInfo) return; if (m_creature->IsPet() && charmInfo->HasState(CHARM_STATE_ACTION, ACTIONS_DISABLE)) return; if (!charmInfo->HasState(CHARM_STATE_REACT, REACT_AGGRESSIVE)) return; if (!u->isTargetableForAttack() || !m_creature->IsHostileTo(u) || !u->isInAccessablePlaceFor(m_creature) || !u->isVisibleForOrDetect(m_creature, m_creature, true)) return; float attackRadius = m_creature->GetAttackDistance(u); if (m_creature->IsWithinDistInMap(u, attackRadius) && m_creature->GetDistanceZ(u) <= CREATURE_Z_ATTACK_RANGE) AttackStart(u); }
void WorldSession::HandlePetAction(WorldPacket& recv_data) { ObjectGuid petGuid; uint32 data; ObjectGuid targetGuid; float x, y, z; recv_data >> petGuid; recv_data >> data; recv_data >> targetGuid; recv_data >> x >> y >> z; 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* pet = GetPlayer()->GetMap()->GetUnit(petGuid); if (!pet) { sLog.outError("HandlePetAction: %s not exist.", petGuid.GetString().c_str()); return; } if (GetPlayer()->GetObjectGuid() != pet->GetCharmerOrOwnerGuid()) { sLog.outError("HandlePetAction: %s isn't controlled by %s.", petGuid.GetString().c_str(), GetPlayer()->GetGuidStr().c_str()); return; } CharmInfo* charmInfo = pet->GetCharmInfo(); if (!charmInfo) { sLog.outError("WorldSession::HandlePetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId()); return; } if (!pet->isAlive()) { pet->SendPetActionFeedback(FEEDBACK_PET_DEAD); return; } if (pet->GetTypeId() == TYPEID_PLAYER) { // controller player can only do melee attack if (!(flag == ACT_COMMAND && spellid == COMMAND_ATTACK)) return; } else if (((Creature*)pet)->IsPet()) { // pet can have action bar disabled if (charmInfo->HasState(CHARM_STATE_ACTION,ACTIONS_DISABLE)) return; } if (((Creature*)pet)->IsPet() || pet->isCharmed()) GetPlayer()->CallForAllControlledUnits(DoPetActionWithHelper(GetPlayer(), flag, spellid, petGuid, targetGuid), CONTROLLED_PET | CONTROLLED_GUARDIANS | CONTROLLED_CHARM); }
void WorldSession::HandlePetSetAction(WorldPacket& recv_data) { DETAIL_LOG("HandlePetSetAction. CMSG_PET_SET_ACTION"); ObjectGuid petGuid; uint8 count; recv_data >> petGuid; Creature* pet = _player->GetMap()->GetAnyTypeCreature(petGuid); if (!pet || (pet != _player->GetPet() && pet != _player->GetCharm())) { sLog.outError("HandlePetSetAction: Unknown pet or pet owner."); return; } CharmInfo* charmInfo = pet->GetCharmInfo(); if (!charmInfo) { sLog.outError("WorldSession::HandlePetSetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId()); return; } // pet can have action bar disabled if (pet->IsPet() && charmInfo->HasState(CHARM_STATE_ACTION,ACTIONS_DISABLE)) return; // if pet is chained - used first pet action bar if (((Pet*)pet)->GetPetCounter()) return; count = (recv_data.size() == 24) ? 2 : 1; uint32 position[2]; uint32 data[2]; bool move_command = false; for (uint8 i = 0; i < count; ++i) { recv_data >> position[i]; recv_data >> data[i]; uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data[i]); // ignore invalid position if (position[i] >= MAX_UNIT_ACTION_BAR_INDEX) return; // in the normal case, command and reaction buttons can only be moved, not removed // at moving count ==2, at removing count == 1 // ignore attempt to remove command|reaction buttons (not possible at normal case) if (act_state == ACT_COMMAND || act_state == ACT_REACTION) { if (count == 1) return; move_command = true; } } // check swap (at command->spell swap client remove spell first in another packet, so check only command move correctness) if (move_command) { uint8 act_state_0 = UNIT_ACTION_BUTTON_TYPE(data[0]); if (act_state_0 == ACT_COMMAND || act_state_0 == ACT_REACTION) { uint32 spell_id_0 = UNIT_ACTION_BUTTON_ACTION(data[0]); UnitActionBarEntry const* actionEntry_1 = charmInfo->GetActionBarEntry(position[1]); if (!actionEntry_1 || spell_id_0 != actionEntry_1->GetAction() || act_state_0 != actionEntry_1->GetType()) return; } uint8 act_state_1 = UNIT_ACTION_BUTTON_TYPE(data[1]); if (act_state_1 == ACT_COMMAND || act_state_1 == ACT_REACTION) { uint32 spell_id_1 = UNIT_ACTION_BUTTON_ACTION(data[1]); UnitActionBarEntry const* actionEntry_0 = charmInfo->GetActionBarEntry(position[0]); if (!actionEntry_0 || spell_id_1 != actionEntry_0->GetAction() || act_state_1 != actionEntry_0->GetType()) return; } } for (uint8 i = 0; i < count; ++i) { uint32 spell_id = UNIT_ACTION_BUTTON_ACTION(data[i]); uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data[i]); DETAIL_LOG("Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position[i], spell_id, uint32(act_state)); // if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add if ((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_PASSIVE) && spell_id && ((Pet*)pet)->HasSpell(spell_id)) { // sign for autocast on/off if (act_state == ACT_ENABLED || act_state == ACT_DISABLED) { bool enabled = act_state == ACT_ENABLED; if (pet->isCharmed()) charmInfo->ToggleCreatureAutocast(spell_id, enabled); else { GuidSet const& groupPets = _player->GetPets(); if (!groupPets.empty()) { for (GuidSet::const_iterator itr = groupPets.begin(); itr != groupPets.end(); ++itr) { if (Pet* pPet = GetPlayer()->GetMap()->GetPet(*itr)) { if (pPet->IsInWorld()) pPet->ToggleAutocast(spell_id, enabled); } } } } } charmInfo->SetActionBar(position[i], spell_id, ActiveStates(act_state)); } } }