void TimedFleeingMovementGenerator::Interrupt(Unit& owner) { owner.clearUnitState(UNIT_STAT_FLEEING | UNIT_STAT_FLEEING_MOVE); if (owner.GetTypeId() == TYPEID_UNIT) // temporary hack to fix creature only fleeing on low hp owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); if (owner.AI()) owner.AI()->TimedFleeingEnded(); }
void WorldSession::HandleTextEmoteOpcode(WorldPacket& recv_data) { if (!GetPlayer()->isAlive()) return; if (!GetPlayer()->CanSpeak()) { std::string timeStr = secsToTimeString(m_muteTime - time(nullptr)); SendNotification(GetMangosString(LANG_WAIT_BEFORE_SPEAKING), timeStr.c_str()); return; } uint32 text_emote, emoteNum; ObjectGuid guid; recv_data >> text_emote; recv_data >> emoteNum; recv_data >> guid; EmotesTextEntry const* em = sEmotesTextStore.LookupEntry(text_emote); if (!em) return; uint32 emote_id = em->textid; switch (emote_id) { case EMOTE_STATE_SLEEP: case EMOTE_STATE_SIT: case EMOTE_STATE_KNEEL: case EMOTE_ONESHOT_NONE: break; default: { // in feign death state allowed only text emotes. if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) break; GetPlayer()->HandleEmoteCommand(emote_id); break; } } Unit* unit = GetPlayer()->GetMap()->GetUnit(guid); MaNGOS::EmoteChatBuilder emote_builder(*GetPlayer(), text_emote, emoteNum, unit); MaNGOS::LocalizedPacketDo<MaNGOS::EmoteChatBuilder > emote_do(emote_builder); MaNGOS::CameraDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::EmoteChatBuilder > > emote_worker(GetPlayer(), sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE), emote_do); Cell::VisitWorldObjects(GetPlayer(), emote_worker, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE)); GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, unit); // Send scripted event call if (unit && unit->AI()) unit->AI()->ReceiveEmote(GetPlayer(), text_emote); }
void TimedFleeingMovementGenerator::Finalize(Unit& owner) { owner.clearUnitState(UNIT_STAT_FLEEING | UNIT_STAT_FLEEING_MOVE); if (Unit* victim = owner.getVictim()) { if (owner.isAlive()) { owner.AttackStop(true); if (owner.AI()) owner.AI()->AttackStart(victim); } } }
void TimedFleeingMovementGenerator::Finalize(Unit& owner) { owner.clearUnitState(UNIT_STAT_FLEEING | UNIT_STAT_FLEEING_MOVE); if (owner.GetTypeId() == TYPEID_UNIT) // temporary hack to fix creature only fleeing on low hp owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); if (Unit* victim = owner.getVictim()) { if (owner.isAlive()) { owner.AttackStop(true); if (owner.AI()) owner.AI()->AttackStart(victim); } } }
void EffectMovementGenerator::Finalize(Unit& unit) { if (unit.GetTypeId() != TYPEID_UNIT) return; if (unit.AI() && unit.movespline->Finalized()) unit.AI()->MovementInform(EFFECT_MOTION_TYPE, m_Id); // Need restore previous movement since we have no proper states system if (unit.isAlive() && !unit.hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_FLEEING | UNIT_STAT_NO_COMBAT_MOVEMENT)) { if (Unit* victim = unit.getVictim()) unit.GetMotionMaster()->MoveChase(victim); else unit.GetMotionMaster()->Initialize(); } }
void AssistanceDistractMovementGenerator::Finalize(Unit& unit) { unit.clearUnitState(UNIT_STAT_DISTRACTED); if (Unit* victim = unit.getVictim()) { if (unit.isAlive()) { unit.AttackStop(true); unit.AI()->AttackStart(victim); } } }
void JustDied(Unit* /*Killer*/) { me->TextEmote(EMOTE_KILREK_DIE, false); if (pInstance) { uint64 TerestianGUID = pInstance->GetData64(DATA_TERESTIAN); if (TerestianGUID) { Unit* Terestian = Unit::GetUnit((*me), TerestianGUID); if (Terestian && Terestian->IsAlive()) DoCast(Terestian, SPELL_BROKEN_PACT, true); /*Resummon Kil'rek*/ if (Creature* Terestian = me->FindNearestCreature(15688, 100.0f, true)) { CAST_AI(boss_terestianAI, Terestian->AI())->ReSummonKilrek_Timer = 30000; CAST_AI(boss_terestianAI, Terestian->AI())->SummonedKilrek = true; CAST_AI(boss_terestianAI, Terestian->AI())->ReSummonedKilrek = false; } } } else ERROR_INST_DATA(me); }
void VehicleInfo::Initialize() { if (!m_overwriteNpcEntry) m_overwriteNpcEntry = m_owner->GetEntry(); // Loading passengers (rough version only!) SQLMultiStorage::SQLMSIteratorBounds<VehicleAccessory> bounds = sVehicleAccessoryStorage.getBounds<VehicleAccessory>(m_overwriteNpcEntry); for (SQLMultiStorage::SQLMultiSIterator<VehicleAccessory> itr = bounds.first; itr != bounds.second; ++itr) { if (Creature* summoned = m_owner->SummonCreature(itr->passengerEntry, m_owner->GetPositionX(), m_owner->GetPositionY(), m_owner->GetPositionZ(), 2 * m_owner->GetOrientation(), TEMPSPAWN_DEAD_DESPAWN, 0)) { DEBUG_LOG("VehicleInfo(of %s)::Initialize: Load vehicle accessory %s onto seat %u", m_owner->GetGuidStr().c_str(), summoned->GetGuidStr().c_str(), itr->seatId); m_accessoryGuids.insert(summoned->GetObjectGuid()); int32 basepoint0 = itr->seatId + 1; summoned->CastCustomSpell((Unit*)m_owner, SPELL_RIDE_VEHICLE_HARDCODED, &basepoint0, nullptr, nullptr, TRIGGERED_OLD_TRIGGERED); } } // Initialize movement limitations uint32 vehicleFlags = GetVehicleEntry()->m_flags; Unit* pVehicle = (Unit*)m_owner; if (vehicleFlags & VEHICLE_FLAG_NO_STRAFE) pVehicle->m_movementInfo.AddMovementFlags2(MOVEFLAG2_NO_STRAFE); if (vehicleFlags & VEHICLE_FLAG_NO_JUMPING) pVehicle->m_movementInfo.AddMovementFlags2(MOVEFLAG2_NO_JUMPING); if (vehicleFlags & VEHICLE_FLAG_FULLSPEEDTURNING) pVehicle->m_movementInfo.AddMovementFlags2(MOVEFLAG2_FULLSPEEDTURNING); if (vehicleFlags & VEHICLE_FLAG_ALLOW_PITCHING) pVehicle->m_movementInfo.AddMovementFlags2(MOVEFLAG2_ALLOW_PITCHING); if (vehicleFlags & VEHICLE_FLAG_FULLSPEEDPITCHING) pVehicle->m_movementInfo.AddMovementFlags2(MOVEFLAG2_FULLSPEEDPITCHING); // NOTE: this is the best possible combination to root a vehicle; However, there are still exceptions, such as creature 27292 if (vehicleFlags & VEHICLE_FLAG_FIXED_POSITION || (!(vehicleFlags & VEHICLE_FLAG_UNK7) && vehicleFlags & VEHICLE_FLAG_UNK15)) pVehicle->SetRoot(true); // TODO: Guesswork, but it looks correct if (vehicleFlags & VEHICLE_FLAG_PASSIVE) pVehicle->AI()->SetReactState(REACT_PASSIVE); // Initialize power type based on DBC values (creatures only) if (pVehicle->GetTypeId() == TYPEID_UNIT) { if (PowerDisplayEntry const* powerEntry = sPowerDisplayStore.LookupEntry(GetVehicleEntry()->m_powerDisplayID)) pVehicle->SetPowerType(Powers(powerEntry->power)); } m_isInitialized = true; }
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->GetMasterGuid()) { 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_POSSESSED)) { // 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 && petUnit->CanAttack(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_DISMISS: _player->BreakCharmOutgoing(petUnit); 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->HasCharmer()) return; } switch (flag) { case ACT_COMMAND: // 0x07 switch (spellid) { case COMMAND_STAY: // flat=1792 // STAY { if (!petUnit->hasUnitState(UNIT_STAT_POSSESSED)) { 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_POSSESSED)) { 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 && petUnit->CanAttack(targetUnit) && 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_POSSESSED)) { 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 petUnit->Attack(targetUnit, true); } } break; } case COMMAND_DISMISS: // dismiss permanent pet, remove temporary pet, uncharm unit { if (pet) { pet->PlayDismissSound(); // No action for Hunter pets, Hunters must use their Dismiss Pet spell if (pet->getPetType() != HUNTER_PET) pet->ForcedDespawn(); } else { // dismissing a summoned pet is like killing them (this prevents returning a soulshard...) if (creature && creature->IsTemporarySummon()) creature->ForcedDespawn(); else _player->BreakCharmOutgoing(petUnit); } 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 { petUnit->AI()->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; } // do not cast not learned spells if (IsPassiveSpell(spellInfo) || !petUnit->HasSpell(spellid)) return; if (!petUnit->IsSpellReady(*spellInfo)) return; for (unsigned int i : spellInfo->EffectImplicitTargetA) { if (i == TARGET_ENUM_UNITS_ENEMY_AOE_AT_SRC_LOC || i == TARGET_ENUM_UNITS_ENEMY_AOE_AT_DEST_LOC || i == TARGET_ENUM_UNITS_ENEMY_AOE_AT_DYNOBJ_LOC) return; } petUnit->clearUnitState(UNIT_STAT_MOVING); uint32 flags = TRIGGERED_NONE; if (!petUnit->hasUnitState(UNIT_STAT_POSSESSED)) flags |= TRIGGERED_PET_CAST; Spell* spell = new Spell(petUnit, spellInfo, flags); 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)) && petUnit->CanAttackNow(unit_target)) { charmInfo->SetSpellOpener(spellid, sRange->minRange, sRange->maxRange); spell->finish(false); delete spell; petUnit->AttackStop(); if (!petUnit->hasUnitState(UNIT_STAT_POSSESSED)) { 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_POSSESSED)) { 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->GetMaster()) if (powner->GetTypeId() == TYPEID_PLAYER) petUnit->SendCreateUpdateToPlayer((Player*)powner); result = SPELL_CAST_OK; } if (result == SPELL_CAST_OK) { charmInfo->SetSpellOpener(); spell->SpellStart(&(spell->m_targets)); } else { if (creature && creature->IsSpellReady(*spellInfo)) 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); } }
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); } }
/// Remove control and such modifiers to a passenger if they were added void VehicleInfo::RemoveSeatMods(Unit* passenger, uint32 seatFlags) { Unit* pVehicle = (Unit*)m_owner; if (seatFlags & SEAT_FLAG_NOT_SELECTABLE) passenger->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); // ToDo: reset passenger model id for SEAT_FLAG_HIDE_PASSENGER? if (passenger->GetTypeId() == TYPEID_PLAYER) { Player* pPlayer = (Player*)passenger; // group update if (pPlayer->GetGroup()) pPlayer->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_VEHICLE_SEAT); if (seatFlags & SEAT_FLAG_CAN_CONTROL) { pPlayer->SetCharm(nullptr); pVehicle->SetCharmer(nullptr); pPlayer->UpdateClientControl(pVehicle, false); pPlayer->SetMover(nullptr); pVehicle->StopMoving(true); pVehicle->GetMotionMaster()->Clear(); pVehicle->clearUnitState(UNIT_STAT_POSSESSED); pVehicle->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_POSSESSED); pVehicle->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED); // must be called after movement control unapplying pPlayer->GetCamera().ResetView(); if (pVehicle->GetTypeId() == TYPEID_UNIT) { // reset vehicle faction ((Creature*)pVehicle)->ClearTemporaryFaction(); // Reset react state if (!(GetVehicleEntry()->m_flags & VEHICLE_FLAG_PASSIVE)) pVehicle->AI()->SetReactState(REACT_AGGRESSIVE); } } if (seatFlags & SEAT_FLAG_CAN_CAST) pPlayer->RemovePetActionBar(); } else if (passenger->GetTypeId() == TYPEID_UNIT) { if (seatFlags & SEAT_FLAG_CAN_CONTROL) { passenger->SetCharm(nullptr); pVehicle->SetCharmer(nullptr); } // Reinitialize movement if (((Creature*)passenger)->AI()) ((Creature*)passenger)->AI()->SetCombatMovement(true, true); if (!passenger->getVictim()) passenger->GetMotionMaster()->Initialize(); } }
/// Add control and such modifiers to a passenger if required void VehicleInfo::ApplySeatMods(Unit* passenger, uint32 seatFlags) { Unit* pVehicle = (Unit*)m_owner; // Vehicles are alawys Unit if (seatFlags & SEAT_FLAG_NOT_SELECTABLE) passenger->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); // ToDo: change passenger model id for SEAT_FLAG_HIDE_PASSENGER? if (passenger->GetTypeId() == TYPEID_PLAYER) { Player* pPlayer = (Player*)passenger; // group update if (pPlayer->GetGroup()) pPlayer->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_VEHICLE_SEAT); if (seatFlags & SEAT_FLAG_CAN_CONTROL) { pPlayer->GetCamera().SetView(pVehicle); pPlayer->SetCharm(pVehicle); pVehicle->SetCharmer(pPlayer); pVehicle->GetMotionMaster()->Clear(); pVehicle->GetMotionMaster()->MoveIdle(); pVehicle->StopMoving(true); pVehicle->addUnitState(UNIT_STAT_POSSESSED); pVehicle->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_POSSESSED); pVehicle->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED); pPlayer->UpdateClientControl(pVehicle, true); pPlayer->SetMover(pVehicle); // Unconfirmed - default speed handling if (pVehicle->GetTypeId() == TYPEID_UNIT) { if (!pPlayer->IsWalking() && pVehicle->IsWalking()) { ((Creature*)pVehicle)->SetWalk(false, true); } else if (pPlayer->IsWalking() && !pVehicle->IsWalking()) { ((Creature*)pVehicle)->SetWalk(true, true); } // set vehicle faction as per the controller faction ((Creature*)pVehicle)->SetFactionTemporary(pPlayer->getFaction(), TEMPFACTION_NONE); // set vehicle react state to passive; player will control the vehicle pVehicle->AI()->SetReactState(REACT_PASSIVE); } } if (seatFlags & SEAT_FLAG_CAN_CAST) { CharmInfo* charmInfo = pVehicle->InitCharmInfo(pVehicle); charmInfo->InitVehicleCreateSpells(); pPlayer->PossessSpellInitialize(); } } else if (passenger->GetTypeId() == TYPEID_UNIT) { if (seatFlags & SEAT_FLAG_CAN_CONTROL) { passenger->SetCharm(pVehicle); pVehicle->SetCharmer(passenger); // Change vehicle react state; ToDo: also change the vehicle faction? if (pVehicle->GetTypeId() == TYPEID_UNIT) pVehicle->AI()->SetReactState(passenger->AI()->GetReactState()); } ((Creature*)passenger)->AI()->SetCombatMovement(false); // Not entirely sure how this must be handled in relation to CONTROL // But in any way this at least would require some changes in the movement system most likely passenger->GetMotionMaster()->Clear(false, true); passenger->GetMotionMaster()->MoveIdle(); } }