diff --git a/CHANGELOG.md b/CHANGELOG.md index 9da523f41..7f735023c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [23.10.3] 9/16/2025 + +### Hotfix + +* Hotfix crashes occurring in #4987. @Akkadius 2025-09-17 + ## [23.10.2] 9/16/2025 ### Hotfix diff --git a/common/version.h b/common/version.h index 285e16968..c119346d4 100644 --- a/common/version.h +++ b/common/version.h @@ -25,7 +25,7 @@ // Build variables // these get injected during the build pipeline -#define CURRENT_VERSION "23.10.2-dev" // always append -dev to the current version for custom-builds +#define CURRENT_VERSION "23.10.3-dev" // always append -dev to the current version for custom-builds #define LOGIN_VERSION "0.8.0" #define COMPILE_DATE __DATE__ #define COMPILE_TIME __TIME__ diff --git a/package.json b/package.json index b1dd4a343..985a21c38 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eqemu-server", - "version": "23.10.2", + "version": "23.10.3", "repository": { "type": "git", "url": "https://github.com/EQEmu/Server.git" diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 441b4a538..a059bef65 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -11080,909 +11080,657 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) LogError("Wrong size: OP_PetCommands, size=[{}], expected [{}]", app->size, sizeof(PetCommand_Struct)); return; } - - auto* s = (PetCommand_Struct*) app->pBuffer; - char val1[20] = { 0 }; + PetCommand_Struct* pet = (PetCommand_Struct*)app->pBuffer; + Mob* mypet = GetPet(); + Mob *target = entity_list.GetMob(pet->target); - Mob* pet = GetPet(); - Mob* t = entity_list.GetMob(s->target); - - if (!pet || s->command == PetCommand::Leader) { - if (s->command == PetCommand::Leader) { + if (!mypet || pet->command == PET_LEADER) { + if (pet->command == PET_LEADER) { // we either send the ID of an NPC we're interested in or no ID for our own pet - if (t) { - Mob* owner = t->GetOwner(); - if (owner) { - t->SayString(PET_LEADERIS, owner->GetCleanName()); - } else { - t->SayString(I_FOLLOW_NOONE); - } - } else if (pet) { - pet->SayString(PET_LEADERIS, GetName()); + if (target) { + auto owner = target->GetOwner(); + if (owner) + target->SayString(PET_LEADERIS, owner->GetCleanName()); + else + target->SayString(I_FOLLOW_NOONE); + } else if (mypet) { + mypet->SayString(PET_LEADERIS, GetName()); } } return; } - if (!pet->IsNPC()) { + if (mypet->GetPetType() == petTargetLock && (pet->command != PET_HEALTHREPORT && pet->command != PET_GETLOST)) return; - } - - if ( - pet->GetPetType() == PetType::TargetLock && - s->command != PetCommand::HealthReport && - s->command != PetCommand::GetLost - ) { - return; - } // just let the command "/pet get lost" work for familiars - if (pet->GetPetType() == PetType::Familiar && s->command != PetCommand::GetLost) { + if (mypet->GetPetType() == petFamiliar && pet->command != PET_GETLOST) return; + + uint32 PetCommand = pet->command; + + // Handle Sit/Stand toggle in UF and later. + /* + if (GetClientVersion() >= EQClientUnderfoot) + { + if (PetCommand == PET_SITDOWN) + if (mypet->GetPetOrder() == SPO_Sit) + PetCommand = PET_STANDUP; } + */ - const bool can_use_command = ( - (pet->GetPetType() == PetType::Animation && aabonuses.PetCommands[s->command]) || - pet->GetPetType() != PetType::Animation - ); + switch (PetCommand) + { + case PET_ATTACK: { + if (!target) + break; - switch (s->command) { - case PetCommand::Attack: { - if ( - !t || - pet->IsFeared() || - !can_use_command || - t == this || - !( - DistanceSquaredNoZ(pet->GetPosition(), GetTarget()->GetPosition()) <= - (RuleR(Pets, AttackCommandRange) * RuleR(Pets, AttackCommandRange)) - ) || - DistanceSquared(pet->GetPosition(), t->GetPosition()) >= RuleR(Aggro, PetAttackRange) - ) { - break; + if (RuleB(Pets, PetsRequireLoS) && !DoLosChecks(target)) { + mypet->SayString(this, NOT_LEGAL_TARGET); + break; + } + + if (target->IsMezzed()) { + MessageString(Chat::NPCQuestSay, CANNOT_WAKE, mypet->GetCleanName(), target->GetCleanName()); + break; + } + + if (mypet->IsFeared()) + break; //prevent pet from attacking stuff while feared + + if (!mypet->IsAttackAllowed(target)) { + mypet->SayString(this, NOT_LEGAL_TARGET); + break; + } + + // default range is 200, takes Z into account + // really they do something weird where they're added to the aggro list then remove them + // and will attack if they come in range -- too lazy, lets remove exploits for now + if (DistanceSquared(mypet->GetPosition(), target->GetPosition()) >= RuleR(Aggro, PetAttackRange)) { + // they say they're attacking then remove on live ... so they don't really say anything in this case ... + break; + } + + if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + if (target != this && DistanceSquared(mypet->GetPosition(), target->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) { + mypet->SetFeigned(false); + if (mypet->IsPetStop()) { + mypet->SetPetStop(false); + SetPetCommandState(PET_BUTTON_STOP, 0); + } + if (mypet->IsPetRegroup()) { + mypet->SetPetRegroup(false); + SetPetCommandState(PET_BUTTON_REGROUP, 0); + } + + // fix GUI sit button to be unpressed and stop sitting regen + SetPetCommandState(PET_BUTTON_SIT, 0); + if (mypet->GetPetOrder() == SPO_Sit || mypet->GetPetOrder() == SPO_FeignDeath) { + mypet->SetPetOrder(mypet->GetPreviousPetOrder()); + mypet->SetAppearance(eaStanding); + } + + zone->AddAggroMob(); + // classic acts like qattack + int hate = 1; + if (mypet->IsEngaged()) { + auto top = mypet->GetHateMost(); + if (top && top != target) + hate += mypet->GetHateAmount(top) - mypet->GetHateAmount(target) + 100; // should be enough to cause target change + } + mypet->AddToHateList(target, hate, 0, true, false, false, SPELL_UNKNOWN, true); + MessageString(Chat::PetResponse, PET_ATTACKING, mypet->GetCleanName(), target->GetCleanName()); + SetTarget(target); } + } + break; + } + case PET_QATTACK: { + if (mypet->IsFeared()) + break; //prevent pet from attacking stuff while feared - if (RuleB(Pets, PetsRequireLoS) && !DoLosChecks(t)) { - pet->SayString(this, NOT_LEGAL_TARGET); - break; + if (!GetTarget()) { + break; + } + + if (RuleB(Pets, PetsRequireLoS) && !DoLosChecks(GetTarget())) { + mypet->SayString(this, NOT_LEGAL_TARGET); + break; + } + + if (GetTarget()->IsMezzed()) { + MessageString(Chat::NPCQuestSay, CANNOT_WAKE, mypet->GetCleanName(), GetTarget()->GetCleanName()); + break; + } + + if (!mypet->IsAttackAllowed(GetTarget())) { + mypet->SayString(this, NOT_LEGAL_TARGET); + break; + } + + if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + if (GetTarget() != this && DistanceSquaredNoZ(mypet->GetPosition(), GetTarget()->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) { + mypet->SetFeigned(false); + if (mypet->IsPetStop()) { + mypet->SetPetStop(false); + SetPetCommandState(PET_BUTTON_STOP, 0); + } + if (mypet->IsPetRegroup()) { + mypet->SetPetRegroup(false); + SetPetCommandState(PET_BUTTON_REGROUP, 0); + } + + // fix GUI sit button to be unpressed and stop sitting regen + SetPetCommandState(PET_BUTTON_SIT, 0); + if (mypet->GetPetOrder() == SPO_Sit || mypet->GetPetOrder() == SPO_FeignDeath) { + mypet->SetPetOrder(mypet->GetPreviousPetOrder()); + mypet->SetAppearance(eaStanding); + } + + zone->AddAggroMob(); + mypet->AddToHateList(GetTarget(), 1, 0, true, false, false, SPELL_UNKNOWN, true); + MessageString(Chat::PetResponse, PET_ATTACKING, mypet->GetCleanName(), GetTarget()->GetCleanName()); } + } + break; + } + case PET_BACKOFF: { + if (mypet->IsFeared()) break; //keeps pet running while feared - if (t->IsMezzed()) { - MessageString(Chat::NPCQuestSay, CANNOT_WAKE, pet->GetCleanName(), t->GetCleanName()); - break; + if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + mypet->SayString(this, Chat::PetResponse, PET_CALMING); + mypet->WipeHateList(); + mypet->SetTarget(nullptr); + if (mypet->IsPetStop()) { + mypet->SetPetStop(false); + SetPetCommandState(PET_BUTTON_STOP, 0); } + } + break; + } + case PET_HEALTHREPORT: { + if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + MessageString(Chat::PetResponse, PET_REPORT_HP, ConvertArrayF(mypet->GetHPRatio(), val1)); + mypet->ShowBuffs(this); + } + 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(SpellEffect::Charm); + break; + } + else { + SetPet(nullptr); + } - if (!pet->IsAttackAllowed(t)) { - pet->SayString(this, NOT_LEGAL_TARGET); - break; - } + mypet->SayString(this, Chat::PetResponse, PET_GETLOST_STRING); + mypet->CastToNPC()->Depop(); - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; + //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->SayString(PET_GETLOST_STRING); + mypet->CastToNPC()->Depop(); + } + */ - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + break; + } + case PET_GUARDHERE: { + if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF - pet->SetFeigned(false); + if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + if (mypet->IsNPC()) { - if (pet->IsPetStop()) { - pet->SetPetStop(false); - SetPetCommandState(PetButton::Stop, PetButtonState::Off); - } + // Set Sit button to unpressed - send stand anim/end hpregen + mypet->SetFeigned(false); + SetPetCommandState(PET_BUTTON_SIT, 0); + mypet->SetAppearance(eaStanding); - if (pet->IsPetRegroup()) { - pet->SetPetRegroup(false); - SetPetCommandState(PetButton::Regroup, PetButtonState::Off); - } - - SetPetCommandState(PetButton::Sit, PetButtonState::Off); - - if (pet->GetPetOrder() == PetOrder::Sit || pet->GetPetOrder() == PetOrder::Feign) { - pet->SetPetOrder(pet->GetPreviousPetOrder()); - pet->SetAppearance(eaStanding); - } - - zone->AddAggroMob(); - - int hate = 1; // classic acts like qattack - if (pet->IsEngaged()) { - Mob* top = pet->GetHateMost(); - if (top && top != t) { - hate += pet->GetHateAmount(top) - pet->GetHateAmount(t) + 100; + mypet->SayString(this, Chat::PetResponse, PET_GUARDINGLIFE); + mypet->SetPetOrder(SPO_Guard); + mypet->CastToNPC()->SaveGuardSpot(mypet->GetPosition()); + if (!mypet->GetTarget()) // want them to not twitch if they're chasing something down + mypet->StopNavigation(); + if (mypet->IsPetStop()) { + mypet->SetPetStop(false); + SetPetCommandState(PET_BUTTON_STOP, 0); } } - - pet->AddToHateList(t, hate, 0, true, false, false, SPELL_UNKNOWN, true); - MessageString(Chat::PetResponse, PET_ATTACKING, pet->GetCleanName(), t->GetCleanName()); - SetTarget(t); - break; } - case PetCommand::QAttack: { - if ( - pet->IsFeared() || - !GetTarget() || - GetTarget() == this || - !can_use_command || - !( - DistanceSquaredNoZ(pet->GetPosition(), GetTarget()->GetPosition()) <= - (RuleR(Pets, AttackCommandRange) * RuleR(Pets, AttackCommandRange)) - ) - ) { - break; + break; + } + case PET_FOLLOWME: { + if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF + + if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + mypet->SetFeigned(false); + mypet->SayString(this, Chat::PetResponse, PET_FOLLOWING); + mypet->SetPetOrder(SPO_Follow); + + // fix GUI sit button to be unpressed - send stand anim/end hpregen + SetPetCommandState(PET_BUTTON_SIT, 0); + mypet->SetAppearance(eaStanding); + + if (mypet->IsPetStop()) { + mypet->SetPetStop(false); + SetPetCommandState(PET_BUTTON_STOP, 0); } - - if (RuleB(Pets, PetsRequireLoS) && !DoLosChecks(GetTarget())) { - pet->SayString(this, NOT_LEGAL_TARGET); - break; - } - - if (GetTarget()->IsMezzed()) { - MessageString(Chat::NPCQuestSay, CANNOT_WAKE, pet->GetCleanName(), GetTarget()->GetCleanName()); - break; - } - - if (!pet->IsAttackAllowed(GetTarget())) { - pet->SayString(this, NOT_LEGAL_TARGET); - break; - } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - pet->SetFeigned(false); - - if (pet->IsPetStop()) { - pet->SetPetStop(false); - SetPetCommandState(PetButton::Stop, PetButtonState::Off); - } - - if (pet->IsPetRegroup()) { - pet->SetPetRegroup(false); - SetPetCommandState(PetButton::Regroup, PetButtonState::Off); - } - - SetPetCommandState(PetButton::Sit, PetButtonState::Off); - - if (pet->GetPetOrder() == PetOrder::Sit || pet->GetPetOrder() == PetOrder::Feign) { - pet->SetPetOrder(pet->GetPreviousPetOrder()); - pet->SetAppearance(eaStanding); - } - - zone->AddAggroMob(); - pet->AddToHateList(GetTarget(), 1, 0, true, false, false, SPELL_UNKNOWN, true); - MessageString(Chat::PetResponse, PET_ATTACKING, pet->GetCleanName(), GetTarget()->GetCleanName()); - break; } - case PetCommand::BackOff: { - if (pet->IsFeared() || !can_use_command) { - break; + break; + } + case PET_TAUNT: { + if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + if (mypet->CastToNPC()->IsTaunting()) + { + MessageString(Chat::PetResponse, PET_NO_TAUNT); + mypet->CastToNPC()->SetTaunting(false); } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - pet->SayString(this, Chat::PetResponse, PET_CALMING); - pet->WipeHateList(); - pet->SetTarget(nullptr); - - if (pet->IsPetStop()) { - pet->SetPetStop(false); - SetPetCommandState(PetButton::Stop, PetButtonState::Off); + else + { + MessageString(Chat::PetResponse, PET_DO_TAUNT); + mypet->CastToNPC()->SetTaunting(true); } - - break; } - case PetCommand::HealthReport: { - if (!can_use_command) { - break; - } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - MessageString(Chat::PetResponse, PET_REPORT_HP, ConvertArrayF(pet->GetHPRatio(), val1)); - pet->ShowBuffs(this); - break; - } - case PetCommand::GetLost: { - if (pet->Charmed()) { - break; - } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - if (pet->GetPetType() == PetType::Charmed) { - pet->BuffFadeByEffect(SpellEffect::Charm); - break; - } else { - SetPet(nullptr); - } - - pet->SayString(this, Chat::PetResponse, PET_GETLOST_STRING); - pet->CastToNPC()->Depop(); - break; - } - case PetCommand::GuardHere: { - if (pet->IsFeared() || !can_use_command) { - break; - } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - pet->SetFeigned(false); - SetPetCommandState(PetButton::Sit, PetButtonState::Off); - pet->SetAppearance(eaStanding); - pet->SayString(this, Chat::PetResponse, PET_GUARDINGLIFE); - pet->SetPetOrder(PetOrder::Guard); - pet->CastToNPC()->SaveGuardSpot(pet->GetPosition()); - - if (!pet->GetTarget()) { - pet->StopNavigation(); - } - - if (pet->IsPetStop()) { - pet->SetPetStop(false); - SetPetCommandState(PetButton::Stop, PetButtonState::Off); - } - - break; - } - case PetCommand::FollowMe: { - if (pet->IsFeared() || !can_use_command) { - break; - } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - pet->SetFeigned(false); - pet->SayString(this, Chat::PetResponse, PET_FOLLOWING); - pet->SetPetOrder(PetOrder::Follow); - SetPetCommandState(PetButton::Sit, PetButtonState::Off); - pet->SetAppearance(eaStanding); - - if (pet->IsPetStop()) { - pet->SetPetStop(false); - SetPetCommandState(PetButton::Stop, PetButtonState::Off); - } - - break; - } - case PetCommand::Taunt: { - if (!can_use_command) { - break; - } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - MessageString(Chat::PetResponse, pet->CastToNPC()->IsTaunting() ? PET_NO_TAUNT : PET_DO_TAUNT); - pet->CastToNPC()->SetTaunting(!pet->CastToNPC()->IsTaunting()); - break; - } - case PetCommand::TauntOn: { - if (!can_use_command) { - break; - } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - + break; + } + case PET_TAUNT_ON: { + if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { MessageString(Chat::PetResponse, PET_DO_TAUNT); - pet->CastToNPC()->SetTaunting(true); - break; + mypet->CastToNPC()->SetTaunting(true); } - case PetCommand::TauntOff: { - if (!can_use_command) { - break; - } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - + break; + } + case PET_TAUNT_OFF: { + if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { MessageString(Chat::PetResponse, PET_NO_TAUNT); - pet->CastToNPC()->SetTaunting(false); - break; + mypet->CastToNPC()->SetTaunting(false); } - case PetCommand::GuardMe: { - if (pet->IsFeared() || can_use_command) { - break; + break; + } + case PET_GUARDME: { + if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF + + if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + mypet->SetFeigned(false); + mypet->SayString(this, Chat::PetResponse, PET_GUARDME_STRING); + mypet->SetPetOrder(SPO_Follow); + + // Set Sit button to unpressed - send stand anim/end hpregen + SetPetCommandState(PET_BUTTON_SIT, 0); + mypet->SetAppearance(eaStanding); + + if (mypet->IsPetStop()) { + mypet->SetPetStop(false); + SetPetCommandState(PET_BUTTON_STOP, 0); } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - pet->SetFeigned(false); - pet->SayString(this, Chat::PetResponse, PET_GUARDME_STRING); - pet->SetPetOrder(PetOrder::Follow); - SetPetCommandState(PetButton::Sit, PetButtonState::Off); - pet->SetAppearance(eaStanding); - - if (pet->IsPetStop()) { - pet->SetPetStop(false); - SetPetCommandState(PetButton::Stop, PetButtonState::Off); - } - - break; } - case PetCommand::Sit: { - if (pet->IsFeared() || !can_use_command) { - break; + break; + } + case PET_SIT: { + if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF + + if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + if (mypet->GetPetOrder() == SPO_Sit) + { + mypet->SetFeigned(false); + mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING); + mypet->SetPetOrder(mypet->GetPreviousPetOrder()); + mypet->SetAppearance(eaStanding); } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - pet->SetFeigned(false); - pet->SayString(this, Chat::PetResponse, PET_SIT_STRING); - pet->SetPetOrder(pet->GetPetOrder() == PetOrder::Sit ? pet->GetPreviousPetOrder() : PetOrder::Sit); - pet->SetAppearance(pet->GetPetOrder() == PetOrder::Sit ? eaStanding : eaSitting); - - if (pet->GetPetOrder() != PetOrder::Sit) { - pet->SetRunAnimSpeed(0); - - if (!pet->UseBardSpellLogic()) { - pet->InterruptSpell(); - } + else + { + mypet->SetFeigned(false); + mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING); + mypet->SetPetOrder(SPO_Sit); + mypet->SetRunAnimSpeed(0); + if (!mypet->UseBardSpellLogic()) //maybe we can have a bard pet + mypet->InterruptSpell(); //No cast 4 u. //i guess the pet should start casting + mypet->SetAppearance(eaSitting); } - - break; } - case PetCommand::StandUp: { - if (pet->IsFeared() || !can_use_command) { - break; - } + break; + } + case PET_STANDUP: { + if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - pet->SetFeigned(false); - pet->SayString(this, Chat::PetResponse, PET_SIT_STRING); - SetPetCommandState(PetButton::Sit, PetButtonState::Off); - pet->SetPetOrder(pet->GetPreviousPetOrder()); - pet->SetAppearance(eaStanding); - break; + if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + mypet->SetFeigned(false); + mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING); + SetPetCommandState(PET_BUTTON_SIT, 0); + mypet->SetPetOrder(mypet->GetPreviousPetOrder()); + mypet->SetAppearance(eaStanding); } - case PetCommand::SitDown: { - if (pet->IsFeared() || !can_use_command) { - break; - } + break; + } + case PET_SITDOWN: { + if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - pet->SetFeigned(false); - pet->SayString(this, Chat::PetResponse, PET_SIT_STRING); - SetPetCommandState(PetButton::Sit, PetButtonState::On); - pet->SetPetOrder(PetOrder::Sit); - pet->SetRunAnimSpeed(0); - - if (!pet->UseBardSpellLogic()){ - pet->InterruptSpell(); - } - - pet->SetAppearance(eaSitting); - break; + if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + mypet->SetFeigned(false); + mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING); + SetPetCommandState(PET_BUTTON_SIT, 1); + mypet->SetPetOrder(SPO_Sit); + mypet->SetRunAnimSpeed(0); + if (!mypet->UseBardSpellLogic()) //maybe we can have a bard pet + mypet->InterruptSpell(); //No cast 4 u. //i guess the pet should start casting + mypet->SetAppearance(eaSitting); } - case PetCommand::Hold: { - if (!aabonuses.PetCommands[s->command]) { - break; - } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - if (pet->IsHeld()) { - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { + break; + } + case PET_HOLD: { + if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { + if (mypet->IsHeld()) + { + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) MessageString(Chat::PetResponse, PET_HOLD_SET_OFF); - } - - pet->SetHeld(false); - } else { - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { + mypet->SetHeld(false); + } + else + { + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) MessageString(Chat::PetResponse, PET_HOLD_SET_ON); - } - if (m_ClientVersionBit & EQ::versions::maskUFAndLater) { - pet->SayString(this, Chat::PetResponse, PET_NOW_HOLDING); - } else { - pet->SayString(this, Chat::PetResponse, PET_ON_HOLD); - } + if (m_ClientVersionBit & EQ::versions::maskUFAndLater) + mypet->SayString(this, Chat::PetResponse, PET_NOW_HOLDING); + else + mypet->SayString(this, Chat::PetResponse, PET_ON_HOLD); - pet->SetHeld(true); + mypet->SetHeld(true); } - - pet->SetGHeld(false); - SetPetCommandState(PetButton::GreaterHold, PetButtonState::Off); - break; + mypet->SetGHeld(false); + SetPetCommandState(PET_BUTTON_GHOLD, 0); } - case PetCommand::HoldOn: { - if (!pet->IsHeld() || !aabonuses.PetCommands[s->command]) { - break; - } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { + break; + } + case PET_HOLD_ON: { + if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC() && !mypet->IsHeld()) { + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) MessageString(Chat::PetResponse, PET_HOLD_SET_ON); - } - if (m_ClientVersionBit & EQ::versions::maskUFAndLater) { - pet->SayString(this, Chat::PetResponse, PET_NOW_HOLDING); - } else { - pet->SayString(this, Chat::PetResponse, PET_ON_HOLD); - } - - pet->SetHeld(true); - pet->SetGHeld(false); - SetPetCommandState(PetButton::GreaterHold, PetButtonState::Off); - break; + if (m_ClientVersionBit & EQ::versions::maskUFAndLater) + mypet->SayString(this, Chat::PetResponse, PET_NOW_HOLDING); + else + mypet->SayString(this, Chat::PetResponse, PET_ON_HOLD); + mypet->SetHeld(true); + mypet->SetGHeld(false); + SetPetCommandState(PET_BUTTON_GHOLD, 0); } - case PetCommand::HoldOff: { - if (!pet->IsHeld() || !aabonuses.PetCommands[s->command]) { - break; - } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { + break; + } + case PET_HOLD_OFF: { + if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC() && mypet->IsHeld()) { + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) MessageString(Chat::PetResponse, PET_HOLD_SET_OFF); - } - - pet->SetHeld(false); - break; + mypet->SetHeld(false); } - case PetCommand::GreaterHold: { - if (!aabonuses.PetCommands[s->command]) { - break; - } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - if (pet->IsGHeld()) { - if (m_ClientVersionBit & EQ::versions::maskUFAndLater) { + break; + } + case PET_GHOLD: { + if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { + if (mypet->IsGHeld()) + { + if (m_ClientVersionBit & EQ::versions::maskUFAndLater) MessageString(Chat::PetResponse, PET_OFF_GHOLD); - } - - pet->SetGHeld(false); - } else { + mypet->SetGHeld(false); + } + else + { if (m_ClientVersionBit & EQ::versions::maskUFAndLater) { MessageString(Chat::PetResponse, PET_ON_GHOLD); - pet->SayString(this, Chat::PetResponse, PET_GHOLD_ON_MSG); + mypet->SayString(this, Chat::PetResponse, PET_GHOLD_ON_MSG); } else { - pet->SayString(this, Chat::PetResponse, PET_ON_HOLD); + mypet->SayString(this, Chat::PetResponse, PET_ON_HOLD); } - - pet->SetGHeld(true); + mypet->SetGHeld(true); } - - pet->SetHeld(false); - SetPetCommandState(PetButton::Hold, PetButtonState::Off); - break; + mypet->SetHeld(false); + SetPetCommandState(PET_BUTTON_HOLD, 0); } - case PetCommand::GreaterHoldOn: { - if (!aabonuses.PetCommands[s->command]) { - break; - } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - + break; + } + case PET_GHOLD_ON: { + if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { if (m_ClientVersionBit & EQ::versions::maskUFAndLater) { MessageString(Chat::PetResponse, PET_ON_GHOLD); - pet->SayString(this, Chat::PetResponse, PET_GHOLD_ON_MSG); + mypet->SayString(this, Chat::PetResponse, PET_GHOLD_ON_MSG); } else { - pet->SayString(this, Chat::PetResponse, PET_ON_HOLD); + mypet->SayString(this, Chat::PetResponse, PET_ON_HOLD); } - - pet->SetGHeld(true); - pet->SetHeld(false); - SetPetCommandState(PetButton::Hold, PetButtonState::Off); - break; + mypet->SetGHeld(true); + mypet->SetHeld(false); + SetPetCommandState(PET_BUTTON_HOLD, 0); } - case PetCommand::GreaterHoldOff: { - if (!pet->IsGHeld() || !aabonuses.PetCommands[s->command]) { - break; - } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - if (m_ClientVersionBit & EQ::versions::maskUFAndLater) { + break; + } + case PET_GHOLD_OFF: { + if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC() && mypet->IsGHeld()) { + if (m_ClientVersionBit & EQ::versions::maskUFAndLater) MessageString(Chat::PetResponse, PET_OFF_GHOLD); - } - - pet->SetGHeld(false); - break; + mypet->SetGHeld(false); } - case PetCommand::SpellHold: { - if (pet->IsFeared() || !aabonuses.PetCommands[s->command]) { + break; + } + case PET_SPELLHOLD: { + if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { + if (mypet->IsFeared()) break; + if (mypet->IsNoCast()) { + MessageString(Chat::PetResponse, PET_CASTING); + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) + MessageString(Chat::PetResponse, PET_SPELLHOLD_SET_OFF); + mypet->SetNoCast(false); } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - MessageString(Chat::PetResponse, pet->IsNoCast() ? PET_CASTING : PET_NOT_CASTING); - - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { - MessageString(Chat::PetResponse, pet->IsNoCast() ? PET_SPELLHOLD_SET_OFF : PET_SPELLHOLD_SET_ON); + else { + MessageString(Chat::PetResponse, PET_NOT_CASTING); + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) + MessageString(Chat::PetResponse, PET_SPELLHOLD_SET_ON); + mypet->SetNoCast(true); } - - pet->SetNoCast(!pet->IsNoCast()); - break; } - case PetCommand::SpellHoldOn: { - if (pet->IsFeared() || pet->IsNoCast() || !aabonuses.PetCommands[s->command]) { + break; + } + case PET_SPELLHOLD_ON: { + if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { + if (mypet->IsFeared()) break; + if (!mypet->IsNoCast()) { + MessageString(Chat::PetResponse, PET_NOT_CASTING); + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) + MessageString(Chat::PetResponse, PET_SPELLHOLD_SET_ON); + mypet->SetNoCast(true); } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - MessageString(Chat::PetResponse, PET_NOT_CASTING); - - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { - MessageString(Chat::PetResponse, PET_SPELLHOLD_SET_ON); - } - - pet->SetNoCast(true); - break; } - case PetCommand::SpellHoldOff: { - if (pet->IsFeared() || !pet->IsNoCast() || !aabonuses.PetCommands[s->command]) { + break; + } + case PET_SPELLHOLD_OFF: { + if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { + if (mypet->IsFeared()) break; + if (mypet->IsNoCast()) { + MessageString(Chat::PetResponse, PET_CASTING); + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) + MessageString(Chat::PetResponse, PET_SPELLHOLD_SET_OFF); + mypet->SetNoCast(false); } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - MessageString(Chat::PetResponse, PET_CASTING); - - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { - MessageString(Chat::PetResponse, PET_SPELLHOLD_SET_OFF); - } - - pet->SetNoCast(false); - break; } - case PetCommand::Focus: { - if (pet->IsFeared() || !aabonuses.PetCommands[s->command]) { + break; + } + case PET_FOCUS: { + if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { + if (mypet->IsFeared()) break; + if (mypet->IsFocused()) { + MessageString(Chat::PetResponse, PET_NOT_FOCUSING); + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) + MessageString(Chat::PetResponse, PET_FOCUS_SET_OFF); + mypet->SetFocused(false); } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - MessageString(Chat::PetResponse, pet->IsFocused() ? PET_NOT_FOCUSING : PET_NOW_FOCUSING); - - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { - MessageString(Chat::PetResponse, pet->IsFocused() ? PET_FOCUS_SET_OFF : PET_FOCUS_SET_ON); + else { + MessageString(Chat::PetResponse, PET_NOW_FOCUSING); + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) + MessageString(Chat::PetResponse, PET_FOCUS_SET_ON); + mypet->SetFocused(true); } - - pet->SetFocused(!pet->IsFocused()); - break; } - case PetCommand::FocusOn: { - if (pet->IsFeared() || pet->IsFocused() || !aabonuses.PetCommands[s->command]) { + break; + } + case PET_FOCUS_ON: { + if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { + if (mypet->IsFeared()) break; + if (!mypet->IsFocused()) { + MessageString(Chat::PetResponse, PET_NOW_FOCUSING); + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) + MessageString(Chat::PetResponse, PET_FOCUS_SET_ON); + mypet->SetFocused(true); } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - MessageString(Chat::PetResponse, PET_NOW_FOCUSING); - - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { - MessageString(Chat::PetResponse, PET_FOCUS_SET_ON); - } - - pet->SetFocused(true); - break; } - case PetCommand::FocusOff: { - if (pet->IsFeared() || !pet->IsFocused() || !aabonuses.PetCommands[s->command]) { + break; + } + case PET_FOCUS_OFF: { + if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { + if (mypet->IsFeared()) break; + if (mypet->IsFocused()) { + MessageString(Chat::PetResponse, PET_NOT_FOCUSING); + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) + MessageString(Chat::PetResponse, PET_FOCUS_SET_OFF); + mypet->SetFocused(false); } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - MessageString(Chat::PetResponse, PET_NOT_FOCUSING); - - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { - MessageString(Chat::PetResponse, PET_FOCUS_SET_OFF); - } - - pet->SetFocused(false); - break; } - case PetCommand::Feign: { - if (pet->IsFeared() || !aabonuses.PetCommands[s->command]) { + break; + } + + case PET_FEIGN: { + if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { + if (mypet->IsFeared()) break; + + int pet_fd_chance = aabonuses.FeignedMinionChance; + if (zone->random.Int(0, 99) > pet_fd_chance) { + mypet->SetFeigned(false); + entity_list.MessageCloseString(this, false, 200, 10, STRING_FEIGNFAILED, mypet->GetCleanName()); } + else { + bool has_aggro_immunity = GetSpecialAbility(SpecialAbility::AggroImmunity); + mypet->SetSpecialAbility(SpecialAbility::AggroImmunity, 1); + mypet->WipeHateList(); + mypet->SetPetOrder(SPO_FeignDeath); + mypet->SetRunAnimSpeed(0); + mypet->StopNavigation(); + mypet->SetAppearance(eaDead); + mypet->SetFeigned(true); + mypet->SetTarget(nullptr); + if (!mypet->UseBardSpellLogic()) { + mypet->InterruptSpell(); + } - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; + if (!has_aggro_immunity) { + mypet->SetSpecialAbility(SpecialAbility::AggroImmunity, 0); + } + } + } + break; + } + case PET_STOP: { + if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - if (zone->random.Int(0, 99) > aabonuses.FeignedMinionChance) { - pet->SetFeigned(false); - entity_list.MessageCloseString(this, false, 200, 10, STRING_FEIGNFAILED, pet->GetCleanName()); + if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + if (mypet->IsPetStop()) { + mypet->SetPetStop(false); } else { - pet->SetSpecialAbility(SpecialAbility::AggroImmunity, 1); - pet->WipeHateList(); - pet->SetPetOrder(PetOrder::Feign); - pet->SetRunAnimSpeed(0); - pet->StopNavigation(); - pet->SetAppearance(eaDead); - pet->SetFeigned(true); - pet->SetTarget(nullptr); - - if (!pet->UseBardSpellLogic()) { - pet->InterruptSpell(); - } - - if (!GetSpecialAbility(SpecialAbility::AggroImmunity)) { - pet->SetSpecialAbility(SpecialAbility::AggroImmunity, 0); + mypet->SetPetStop(true); + mypet->StopNavigation(); + mypet->SetTarget(nullptr); + if (mypet->IsPetRegroup()) { + mypet->SetPetRegroup(false); + SetPetCommandState(PET_BUTTON_REGROUP, 0); } } - - break; + mypet->SayString(this, Chat::PetResponse, PET_GETLOST_STRING); } - case PetCommand::Stop: { - if (pet->IsFeared() || !can_use_command) { - break; + 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->StopNavigation(); + mypet->SetTarget(nullptr); + mypet->SayString(this, Chat::PetResponse, PET_GETLOST_STRING); + if (mypet->IsPetRegroup()) { + mypet->SetPetRegroup(false); + SetPetCommandState(PET_BUTTON_REGROUP, 0); } + } + break; + } + case PET_STOP_OFF: { + if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; + if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + mypet->SetPetStop(false); + mypet->SayString(this, Chat::PetResponse, PET_GETLOST_STRING); + } + break; + } + case PET_REGROUP: { + if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - if (pet->IsPetStop()) { - pet->SetPetStop(false); + if (aabonuses.PetCommands[PetCommand]) { + if (mypet->IsPetRegroup()) { + mypet->SetPetRegroup(false); + mypet->SayString(this, Chat::PetResponse, PET_OFF_REGROUPING); } else { - pet->SetPetStop(true); - pet->StopNavigation(); - pet->SetTarget(nullptr); - - if (pet->IsPetRegroup()) { - pet->SetPetRegroup(false); - SetPetCommandState(PetButton::Regroup, PetButtonState::Off); + mypet->SetPetRegroup(true); + mypet->SetTarget(nullptr); + mypet->SayString(this, Chat::PetResponse, PET_ON_REGROUPING); + if (mypet->IsPetStop()) { + mypet->SetPetStop(false); + SetPetCommandState(PET_BUTTON_STOP, 0); } } - - pet->SayString(this, Chat::PetResponse, PET_GETLOST_STRING); - break; } - case PetCommand::StopOn: { - if (pet->IsFeared() || pet->IsPetStop() || !can_use_command) { - break; + break; + } + case PET_REGROUP_ON: { + if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF + + if (aabonuses.PetCommands[PetCommand]) { + mypet->SetPetRegroup(true); + mypet->SetTarget(nullptr); + mypet->SayString(this, Chat::PetResponse, PET_ON_REGROUPING); + if (mypet->IsPetStop()) { + mypet->SetPetStop(false); + SetPetCommandState(PET_BUTTON_STOP, 0); } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - pet->SetPetStop(true); - pet->StopNavigation(); - pet->SetTarget(nullptr); - pet->SayString(this, Chat::PetResponse, PET_GETLOST_STRING); - - if (pet->IsPetRegroup()) { - pet->SetPetRegroup(false); - SetPetCommandState(PetButton::Regroup, PetButtonState::Off); - } - - break; } - case PetCommand::StopOff: { - if (pet->IsFeared() || !pet->IsPetStop() || !can_use_command) { - break; - } + break; + } + case PET_REGROUP_OFF: { + if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - pet->SetPetStop(false); - pet->SayString(this, Chat::PetResponse, PET_GETLOST_STRING); - break; - } - case PetCommand::Regroup: { - if (pet->IsFeared() || !aabonuses.PetCommands[s->command]) { - break; - } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - if (pet->IsPetRegroup()) { - pet->SetPetRegroup(false); - pet->SayString(this, Chat::PetResponse, PET_OFF_REGROUPING); - } else { - pet->SetPetRegroup(true); - pet->SetTarget(nullptr); - pet->SayString(this, Chat::PetResponse, PET_ON_REGROUPING); - - if (pet->IsPetStop()) { - pet->SetPetStop(false); - SetPetCommandState(PetButton::Stop, PetButtonState::Off); - } - } - - break; - } - case PetCommand::RegroupOn: { - if (pet->IsFeared() || pet->IsPetRegroup() || !aabonuses.PetCommands[s->command]) { - break; - } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - pet->SetPetRegroup(true); - pet->SetTarget(nullptr); - pet->SayString(this, Chat::PetResponse, PET_ON_REGROUPING); - - if (pet->IsPetStop()) { - pet->SetPetStop(false); - SetPetCommandState(PetButton::Stop, PetButtonState::Off); - } - - break; - } - case PetCommand::RegroupOff: { - if (pet->IsFeared() || !pet->IsPetRegroup() || !aabonuses.PetCommands[s->command]) { - break; - } - - std::function f = [&s]() { - return PetCommand::GetName(s->command); - }; - - parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); - parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - - pet->SetPetRegroup(false); - pet->SayString(this, Chat::PetResponse, PET_OFF_REGROUPING); - break; - } - default: { - LogError("[{}] attempted to use an unknown pet command: [{}]", GetCleanName(), s->command); - break; + if (aabonuses.PetCommands[PetCommand]) { + mypet->SetPetRegroup(false); + mypet->SayString(this, Chat::PetResponse, PET_OFF_REGROUPING); } + break; + } + default: + printf("Client attempted to use a unknown pet command:\n"); + break; } } - void Client::Handle_OP_Petition(const EQApplicationPacket *app) { if (app->size <= 1) diff --git a/zone/common.h b/zone/common.h index 4c187566d..6a11f7255 100644 --- a/zone/common.h +++ b/zone/common.h @@ -854,6 +854,66 @@ struct DataBucketCache uint32_t bucket_expires; }; +// Defines based on the RoF2 Client +#define PET_HEALTHREPORT 0 // 0x00 - /pet health or Pet Window +#define PET_LEADER 1 // 0x01 - /pet leader or Pet Window +#define PET_ATTACK 2 // 0x02 - /pet attack or Pet Window +#define PET_QATTACK 3 // 0x03 - /pet qattack or Pet Window +#define PET_FOLLOWME 4 // 0x04 - /pet follow or Pet Window +#define PET_GUARDHERE 5 // 0x05 - /pet guard or Pet Window +#define PET_SIT 6 // 0x06 - /pet sit or Pet Window +#define PET_SITDOWN 7 // 0x07 - /pet sit on +#define PET_STANDUP 8 // 0x08 - /pet sit off +#define PET_STOP 9 // 0x09 - /pet stop or Pet Window - Not implemented +#define PET_STOP_ON 10 // 0x0a - /pet stop on - Not implemented +#define PET_STOP_OFF 11 // 0x0b - /pet stop off - Not implemented +#define PET_TAUNT 12 // 0x0c - /pet taunt or Pet Window +#define PET_TAUNT_ON 13 // 0x0d - /pet taunt on +#define PET_TAUNT_OFF 14 // 0x0e - /pet taunt off +#define PET_HOLD 15 // 0x0f - /pet hold or Pet Window, won't add to hate list unless attacking +#define PET_HOLD_ON 16 // 0x10 - /pet hold on +#define PET_HOLD_OFF 17 // 0x11 - /pet hold off +#define PET_GHOLD 18 // 0x12 - /pet ghold, will never add to hate list unless told to +#define PET_GHOLD_ON 19 // 0x13 - /pet ghold on +#define PET_GHOLD_OFF 20 // 0x14 - /pet ghold off +#define PET_SPELLHOLD 21 // 0x15 - /pet no cast or /pet spellhold or Pet Window +#define PET_SPELLHOLD_ON 22 // 0x16 - /pet spellhold on +#define PET_SPELLHOLD_OFF 23 // 0x17 - /pet spellhold off +#define PET_FOCUS 24 // 0x18 - /pet focus or Pet Window +#define PET_FOCUS_ON 25 // 0x19 - /pet focus on +#define PET_FOCUS_OFF 26 // 0x1a - /pet focus off +#define PET_FEIGN 27 // 0x1b - /pet feign +#define PET_BACKOFF 28 // 0x1c - /pet back off +#define PET_GETLOST 29 // 0x1d - /pet get lost +#define PET_GUARDME 30 // 0x1e - Same as /pet follow, but different message in older clients - define not from client /pet target in modern clients but doesn't send packet +#define PET_REGROUP 31 // 0x1f - /pet regroup, acts like classic hold. Stops attack and moves back to guard/you but doesn't clear hate list +#define PET_REGROUP_ON 32 // 0x20 - /pet regroup on, turns on regroup +#define PET_REGROUP_OFF 33 // 0x21 - /pet regroup off, turns off regroup +#define PET_MAXCOMMANDS PET_REGROUP_OFF + 1 + +// can change the state of these buttons with a packet +#define PET_BUTTON_SIT 0 +#define PET_BUTTON_STOP 1 +#define PET_BUTTON_REGROUP 2 +#define PET_BUTTON_FOLLOW 3 +#define PET_BUTTON_GUARD 4 +#define PET_BUTTON_TAUNT 5 +#define PET_BUTTON_HOLD 6 +#define PET_BUTTON_GHOLD 7 +#define PET_BUTTON_FOCUS 8 +#define PET_BUTTON_SPELLHOLD 9 + +enum eStandingPetOrder { SPO_Follow, SPO_Sit, SPO_Guard, SPO_FeignDeath }; + +typedef enum { + petFamiliar, //only listens to /pet get lost + petAnimation, //does not listen to any commands + petOther, + petCharmed, + petNPCFollow, + petTargetLock, //remain active as long something is on the hatelist. Don't listen to any commands + petNone = 0xFF // not a pet +} PetTypeOld; #endif