diff --git a/zone/attack.cpp b/zone/attack.cpp index 179534966..7ffbc07bf 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -2516,6 +2516,9 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b } } + if (IsPetStop()) + return; + // Pet that is /pet hold on will not add to their hate list if they're not engaged // Pet that is /pet hold on and /pet focus on will not add others to their hate list // Pet that is /pet ghold on will never add to their hate list unless /pet attack or /pet qattack @@ -2632,7 +2635,7 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b } } - if (mypet && !mypet->IsHeld()) { // I have a pet, add other to it + if (mypet && !mypet->IsHeld() && !mypet->IsPetStop()) { // I have a pet, add other to it if (!mypet->IsFamiliar() && !mypet->GetSpecialAbility(IMMUNE_AGGRO)) mypet->hate_list.AddEntToHateList(other, 0, 0, bFrenzy); } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 4d32a0ea9..aa64b5d82 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -10013,6 +10013,10 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { if (target != this && DistanceSquaredNoZ(mypet->GetPosition(), target->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) { + if (mypet->IsPetStop()) { + mypet->SetPetStop(false); + SetPetCommandState(PET_BUTTON_STOP, 0); + } zone->AddAggroMob(); // classic acts like qattack int hate = 1; @@ -10046,6 +10050,10 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { if (GetTarget() != this && DistanceSquaredNoZ(mypet->GetPosition(), GetTarget()->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) { + if (mypet->IsPetStop()) { + mypet->SetPetStop(false); + SetPetCommandState(PET_BUTTON_STOP, 0); + } zone->AddAggroMob(); mypet->AddToHateList(GetTarget(), 1, 0, true, false, false, SPELL_UNKNOWN, true); Message_StringID(MT_PetResponse, PET_ATTACKING, mypet->GetCleanName(), GetTarget()->GetCleanName()); @@ -10060,6 +10068,10 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) mypet->Say_StringID(MT_PetResponse, PET_CALMING); mypet->WipeHateList(); mypet->SetTarget(nullptr); + if (mypet->IsPetStop()) { + mypet->SetPetStop(false); + SetPetCommandState(PET_BUTTON_STOP, 0); + } } break; } @@ -10107,6 +10119,10 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) mypet->CastToNPC()->SaveGuardSpot(); if (!mypet->GetTarget()) // want them to not twitch if they're chasing something down mypet->SetCurrentSpeed(0); + if (mypet->IsPetStop()) { + mypet->SetPetStop(false); + SetPetCommandState(PET_BUTTON_STOP, 0); + } } } break; @@ -10118,6 +10134,10 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) mypet->Say_StringID(MT_PetResponse, PET_FOLLOWING); mypet->SetPetOrder(SPO_Follow); mypet->SendAppearancePacket(AT_Anim, ANIM_STAND); + if (mypet->IsPetStop()) { + mypet->SetPetStop(false); + SetPetCommandState(PET_BUTTON_STOP, 0); + } } break; } @@ -10157,6 +10177,10 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) mypet->Say_StringID(MT_PetResponse, PET_GUARDME_STRING); mypet->SetPetOrder(SPO_Follow); mypet->SendAppearancePacket(AT_Anim, ANIM_STAND); + if (mypet->IsPetStop()) { + mypet->SetPetStop(false); + SetPetCommandState(PET_BUTTON_STOP, 0); + } } break; } @@ -10339,6 +10363,43 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) } break; } + case PET_STOP: { + if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF + + if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + if (mypet->IsPetStop()) { + mypet->SetPetStop(false); + } else { + mypet->SetPetStop(true); + mypet->SetCurrentSpeed(0); + mypet->WipeHateList(); + mypet->SetTarget(nullptr); + } + mypet->Say_StringID(MT_PetResponse, PET_GETLOST_STRING); + } + break; + } + case PET_STOP_ON: { + if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF + + if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + mypet->SetPetStop(true); + mypet->SetCurrentSpeed(0); + mypet->WipeHateList(); + mypet->SetTarget(nullptr); + mypet->Say_StringID(MT_PetResponse, PET_GETLOST_STRING); + } + break; + } + case PET_STOP_OFF: { + if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF + + if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + mypet->SetPetStop(false); + mypet->Say_StringID(MT_PetResponse, PET_GETLOST_STRING); + } + break; + } default: printf("Client attempted to use a unknown pet command:\n"); break; diff --git a/zone/mob.cpp b/zone/mob.cpp index d219a27af..7f1adedc3 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -344,8 +344,10 @@ Mob::Mob(const char* in_name, typeofpet = petNone; // default to not a pet petpower = 0; held = false; + gheld = false; nocast = false; focused = false; + pet_stop = false; _IsTempPet = false; pet_owner_client = false; pet_targetlock_id = 0; diff --git a/zone/mob.h b/zone/mob.h index 9a1ff67a0..53a890132 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -875,6 +875,8 @@ public: inline const bool IsNoCast() const { return nocast; } inline void SetFocused(bool nState) { focused = nState; } inline const bool IsFocused() const { return focused; } + inline void SetPetStop(bool nState) { pet_stop = nState; } + inline const bool IsPetStop() const { return pet_stop; } inline const bool IsRoamer() const { return roamer; } inline const int GetWanderType() const { return wandertype; } inline const bool IsRooted() const { return rooted || permarooted; } @@ -1184,6 +1186,7 @@ protected: bool gheld; bool nocast; bool focused; + bool pet_stop; bool spawned; void CalcSpellBonuses(StatBonuses* newbon); virtual void CalcBonuses(); diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index ddd6d1c76..ac77c9c74 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -943,7 +943,7 @@ void Mob::AI_Process() { // if(RuleB(Combat, EnableFearPathing)){ if(currently_fleeing) { - if(IsRooted() || (IsBlind() && CombatRange(hate_list.GetClosestEntOnHateList(this)))) { + if((IsRooted() || (IsBlind() && CombatRange(hate_list.GetClosestEntOnHateList(this)))) && !IsPetStop()) { //make sure everybody knows were not moving, for appearance sake if(IsMoving()) { @@ -1304,6 +1304,9 @@ void Mob::AI_Process() { if (m_PlayerState & static_cast(PlayerState::Aggressive)) SendRemovePlayerState(PlayerState::Aggressive); + if (IsPetStop()) // pet stop won't be engaged, so we will always get here and we want the above branch to execute + return; + if(zone->CanDoCombat() && AI_feign_remember_timer->Check()) { // 6/14/06 // Improved Feign Death Memory