Pet commands are handled in zone/client_packet.cpp:
Code:
void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
{
char val1[20]={0};
PetCommand_Struct* pet = (PetCommand_Struct*) app->pBuffer;
Mob* mypet = this->GetPet();
if(!mypet) return;
if(mypet->GetPetType() == petAnimation && (pet->command != PET_HEALTHREPORT && pet->command != PET_GETLOST) && !GetAA(aaAnimationEmpathy))
return;
// just let the command "/pet get lost" work for familiars
if(mypet->GetPetType() == petFamiliar && pet->command != PET_GETLOST)
return;
switch(pet->command) {
case PET_ATTACK: {
if (!target)
break;
if (target->IsMezzed()) {
Message_StringID(10, CANNOT_WAKE, mypet->GetCleanName(), target->GetCleanName());
break;
}
if((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 2) || mypet->GetPetType() != petAnimation) {
if (mypet->GetHateTop()==0 && target != this && DistNoRootNoZ(*target) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) {
mypet->SetHeld(false); //break the hold and guard if we explicitly tell the pet to attack.
mypet->SetPetOrder(SPO_Follow);
zone->AddAggroMob();
mypet->AddToHateList(target, 1);
Message_StringID(10, PET_ATTACKING, mypet->GetCleanName(), target->GetCleanName());
}
}
break;
}
case PET_BACKOFF: {
if((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) {
mypet->Say_StringID(PET_CALMING);
mypet->WhipeHateList();
}
break;
}
case PET_HEALTHREPORT: {
Message_StringID(10, PET_REPORT_HP, ConvertArrayF(mypet->GetHPRatio(), val1));
mypet->ShowBuffList(this);
//Message(10,"%s tells you, 'I have %d percent of my hit points left.'",mypet->GetName(),(int8)mypet->GetHPRatio());
break;
}
case PET_GETLOST: {
if (mypet->Charmed())
break;
if (mypet->GetPetType() == petCharmed || !mypet->IsNPC()) {
// eqlive ignores this command
// we could just remove the charm
// and continue
mypet->BuffFadeByEffect(SE_Charm);
break;
} else {
SetPet(NULL);
}
mypet->Say_StringID(PET_GETLOST_STRING);
mypet->CastToNPC()->Depop();
// WildcardX: Oddly, the client (Titanium) will still allow "/pet get lost" command despite me adding the code below. If someone can figure that out, you can uncomment this code and use it.
/*
if((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 2) || mypet->GetPetType() != petAnimation) {
mypet->Say_StringID(PET_GETLOST_STRING);
mypet->CastToNPC()->Depop();
}
*/
break;
}
case PET_LEADER: {
mypet->Say_StringID(PET_LEADERIS);
break;
}
case PET_GUARDHERE: {
if((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 1) || mypet->GetPetType() != petAnimation) {
if(mypet->IsNPC()) {
mypet->SetHeld(false);
mypet->Say_StringID(PET_GUARDINGLIFE);
mypet->SetPetOrder(SPO_Guard);
mypet->CastToNPC()->SaveGuardSpot();
}
}
break;
}
case PET_FOLLOWME: {
if((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 1) || mypet->GetPetType() != petAnimation) {
mypet->SetHeld(false);
mypet->Say_StringID(PET_FOLLOWING);
mypet->SetPetOrder(SPO_Follow);
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
}
break;
}
case PET_TAUNT: {
if((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) {
Message(0,"%s says, 'Now taunting foes, Master!",mypet->GetCleanName());
mypet->CastToNPC()->SetTaunting(true);
}
break;
}
case PET_NOTAUNT: {
if((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) {
Message(0,"%s says, 'No longer taunting foes, Master!",mypet->GetCleanName());
mypet->CastToNPC()->SetTaunting(false);
}
break;
}
case PET_GUARDME: {
if((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 1) || mypet->GetPetType() != petAnimation) {
mypet->SetHeld(false);
mypet->Say_StringID(PET_GUARDME_STRING);
mypet->SetPetOrder(SPO_Follow);
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
}
break;
}
case PET_SITDOWN: {
if((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) {
mypet->Say_StringID(PET_SIT_STRING);
mypet->SetPetOrder(SPO_Sit);
mypet->SetRunAnimSpeed(0);
if(!mypet->UseBardSpellLogic()) // solar: maybe we can have a bard pet
mypet->InterruptSpell(); //Baron-Sprite: No cast 4 u. // neotokyo: i guess the pet should start casting
mypet->SendAppearancePacket(AT_Anim, ANIM_SIT);
}
break;
}
case PET_STANDUP: {
if((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) {
mypet->Say_StringID(PET_SIT_STRING);
mypet->SetPetOrder(SPO_Follow);
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
}
break;
}
case PET_SLUMBER: {
if(mypet->GetPetType() != petAnimation) {
mypet->Say_StringID(PET_SIT_STRING);
mypet->SetPetOrder(SPO_Sit);
mypet->SetRunAnimSpeed(0);
if(!mypet->UseBardSpellLogic()) // solar: maybe we can have a bard pet
mypet->InterruptSpell(); //Baron-Sprite: No cast 4 u. // neotokyo: i guess the pet should start casting
mypet->SendAppearancePacket(AT_Anim, ANIM_DEATH);
}
break;
}
case PET_HOLD: {
if(GetAA(aaPetDiscipline) && mypet->IsNPC()){
mypet->Say("I will hold until given an order, master.");
mypet->WhipeHateList();
mypet->SetHeld(true);
mypet->SetPetOrder(SPO_Guard);
mypet->CastToNPC()->SaveGuardSpot();
}
}
default:
printf("Client attempted to use a unknown pet command:\n");
break;
}
}
I believe you should be able to add a check like this for each command that they shouldn't be able to respond to:
Code:
if (mypet->IsFeared()) break;
So, to fix /pet back specifically, after
Code:
case PET_BACKOFF: {
add
Code:
if (mypet->IsFeared()) break;
If I'm not mistaken, we'll need to do the same thing for /pet attack, /pet get lost, /pet guard here, /pet follow, /pet guard me, /pet sit, /pet stand, /pet slumber, and /pet hold. I think that just leaves us with /pet health, /pet leader, and /pet taunt.