diff --git a/common/emu_constants.cpp b/common/emu_constants.cpp index 670aeb981..ecb1e4c58 100644 --- a/common/emu_constants.cpp +++ b/common/emu_constants.cpp @@ -451,3 +451,23 @@ bool LDoNTheme::IsValid(uint32 theme_id) { return ldon_theme_names.find(theme_id) != ldon_theme_names.end(); } + +std::string PetCommand::GetName(uint8 pet_command) +{ + return IsValid(pet_command) ? pet_commands[pet_command] : "UNKNOWN PET COMMAND"; +} + +bool PetCommand::IsValid(uint8 pet_command) +{ + return pet_commands.find(pet_command) != pet_commands.end(); +} + +std::string PetType::GetName(uint8 pet_type) +{ + return IsValid(pet_type) ? pet_types[pet_type] : "UNKNOWN PET TYPE"; +} + +bool PetType::IsValid(uint8 pet_type) +{ + return pet_types.find(pet_type) != pet_types.end(); +} diff --git a/common/emu_constants.h b/common/emu_constants.h index 085fcd828..0c762ffb8 100644 --- a/common/emu_constants.h +++ b/common/emu_constants.h @@ -792,4 +792,131 @@ namespace BookType { constexpr uint8 ItemInfo = 2; } +namespace PetButton { + constexpr uint8 Sit = 0; + constexpr uint8 Stop = 1; + constexpr uint8 Regroup = 2; + constexpr uint8 Follow = 3; + constexpr uint8 Guard = 4; + constexpr uint8 Taunt = 5; + constexpr uint8 Hold = 6; + constexpr uint8 GreaterHold = 7; + constexpr uint8 Focus = 8; + constexpr uint8 SpellHold = 9; +} + +namespace PetButtonState { + constexpr uint8 Off = 0; + constexpr uint8 On = 1; +} + +namespace PetCommand { + constexpr uint8 HealthReport = 0; // /pet health or Pet Window + constexpr uint8 Leader = 1; // /pet leader or Pet Window + constexpr uint8 Attack = 2; // /pet attack or Pet Window + constexpr uint8 QAttack = 3; // /pet qattack or Pet Window + constexpr uint8 FollowMe = 4; // /pet follow or Pet Window + constexpr uint8 GuardHere = 5; // /pet guard or Pet Window + constexpr uint8 Sit = 6; // /pet sit or Pet Window + constexpr uint8 SitDown = 7; // /pet sit on + constexpr uint8 StandUp = 8; // /pet sit off + constexpr uint8 Stop = 9; // /pet stop or Pet Window - Not implemented + constexpr uint8 StopOn = 10; // /pet stop on - Not implemented + constexpr uint8 StopOff = 11; // /pet stop off - Not implemented + constexpr uint8 Taunt = 12; // /pet taunt or Pet Window + constexpr uint8 TauntOn = 13; // /pet taunt on + constexpr uint8 TauntOff = 14; // /pet taunt off + constexpr uint8 Hold = 15; // /pet hold or Pet Window, won't add to hate list unless attacking + constexpr uint8 HoldOn = 16; // /pet hold on + constexpr uint8 HoldOff = 17; // /pet hold off + constexpr uint8 GreaterHold = 18; // /pet ghold, will never add to hate list unless told to + constexpr uint8 GreaterHoldOn = 19; // /pet ghold on + constexpr uint8 GreaterHoldOff = 20; // /pet ghold off + constexpr uint8 SpellHold = 21; // /pet no cast or /pet spellhold or Pet Window + constexpr uint8 SpellHoldOn = 22; // /pet spellhold on + constexpr uint8 SpellHoldOff = 23; // /pet spellhold off + constexpr uint8 Focus = 24; // /pet focus or Pet Window + constexpr uint8 FocusOn = 25; // /pet focus on + constexpr uint8 FocusOff = 26; // /pet focus off + constexpr uint8 Feign = 27; // /pet feign + constexpr uint8 BackOff = 28; // /pet back off + constexpr uint8 GetLost = 29; // /pet get lost + constexpr uint8 GuardMe = 30; // Same as /pet follow, but different message in older clients + constexpr uint8 Regroup = 31; // /pet regroup, acts like classic hold + constexpr uint8 RegroupOn = 32; // /pet regroup on + constexpr uint8 RegroupOff = 33; // /pet regroup off + constexpr uint8 Max = 34; + + static std::map pet_commands = { + { PetCommand::HealthReport, "Health Report" }, + { PetCommand::Leader, "Leader" }, + { PetCommand::Attack, "Attack" }, + { PetCommand::QAttack, "QAttack" }, + { PetCommand::FollowMe, "Follow Me" }, + { PetCommand::GuardHere, "Guard Here" }, + { PetCommand::Sit, "Sit" }, + { PetCommand::SitDown, "Sit Down" }, + { PetCommand::StandUp, "Stand Up" }, + { PetCommand::Stop, "Stop" }, + { PetCommand::StopOn, "Stop On" }, + { PetCommand::StopOff, "Stop Off" }, + { PetCommand::Taunt, "Taunt" }, + { PetCommand::TauntOn, "Taunt On" }, + { PetCommand::TauntOff, "Taunt Off" }, + { PetCommand::Hold, "Hold" }, + { PetCommand::HoldOn, "Hold On" }, + { PetCommand::HoldOff, "Hold Off" }, + { PetCommand::GreaterHold, "Greater Hold" }, + { PetCommand::GreaterHoldOn, "Greater Hold On" }, + { PetCommand::GreaterHoldOff, "Greater Hold Off" }, + { PetCommand::SpellHold, "Spell Hold" }, + { PetCommand::SpellHoldOn, "Spell Hold On" }, + { PetCommand::SpellHoldOff, "Spell Hold Off" }, + { PetCommand::Focus, "Focus" }, + { PetCommand::FocusOn, "Focus On" }, + { PetCommand::FocusOff, "Focus Off" }, + { PetCommand::Feign, "Feign" }, + { PetCommand::BackOff, "Back Off" }, + { PetCommand::GetLost, "Get Lost" }, + { PetCommand::GuardMe, "Guard Me" }, + { PetCommand::Regroup, "Regroup" }, + { PetCommand::RegroupOn, "Regroup On" }, + { PetCommand::RegroupOff, "Regroup Off" }, + { PetCommand::Max, "Max" } + }; + + std::string GetName(uint8 pet_command); + bool IsValid(uint8 pet_command); +} + +namespace PetOrder { + constexpr uint8 Follow = 0; + constexpr uint8 Sit = 1; + constexpr uint8 Guard = 2; + constexpr uint8 Feign = 3; +} + +namespace PetType { + constexpr uint8 Familiar = 0; + constexpr uint8 Animation = 1; + constexpr uint8 Normal = 2; + constexpr uint8 Charmed = 3; + constexpr uint8 Follow = 4; + constexpr uint8 TargetLock = 5; + constexpr uint8 None = 255; + + static std::map pet_types = { + { PetType::Familiar, "Familiar" }, + { PetType::Animation, "Animation" }, + { PetType::Normal, "Normal" }, + { PetType::Charmed, "Charmed" }, + { PetType::Follow, "Follow" }, + { PetType::TargetLock, "Target Lock" }, + { PetType::None, "None" } + }; + + std::string GetName(uint8 pet_type); + bool IsValid(uint8 pet_type); +} + #endif /*COMMON_EMU_CONSTANTS_H*/ diff --git a/zone/attack.cpp b/zone/attack.cpp index f541c3e92..5a26a9b8f 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -4113,11 +4113,11 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons if (IsPet()) { Mob *owner = GetOwner(); if (owner && owner->IsClient()) { - if (GetPetOrder() == SPO_Sit) { + if (GetPetOrder() == PetOrder::Sit) { SetPetOrder(GetPreviousPetOrder()); } // fix GUI sit button to be unpressed and stop sitting regen - owner->CastToClient()->SetPetCommandState(PET_BUTTON_SIT, 0); + owner->CastToClient()->SetPetCommandState(PetButton::Sit, PetButtonState::Off); SetAppearance(eaStanding); } } @@ -4147,12 +4147,12 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons if (IsClient() && !pet->IsPetStop()) { // if pet was sitting his new mode is previous setting of // follow or guard after the battle (live verified) - if (pet->GetPetOrder() == SPO_Sit) { + if (pet->GetPetOrder() == PetOrder::Sit) { pet->SetPetOrder(pet->GetPreviousPetOrder()); } // fix GUI sit button to be unpressed and stop sitting regen - CastToClient()->SetPetCommandState(PET_BUTTON_SIT, 0); + CastToClient()->SetPetCommandState(PetButton::Sit, PetButtonState::Off); pet->SetAppearance(eaStanding); } diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index d81c3ddf8..640e9ddd1 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1549,7 +1549,7 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon) break; case SE_AddPetCommand: - if (base_value && limit_value < PET_MAXCOMMANDS) + if (base_value && limit_value < PetCommand::Max) newbon->PetCommands[limit_value] = true; break; @@ -1557,7 +1557,7 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon) if (newbon->FeignedMinionChance < base_value) { newbon->FeignedMinionChance = base_value; } - newbon->PetCommands[PET_FEIGN] = true; + newbon->PetCommands[PetCommand::Feign] = true; break; case SE_AdditionalAura: diff --git a/zone/bot.cpp b/zone/bot.cpp index 7f1be1688..2716c88c6 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -99,7 +99,7 @@ Bot::Bot(NPCType *npcTypeData, Client* botOwner) : NPC(npcTypeData, nullptr, glm SetPullingFlag(false); SetReturningFlag(false); SetIsUsingItemClick(false); - m_previous_pet_order = SPO_Guard; + m_previous_pet_order = PetOrder::Guard; rest_timer.Disable(); m_ping_timer.Disable(); @@ -232,7 +232,7 @@ Bot::Bot( SetPullingFlag(false); SetReturningFlag(false); SetIsUsingItemClick(false); - m_previous_pet_order = SPO_Guard; + m_previous_pet_order = PetOrder::Guard; rest_timer.Disable(); m_ping_timer.Disable(); @@ -2313,7 +2313,7 @@ void Bot::AI_Process() bot_owner->SetBotPulling(false); if (GetPet()) { - GetPet()->SetPetOrder(SPO_Follow); + GetPet()->SetPetOrder(PetOrder::Follow); GetPet()->CastToNPC()->SaveGuardSpot(true); } @@ -2569,7 +2569,7 @@ void Bot::DoOutOfCombatChecks(Client* bot_owner, Mob* follow_mob, float leash_di bot_owner->SetBotPulling(false); if (GetPet()) { - GetPet()->SetPetOrder(SPO_Follow); + GetPet()->SetPetOrder(PetOrder::Follow); GetPet()->CastToNPC()->SaveGuardSpot(true); } } @@ -3198,7 +3198,7 @@ bool Bot::IsValidTarget( bot_owner->SetBotPulling(false); if (GetPet()) { - GetPet()->SetPetOrder(SPO_Follow); + GetPet()->SetPetOrder(PetOrder::Follow); GetPet()->CastToNPC()->SaveGuardSpot(true); } } @@ -3233,7 +3233,7 @@ Mob* Bot::GetBotTarget(Client* bot_owner) bot_owner->SetBotPulling(false); if (GetPet()) { - GetPet()->SetPetOrder(SPO_Follow); + GetPet()->SetPetOrder(PetOrder::Follow); GetPet()->CastToNPC()->SaveGuardSpot(true); } } @@ -3269,7 +3269,7 @@ bool Bot::ReturningFlagChecks(Client* bot_owner, Mob* leash_owner, float fm_dist bot_owner->SetBotPulling(false); if (GetPet()) { - GetPet()->SetPetOrder(SPO_Follow); + GetPet()->SetPetOrder(PetOrder::Follow); GetPet()->CastToNPC()->SaveGuardSpot(true); if (HasControllablePet(BotAnimEmpathy::BackOff)) { @@ -3313,7 +3313,7 @@ bool Bot::PullingFlagChecks(Client* bot_owner) { bot_owner->SetBotPulling(false); if (GetPet()) { - GetPet()->SetPetOrder(SPO_Follow); + GetPet()->SetPetOrder(PetOrder::Follow); GetPet()->CastToNPC()->SaveGuardSpot(true); } @@ -3494,7 +3494,7 @@ Client* Bot::SetLeashOwner(Client* bot_owner, Group* bot_group, Raid* raid, uint void Bot::SetOwnerTarget(Client* bot_owner) { if (GetPet() && (PULLING_BOT || RETURNING_BOT)) { - GetPet()->SetPetOrder(SPO_Follow); + GetPet()->SetPetOrder(PetOrder::Follow); } SetAttackFlag(false); @@ -3533,7 +3533,7 @@ void Bot::BotPullerProcess(Client* bot_owner, Raid* raid) { bot_owner->SetBotPulling(false); if (GetPet()) { - GetPet()->SetPetOrder(SPO_Follow); + GetPet()->SetPetOrder(PetOrder::Follow); GetPet()->CastToNPC()->SaveGuardSpot(true); } @@ -3562,7 +3562,7 @@ void Bot::BotPullerProcess(Client* bot_owner, Raid* raid) { if (HasControllablePet(BotAnimEmpathy::Guard)) { m_previous_pet_order = GetPet()->GetPetOrder(); GetPet()->CastToNPC()->SaveGuardSpot(GetPosition()); - GetPet()->SetPetOrder(SPO_Guard); + GetPet()->SetPetOrder(PetOrder::Guard); } } } @@ -13456,6 +13456,6 @@ bool Bot::HasControllablePet(uint8 ranks_required) { } return GetClass() != Class::Enchanter || - GetPet()->GetPetType() != petAnimation || + GetPet()->GetPetType() != PetType::Animation || GetAA(aaAnimationEmpathy) >= ranks_required; } diff --git a/zone/client.cpp b/zone/client.cpp index 17eb2bac5..2fa767d09 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -6415,17 +6415,17 @@ void Client::SuspendMinion(int value) // TODO: These pet command states need to be synced ... // Will just fix them for now if (m_ClientVersionBit & EQ::versions::maskUFAndLater) { - SetPetCommandState(PET_BUTTON_SIT, 0); - SetPetCommandState(PET_BUTTON_STOP, 0); - SetPetCommandState(PET_BUTTON_REGROUP, 0); - SetPetCommandState(PET_BUTTON_FOLLOW, 1); - SetPetCommandState(PET_BUTTON_GUARD, 0); + SetPetCommandState(PetButton::Sit, PetButtonState::Off); + SetPetCommandState(PetButton::Stop, PetButtonState::Off); + SetPetCommandState(PetButton::Regroup, PetButtonState::Off); + SetPetCommandState(PetButton::Follow, PetButtonState::On); + SetPetCommandState(PetButton::Guard, PetButtonState::Off); // Taunt saved on client side for logging on with pet // In our db for when we zone. - SetPetCommandState(PET_BUTTON_HOLD, 0); - SetPetCommandState(PET_BUTTON_GHOLD, 0); - SetPetCommandState(PET_BUTTON_FOCUS, 0); - SetPetCommandState(PET_BUTTON_SPELLHOLD, 0); + SetPetCommandState(PetButton::Hold, PetButtonState::Off); + SetPetCommandState(PetButton::GreaterHold, PetButtonState::Off); + SetPetCommandState(PetButton::Focus, PetButtonState::Off); + SetPetCommandState(PetButton::SpellHold, PetButtonState::Off); } } else @@ -6906,9 +6906,9 @@ void Client::CheckLDoNHail(NPC* n) auto pet = GetPet(); if (pet) { - if (pet->GetPetType() == petCharmed) { + if (pet->GetPetType() == PetType::Charmed) { pet->BuffFadeByEffect(SE_Charm); - } else if (pet->GetPetType() == petNPCFollow) { + } else if (pet->GetPetType() == PetType::Follow) { pet->SetOwnerID(0); } else { pet->Depop(); @@ -9450,12 +9450,15 @@ void Client::ProcessAggroMeter() } } -void Client::SetPetCommandState(int button, int state) +void Client::SetPetCommandState(uint8 button, uint8 state) { auto app = new EQApplicationPacket(OP_PetCommandState, sizeof(PetCommandState_Struct)); - auto pcs = (PetCommandState_Struct *)app->pBuffer; - pcs->button_id = button; - pcs->state = state; + + auto s = (PetCommandState_Struct*) app->pBuffer; + + s->button_id = button; + s->state = state; + FastQueuePacket(&app); } diff --git a/zone/client.h b/zone/client.h index 87a9c1d96..d5e8f3ef4 100644 --- a/zone/client.h +++ b/zone/client.h @@ -524,7 +524,7 @@ public: inline const InspectMessage_Struct& GetInspectMessage() const { return m_inspect_message; } void ReloadExpansionProfileSetting(); - void SetPetCommandState(int button, int state); + void SetPetCommandState(uint8 button, uint8 state); bool AutoAttackEnabled() const { return auto_attack; } bool AutoFireEnabled() const { return auto_fire; } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index bdcbbc13a..1f273a191 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -955,17 +955,17 @@ void Client::CompleteConnect() // TODO: load these states // We at least will set them to the correct state for now if (m_ClientVersionBit & EQ::versions::maskUFAndLater && GetPet()) { - SetPetCommandState(PET_BUTTON_SIT, 0); - SetPetCommandState(PET_BUTTON_STOP, 0); - SetPetCommandState(PET_BUTTON_REGROUP, 0); - SetPetCommandState(PET_BUTTON_FOLLOW, 1); - SetPetCommandState(PET_BUTTON_GUARD, 0); + SetPetCommandState(PetButton::Sit, PetButtonState::Off); + SetPetCommandState(PetButton::Stop, PetButtonState::Off); + SetPetCommandState(PetButton::Regroup, PetButtonState::Off); + SetPetCommandState(PetButton::Follow, PetButtonState::On); + SetPetCommandState(PetButton::Guard, PetButtonState::Off); // Taunt saved on client side for logging on with pet // In our db for when we zone. - SetPetCommandState(PET_BUTTON_HOLD, 0); - SetPetCommandState(PET_BUTTON_GHOLD, 0); - SetPetCommandState(PET_BUTTON_FOCUS, 0); - SetPetCommandState(PET_BUTTON_SPELLHOLD, 0); + SetPetCommandState(PetButton::Hold, PetButtonState::Off); + SetPetCommandState(PetButton::GreaterHold, PetButtonState::Off); + SetPetCommandState(PetButton::Focus, PetButtonState::Off); + SetPetCommandState(PetButton::SpellHold, PetButtonState::Off); } database.LoadAuras(this); // this ends up spawning them so probably safer to load this later (here) @@ -11073,661 +11073,913 @@ void Client::Handle_OP_PDeletePetition(const EQApplicationPacket *app) return; } + void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) { if (app->size != sizeof(PetCommand_Struct)) { LogError("Wrong size: OP_PetCommands, size=[{}], expected [{}]", app->size, sizeof(PetCommand_Struct)); return; } - char val1[20] = { 0 }; - PetCommand_Struct* pet = (PetCommand_Struct*)app->pBuffer; - Mob* mypet = GetPet(); - Mob *target = entity_list.GetMob(pet->target); - if (!mypet || pet->command == PET_LEADER) { - if (pet->command == PET_LEADER) { + auto* s = (PetCommand_Struct*) app->pBuffer; + + char val1[20] = { 0 }; + + Mob* pet = GetPet(); + Mob* t = entity_list.GetMob(s->target); + + if (!pet || s->command == PetCommand::Leader) { + if (s->command == PetCommand::Leader) { // we either send the ID of an NPC we're interested in or no ID for our own pet - 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()); + 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()); } } return; } - if (mypet->GetPetType() == petTargetLock && (pet->command != PET_HEALTHREPORT && pet->command != PET_GETLOST)) + if (!pet->IsNPC()) { 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 (mypet->GetPetType() == petFamiliar && pet->command != PET_GETLOST) + if (pet->GetPetType() == PetType::Familiar && s->command != PetCommand::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; } - */ - switch (PetCommand) - { - case PET_ATTACK: { - if (!target) - break; + const bool can_use_command = ( + (pet->GetPetType() == PetType::Animation && aabonuses.PetCommands[s->command]) || + pet->GetPetType() != PetType::Animation + ); - 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); + 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; } - } - break; - } - case PET_QATTACK: { - if (mypet->IsFeared()) - break; //prevent pet from attacking stuff while feared - 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()); + if (RuleB(Pets, PetsRequireLoS) && !DoLosChecks(t)) { + pet->SayString(this, NOT_LEGAL_TARGET); + break; } - } - break; - } - case PET_BACKOFF: { - if (mypet->IsFeared()) break; //keeps pet running while feared - 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); + if (t->IsMezzed()) { + MessageString(Chat::NPCQuestSay, CANNOT_WAKE, pet->GetCleanName(), t->GetCleanName()); + break; } - } - 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(SE_Charm); - break; - } - else { - SetPet(nullptr); - } - mypet->SayString(this, Chat::PetResponse, PET_GETLOST_STRING); - mypet->CastToNPC()->Depop(); + if (!pet->IsAttackAllowed(t)) { + pet->SayString(this, NOT_LEGAL_TARGET); + break; + } - //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(); - } - */ + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; - break; - } - case PET_GUARDHERE: { - 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 ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { - if (mypet->IsNPC()) { + pet->SetFeigned(false); - // Set Sit button to unpressed - send stand anim/end hpregen - mypet->SetFeigned(false); - SetPetCommandState(PET_BUTTON_SIT, 0); - mypet->SetAppearance(eaStanding); + if (pet->IsPetStop()) { + pet->SetPetStop(false); + SetPetCommandState(PetButton::Stop, PetButtonState::Off); + } - 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); + 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; } } - } - 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); - } + pet->AddToHateList(t, hate, 0, true, false, false, SPELL_UNKNOWN, true); + MessageString(Chat::PetResponse, PET_ATTACKING, pet->GetCleanName(), t->GetCleanName()); + SetTarget(t); + 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); + case PetCommand::QAttack: { + if ( + pet->IsFeared() || + !GetTarget() || + GetTarget() == this || + !can_use_command || + !( + DistanceSquaredNoZ(pet->GetPosition(), GetTarget()->GetPosition()) <= + (RuleR(Pets, AttackCommandRange) * RuleR(Pets, AttackCommandRange)) + ) + ) { + break; } - else - { - MessageString(Chat::PetResponse, PET_DO_TAUNT); - mypet->CastToNPC()->SetTaunting(true); + + 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; } - break; - } - case PET_TAUNT_ON: { - if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + case PetCommand::BackOff: { + 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->SayString(this, Chat::PetResponse, PET_CALMING); + pet->WipeHateList(); + pet->SetTarget(nullptr); + + if (pet->IsPetStop()) { + pet->SetPetStop(false); + SetPetCommandState(PetButton::Stop, PetButtonState::Off); + } + + 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(SE_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); + MessageString(Chat::PetResponse, PET_DO_TAUNT); - mypet->CastToNPC()->SetTaunting(true); + pet->CastToNPC()->SetTaunting(true); + break; } - break; - } - case PET_TAUNT_OFF: { - if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + 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); + MessageString(Chat::PetResponse, PET_NO_TAUNT); - mypet->CastToNPC()->SetTaunting(false); + pet->CastToNPC()->SetTaunting(false); + 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); + case PetCommand::GuardMe: { + 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_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); } - 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::Sit: { + if (pet->IsFeared() || !can_use_command) { + break; } - } - break; - } - case PET_STANDUP: { - 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_SIT_STRING); - SetPetCommandState(PET_BUTTON_SIT, 0); - mypet->SetPetOrder(mypet->GetPreviousPetOrder()); - mypet->SetAppearance(eaStanding); - } - break; - } - case PET_SITDOWN: { - 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->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); + 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(); + } + } + + break; } - break; - } - case PET_HOLD: { - if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { - if (mypet->IsHeld()) - { - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) + case PetCommand::StandUp: { + 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_SIT_STRING); + SetPetCommandState(PetButton::Sit, PetButtonState::Off); + pet->SetPetOrder(pet->GetPreviousPetOrder()); + pet->SetAppearance(eaStanding); + break; + } + case PetCommand::SitDown: { + 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_SIT_STRING); + SetPetCommandState(PetButton::Sit, PetButtonState::On); + pet->SetPetOrder(PetOrder::Sit); + pet->SetRunAnimSpeed(0); + + if (!pet->UseBardSpellLogic()){ + pet->InterruptSpell(); + } + + pet->SetAppearance(eaSitting); + break; + } + 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) { MessageString(Chat::PetResponse, PET_HOLD_SET_OFF); - mypet->SetHeld(false); - } - else - { - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) + } + + pet->SetHeld(false); + } else { + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { MessageString(Chat::PetResponse, PET_HOLD_SET_ON); + } - if (m_ClientVersionBit & EQ::versions::maskUFAndLater) - mypet->SayString(this, Chat::PetResponse, PET_NOW_HOLDING); - else - mypet->SayString(this, Chat::PetResponse, PET_ON_HOLD); + if (m_ClientVersionBit & EQ::versions::maskUFAndLater) { + pet->SayString(this, Chat::PetResponse, PET_NOW_HOLDING); + } else { + pet->SayString(this, Chat::PetResponse, PET_ON_HOLD); + } - mypet->SetHeld(true); + pet->SetHeld(true); } - mypet->SetGHeld(false); - SetPetCommandState(PET_BUTTON_GHOLD, 0); + + pet->SetGHeld(false); + SetPetCommandState(PetButton::GreaterHold, PetButtonState::Off); + break; } - break; - } - case PET_HOLD_ON: { - if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC() && !mypet->IsHeld()) { - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) + 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) { MessageString(Chat::PetResponse, PET_HOLD_SET_ON); - - 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); - } - 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); - mypet->SetHeld(false); - } - 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); - mypet->SetGHeld(false); } - else - { + + 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; + } + 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) { + MessageString(Chat::PetResponse, PET_HOLD_SET_OFF); + } + + pet->SetHeld(false); + break; + } + 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) { + MessageString(Chat::PetResponse, PET_OFF_GHOLD); + } + + pet->SetGHeld(false); + } else { if (m_ClientVersionBit & EQ::versions::maskUFAndLater) { MessageString(Chat::PetResponse, PET_ON_GHOLD); - mypet->SayString(this, Chat::PetResponse, PET_GHOLD_ON_MSG); + pet->SayString(this, Chat::PetResponse, PET_GHOLD_ON_MSG); } else { - mypet->SayString(this, Chat::PetResponse, PET_ON_HOLD); + pet->SayString(this, Chat::PetResponse, PET_ON_HOLD); } - mypet->SetGHeld(true); + + pet->SetGHeld(true); } - mypet->SetHeld(false); - SetPetCommandState(PET_BUTTON_HOLD, 0); + + pet->SetHeld(false); + SetPetCommandState(PetButton::Hold, PetButtonState::Off); + break; } - break; - } - case PET_GHOLD_ON: { - if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { + 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); + if (m_ClientVersionBit & EQ::versions::maskUFAndLater) { MessageString(Chat::PetResponse, PET_ON_GHOLD); - mypet->SayString(this, Chat::PetResponse, PET_GHOLD_ON_MSG); + pet->SayString(this, Chat::PetResponse, PET_GHOLD_ON_MSG); } else { - mypet->SayString(this, Chat::PetResponse, PET_ON_HOLD); + pet->SayString(this, Chat::PetResponse, PET_ON_HOLD); } - mypet->SetGHeld(true); - mypet->SetHeld(false); - SetPetCommandState(PET_BUTTON_HOLD, 0); + + pet->SetGHeld(true); + pet->SetHeld(false); + SetPetCommandState(PetButton::Hold, PetButtonState::Off); + break; } - break; - } - case PET_GHOLD_OFF: { - if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC() && mypet->IsGHeld()) { - if (m_ClientVersionBit & EQ::versions::maskUFAndLater) + 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) { MessageString(Chat::PetResponse, PET_OFF_GHOLD); - mypet->SetGHeld(false); - } - 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); } - else { - MessageString(Chat::PetResponse, PET_NOT_CASTING); - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) - MessageString(Chat::PetResponse, PET_SPELLHOLD_SET_ON); - mypet->SetNoCast(true); - } - } - 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); - } - } - 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); - } - } - 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); - } - else { - MessageString(Chat::PetResponse, PET_NOW_FOCUSING); - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) - MessageString(Chat::PetResponse, PET_FOCUS_SET_ON); - mypet->SetFocused(true); - } - } - 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); - } - } - 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); - } - } - 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(); - } - - if (!has_aggro_immunity) { - mypet->SetSpecialAbility(SpecialAbility::AggroImmunity, 0); - } - } + pet->SetGHeld(false); + break; } - break; - } - case PET_STOP: { - if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF + case PetCommand::SpellHold: { + if (pet->IsFeared() || !aabonuses.PetCommands[s->command]) { + break; + } - if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { - if (mypet->IsPetStop()) { - mypet->SetPetStop(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); + } + + pet->SetNoCast(!pet->IsNoCast()); + break; + } + case PetCommand::SpellHoldOn: { + if (pet->IsFeared() || pet->IsNoCast() || !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); + + 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; + } + + 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; + } + + 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); + } + + pet->SetFocused(!pet->IsFocused()); + break; + } + case PetCommand::FocusOn: { + if (pet->IsFeared() || pet->IsFocused() || !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); + + 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; + } + + 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; + } + + 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 (zone->random.Int(0, 99) > aabonuses.FeignedMinionChance) { + pet->SetFeigned(false); + entity_list.MessageCloseString(this, false, 200, 10, STRING_FEIGNFAILED, pet->GetCleanName()); } else { - mypet->SetPetStop(true); - mypet->StopNavigation(); - mypet->SetTarget(nullptr); - if (mypet->IsPetRegroup()) { - mypet->SetPetRegroup(false); - SetPetCommandState(PET_BUTTON_REGROUP, 0); + 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->SayString(this, Chat::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->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 PetCommand::Stop: { + if (pet->IsFeared() || !can_use_command) { + break; } - } - 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->SayString(this, Chat::PetResponse, PET_GETLOST_STRING); - } - break; - } - case PET_REGROUP: { - if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; - if (aabonuses.PetCommands[PetCommand]) { - if (mypet->IsPetRegroup()) { - mypet->SetPetRegroup(false); - mypet->SayString(this, Chat::PetResponse, PET_OFF_REGROUPING); + 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); } else { - 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->SetPetStop(true); + pet->StopNavigation(); + pet->SetTarget(nullptr); + + if (pet->IsPetRegroup()) { + pet->SetPetRegroup(false); + SetPetCommandState(PetButton::Regroup, PetButtonState::Off); } } - } - 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); + 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_OFF: { - if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF - if (aabonuses.PetCommands[PetCommand]) { - mypet->SetPetRegroup(false); - mypet->SayString(this, Chat::PetResponse, PET_OFF_REGROUPING); + 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; + } + + 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; } - break; - } - default: - printf("Client attempted to use a unknown pet command:\n"); - break; } } diff --git a/zone/common.h b/zone/common.h index 10c17b7a6..5c5e12f79 100644 --- a/zone/common.h +++ b/zone/common.h @@ -3,6 +3,7 @@ #include "../common/types.h" #include "../common/spdat.h" +#include "../common/emu_constants.h" #include @@ -45,55 +46,6 @@ namespace Archetype { //Maximum distance from a zone point if zone was specified #define ZONEPOINT_ZONE_RANGE 40000.0f -// 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 - #define AURA_HARDCAP 2 #define WEAPON_STANCE_TYPE_MAX 2 @@ -617,7 +569,7 @@ struct StatBonuses { uint8 TradeSkillMastery; // Allow number of tradeskills to exceed 200 skill. int16 NoBreakAESneak; // Percent value int16 FeignedCastOnChance; // Percent Value - bool PetCommands[PET_MAXCOMMANDS]; // SPA 267 + bool PetCommands[PetCommand::Max]; // SPA 267 int FeignedMinionChance; // SPA 281 base1 = chance, just like normal FD int GrantForage; // affects max skill of forage as well as granting non-forage classes forage int aura_slots; @@ -781,16 +733,6 @@ enum { GridRandomPath }; -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 -} PetType; - typedef enum { SingleTarget, // causes effect to spell_target AETarget, // causes effect in aerange of target + target diff --git a/zone/embparser.cpp b/zone/embparser.cpp index bd4eabc0d..6d220b8d8 100644 --- a/zone/embparser.cpp +++ b/zone/embparser.cpp @@ -207,6 +207,7 @@ const char* QuestEventSubroutines[_LargestEventID] = { "EVENT_AA_LOSS", "EVENT_SPELL_BLOCKED", "EVENT_READ_ITEM", + "EVENT_PET_COMMAND", // Add new events before these or Lua crashes "EVENT_SPELL_EFFECT_BOT", @@ -2532,6 +2533,12 @@ void PerlembParser::ExportEventVariables( break; } + case EVENT_PET_COMMAND: { + ExportVar(package_name.c_str(), "pet_command", extra_data); + ExportVar(package_name.c_str(), "pet_command_name", data); + break; + } + default: { break; } diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index c305532f7..feedab7fd 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -6039,6 +6039,16 @@ perl::array Perl__get_timers(Mob* m) return a; } +std::string Perl__get_pet_command_name(uint8 pet_command) +{ + return PetCommand::GetName(pet_command); +} + +std::string Perl__get_pet_type_name(uint8 pet_type) +{ + return PetType::GetName(pet_type); +} + void perl_register_quest() { perl::interpreter perl(PERL_GET_THX); @@ -6729,6 +6739,8 @@ void perl_register_quest() package.add("getgroupidbycharid", &Perl__getgroupidbycharid); package.add("getinventoryslotname", &Perl__getinventoryslotname); package.add("get_paused_timers", &Perl__get_paused_timers); + package.add("get_pet_command_name", &Perl__get_pet_command_name); + package.add("get_pet_type_name", &Perl__get_pet_type_name); package.add("getraididbycharid", &Perl__getraididbycharid); package.add("get_race_bitmask", &Perl__get_race_bitmask); package.add("get_recipe_component_item_ids", &Perl__GetRecipeComponentItemIDs); diff --git a/zone/event_codes.h b/zone/event_codes.h index aeee13393..0d14f565d 100644 --- a/zone/event_codes.h +++ b/zone/event_codes.h @@ -145,6 +145,7 @@ typedef enum { EVENT_AA_LOSS, EVENT_SPELL_BLOCKED, EVENT_READ_ITEM, + EVENT_PET_COMMAND, // Add new events before these or Lua crashes EVENT_SPELL_EFFECT_BOT, diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index ae3242885..ae8c4b2af 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -5701,6 +5701,16 @@ luabind::object lua_get_timers(lua_State* L, Mob* m) { return t; } +std::string lua_get_pet_command_name(uint8 pet_command) +{ + return PetCommand::GetName(pet_command); +} + +std::string lua_get_pet_type_name(uint8 pet_type) +{ + return PetType::GetName(pet_type); +} + #define LuaCreateNPCParse(name, c_type, default_value) do { \ cur = table[#name]; \ if(luabind::type(cur) != LUA_TNIL) { \ @@ -6514,6 +6524,8 @@ luabind::scope lua_register_general() { luabind::def("handin", &lua_handin), luabind::def("get_paused_timers", &lua_get_paused_timers), luabind::def("get_timers", &lua_get_timers), + luabind::def("get_pet_command_name", &lua_get_pet_command_name), + luabind::def("get_pet_type_name", &lua_get_pet_type_name), /* Cross Zone */ @@ -6979,7 +6991,8 @@ luabind::scope lua_register_events() { luabind::value("entity_variable_set", static_cast(EVENT_ENTITY_VARIABLE_SET)), luabind::value("entity_variable_update", static_cast(EVENT_ENTITY_VARIABLE_UPDATE)), luabind::value("aa_loss", static_cast(EVENT_AA_LOSS)), - luabind::value("read", static_cast(EVENT_READ_ITEM)) + luabind::value("read", static_cast(EVENT_READ_ITEM)), + luabind::value("pet_command", static_cast(EVENT_PET_COMMAND)) )]; } diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index 23890987e..e23eb2d03 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -1241,12 +1241,12 @@ float Lua_Mob::GetAssistRange() { return self->GetAssistRange(); } -void Lua_Mob::SetPetOrder(int order) { +void Lua_Mob::SetPetOrder(uint8 pet_order) { Lua_Safe_Call_Void(); - self->SetPetOrder(static_cast(order)); + self->SetPetOrder(pet_order); } -int Lua_Mob::GetPetOrder() { +uint8 Lua_Mob::GetPetOrder() { Lua_Safe_Call_Int(); return self->GetPetOrder(); } @@ -3512,6 +3512,24 @@ luabind::object Lua_Mob::GetTimers(lua_State* L) { return t; } +uint8 Lua_Mob::GetPetType() +{ + Lua_Safe_Call_Int(); + return self->GetPetType(); +} + +std::string Lua_Mob::GetPetTypeName() +{ + Lua_Safe_Call_String(); + return PetType::GetName(self->GetPetType()); +} + +void Lua_Mob::SetPetType(uint8 pet_type) +{ + Lua_Safe_Call_Void(); + self->SetPetType(pet_type); +} + luabind::scope lua_register_mob() { return luabind::class_("Mob") .def(luabind::constructor<>()) @@ -3854,7 +3872,9 @@ luabind::scope lua_register_mob() { .def("GetPR", &Lua_Mob::GetPR) .def("GetPausedTimers", &Lua_Mob::GetPausedTimers) .def("GetPet", &Lua_Mob::GetPet) - .def("GetPetOrder", (int(Lua_Mob::*)(void))&Lua_Mob::GetPetOrder) + .def("GetPetOrder", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetPetOrder) + .def("GetPetType", &Lua_Mob::GetPetType) + .def("GetPetTypeName", &Lua_Mob::GetPetTypeName) .def("GetPhR", &Lua_Mob::GetPhR) .def("GetRace", &Lua_Mob::GetRace) .def("GetRaceName", &Lua_Mob::GetRaceName) @@ -4049,7 +4069,8 @@ luabind::scope lua_register_mob() { .def("SetMana", &Lua_Mob::SetMana) .def("SetOOCRegen", (void(Lua_Mob::*)(int64))&Lua_Mob::SetOOCRegen) .def("SetPet", &Lua_Mob::SetPet) - .def("SetPetOrder", (void(Lua_Mob::*)(int))&Lua_Mob::SetPetOrder) + .def("SetPetOrder", (void(Lua_Mob::*)(uint8))&Lua_Mob::SetPetOrder) + .def("SetPetType", &Lua_Mob::SetPetType) .def("SetPseudoRoot", (void(Lua_Mob::*)(bool))&Lua_Mob::SetPseudoRoot) .def("SetRace", (void(Lua_Mob::*)(uint16))&Lua_Mob::SetRace) .def("SetRunning", (void(Lua_Mob::*)(bool))&Lua_Mob::SetRunning) diff --git a/zone/lua_mob.h b/zone/lua_mob.h index f95794a10..b5019aa5f 100644 --- a/zone/lua_mob.h +++ b/zone/lua_mob.h @@ -280,8 +280,8 @@ public: bool IsAIControlled(); float GetAggroRange(); float GetAssistRange(); - void SetPetOrder(int order); - int GetPetOrder(); + void SetPetOrder(uint8 pet_order); + uint8 GetPetOrder(); bool IsRoamer(); bool IsRooted(); bool IsEngaged(); @@ -614,6 +614,9 @@ public: void BuffFadeSongs(); luabind::object GetPausedTimers(lua_State* L); luabind::object GetTimers(lua_State* L); + uint8 GetPetType(); + std::string GetPetTypeName(); + void SetPetType(uint8 pet_type); }; #endif diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index 0f8dded50..c3f37aec5 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -188,7 +188,8 @@ const char *LuaEvents[_LargestEventID] = { "event_entity_variable_update", "event_aa_loss", "event_spell_blocked", - "event_read_item" + "event_read_item", + "event_pet_command" }; extern Zone *zone; @@ -264,6 +265,7 @@ LuaParser::LuaParser() { NPCArgumentDispatch[EVENT_ENTITY_VARIABLE_SET] = handle_npc_entity_variable; NPCArgumentDispatch[EVENT_ENTITY_VARIABLE_UPDATE] = handle_npc_entity_variable; NPCArgumentDispatch[EVENT_SPELL_BLOCKED] = handle_npc_spell_blocked; + NPCArgumentDispatch[EVENT_PET_COMMAND] = handle_npc_pet_command; PlayerArgumentDispatch[EVENT_SAY] = handle_player_say; PlayerArgumentDispatch[EVENT_ENVIRONMENTAL_DAMAGE] = handle_player_environmental_damage; @@ -355,6 +357,7 @@ LuaParser::LuaParser() { PlayerArgumentDispatch[EVENT_SPELL_BLOCKED] = handle_player_spell_blocked; PlayerArgumentDispatch[EVENT_READ_ITEM] = handle_player_read_item; PlayerArgumentDispatch[EVENT_CONNECT] = handle_player_connect; + PlayerArgumentDispatch[EVENT_PET_COMMAND] = handle_player_pet_command; ItemArgumentDispatch[EVENT_ITEM_CLICK] = handle_item_click; ItemArgumentDispatch[EVENT_ITEM_CLICK_CAST] = handle_item_click; diff --git a/zone/lua_parser_events.cpp b/zone/lua_parser_events.cpp index 153775e78..68dd7ca2a 100644 --- a/zone/lua_parser_events.cpp +++ b/zone/lua_parser_events.cpp @@ -668,6 +668,23 @@ void handle_npc_spell_blocked( lua_setfield(L, -2, "cast_spell"); } +void handle_npc_pet_command( + QuestInterface *parse, + lua_State* L, + NPC* npc, + Mob *init, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) +{ + lua_pushinteger(L, extra_data); + lua_setfield(L, -2, "pet_command"); + + lua_pushstring(L, data.c_str()); + lua_setfield(L, -2, "pet_command_name"); +} + // Player void handle_player_say( QuestInterface *parse, @@ -1829,6 +1846,22 @@ void handle_player_connect( lua_setfield(L, -2, "is_first_login"); } +void handle_player_pet_command( + QuestInterface *parse, + lua_State* L, + Client* client, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) +{ + lua_pushinteger(L, extra_data); + lua_setfield(L, -2, "pet_command"); + + lua_pushstring(L, data.c_str()); + lua_setfield(L, -2, "pet_command_name"); +} + // Item void handle_item_click( QuestInterface *parse, diff --git a/zone/lua_parser_events.h b/zone/lua_parser_events.h index 0adb7ba99..79135bd6e 100644 --- a/zone/lua_parser_events.h +++ b/zone/lua_parser_events.h @@ -262,6 +262,16 @@ void handle_npc_spell_blocked( std::vector *extra_pointers ); +void handle_npc_pet_command( + QuestInterface *parse, + lua_State* L, + NPC* npc, + Mob *init, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); + // Player void handle_player_say( QuestInterface *parse, @@ -875,6 +885,15 @@ void handle_player_connect( std::vector *extra_pointers ); +void handle_player_pet_command( + QuestInterface *parse, + lua_State* L, + Client* client, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); + // Item void handle_item_click( QuestInterface *parse, diff --git a/zone/mob.cpp b/zone/mob.cpp index 7d6f3229e..0a167201d 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -392,7 +392,7 @@ Mob::Mob( spellbonuses.AssistRange = -1; SetPetID(0); SetOwnerID(0); - SetPetType(petNone); // default to not a pet + SetPetType(PetType::None); // default to not a pet SetPetPower(0); held = false; gheld = false; @@ -454,8 +454,8 @@ Mob::Mob( weaponstance.itembonus_buff_spell_id = 0; weaponstance.aabonus_buff_spell_id = 0; - pStandingPetOrder = SPO_Follow; - m_previous_pet_order = SPO_Follow; + m_pet_order = PetOrder::Follow; + m_previous_pet_order = PetOrder::Follow; pseudo_rooted = false; nobuff_invisible = 0; @@ -623,7 +623,7 @@ bool Mob::HasAnInvisibilityEffect() { void Mob::BreakCharmPetIfConditionsMet() { auto pet = GetPet(); - if (pet && pet->GetPetType() == petCharmed && HasAnInvisibilityEffect()) { + if (pet && pet->GetPetType() == PetType::Charmed && HasAnInvisibilityEffect()) { if (RuleB(Pets, LivelikeBreakCharmOnInvis) || IsInvisible(pet)) { pet->BuffFadeByEffect(SE_Charm); } @@ -655,14 +655,14 @@ void Mob::CalcInvisibleLevel() BreakCharmPetIfConditionsMet(); } -void Mob::SetPetOrder(eStandingPetOrder i) { - if (i == SPO_Sit || i == SPO_FeignDeath) { - if (pStandingPetOrder == SPO_Follow || pStandingPetOrder == SPO_Guard) { - m_previous_pet_order = pStandingPetOrder; +void Mob::SetPetOrder(uint8 pet_order) { + if (pet_order == PetOrder::Sit || pet_order == PetOrder::Feign) { + if (m_pet_order == PetOrder::Follow || m_pet_order == PetOrder::Guard) { + m_previous_pet_order = m_pet_order; } } - pStandingPetOrder = i; + m_pet_order = pet_order; } void Mob::SetInvisible(uint8 state, bool set_on_bonus_calc) { @@ -4567,8 +4567,8 @@ void Mob::SetOwnerID(uint16 new_owner_id) { if ( !ownerid && IsNPC() && - GetPetType() != petCharmed && - GetPetType() != petNone + GetPetType() != PetType::Charmed && + GetPetType() != PetType::None ) { Depop(); } diff --git a/zone/mob.h b/zone/mob.h index 193d8aae2..ca0abe268 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -98,7 +98,6 @@ class Mob : public Entity { public: enum CLIENT_CONN_STATUS { CLIENT_CONNECTING, CLIENT_CONNECTED, CLIENT_LINKDEAD, CLIENT_KICKED, DISCONNECTED, CLIENT_ERROR, CLIENT_CONNECTINGALL }; - enum eStandingPetOrder { SPO_Follow, SPO_Sit, SPO_Guard, SPO_FeignDeath }; struct MobSpecialAbility { MobSpecialAbility() { @@ -601,7 +600,7 @@ public: inline const char* GetName() const { return name; } inline const char* GetOrigName() const { return orig_name; } inline const char* GetLastName() const { return lastname; } - inline const eStandingPetOrder GetPreviousPetOrder() const { return m_previous_pet_order; } + inline const uint8 GetPreviousPetOrder() const { return m_previous_pet_order; } const char *GetCleanName(); virtual void SetName(const char *new_name = nullptr) { new_name ? strn0cpy(name, new_name, 64) : strn0cpy(name, GetName(), 64); return; }; @@ -1083,14 +1082,14 @@ public: Mob* GetUltimateOwner(); void SetPetID(uint16 NewPetID); inline uint16 GetPetID() const { return petid; } - inline PetType GetPetType() const { return type_of_pet; } - void SetPetType(PetType p) { type_of_pet = p; } + inline uint8 GetPetType() const { return type_of_pet; } + void SetPetType(uint8 pet_type) { type_of_pet = pet_type; } inline int16 GetPetPower() const { return (petpower < 0) ? 0 : petpower; } void SetPetPower(int16 p) { if (p < 0) petpower = 0; else petpower = p; } - bool IsFamiliar() const { return type_of_pet == petFamiliar; } - bool IsAnimation() const { return type_of_pet == petAnimation; } - bool IsCharmed() const { return type_of_pet == petCharmed; } - bool IsTargetLockPet() const { return type_of_pet == petTargetLock; } + bool IsFamiliar() const { return type_of_pet == PetType::Familiar; } + bool IsAnimation() const { return type_of_pet == PetType::Animation; } + bool IsCharmed() const { return type_of_pet == PetType::Charmed; } + bool IsTargetLockPet() const { return type_of_pet == PetType::TargetLock; } inline uint32 GetPetTargetLockID() { return pet_targetlock_id; }; inline void SetPetTargetLockID(uint32 value) { pet_targetlock_id = value; }; void SetOwnerID(uint16 new_owner_id); @@ -1212,8 +1211,8 @@ public: inline const float GetAssistRange() const { return (spellbonuses.AssistRange == -1) ? pAssistRange : spellbonuses.AssistRange; } - void SetPetOrder(eStandingPetOrder i); - inline const eStandingPetOrder GetPetOrder() const { return pStandingPetOrder; } + void SetPetOrder(uint8 pet_order); + inline const uint8 GetPetOrder() const { return m_pet_order; } inline void SetHeld(bool nState) { held = nState; } inline const bool IsHeld() const { return held; } inline void SetGHeld(bool nState) { gheld = nState; } @@ -1300,7 +1299,7 @@ public: bool IsPetAggroExempt(Mob *pet_owner); void InstillDoubt(Mob *who); - bool Charmed() const { return type_of_pet == petCharmed; } + bool Charmed() const { return type_of_pet == PetType::Charmed; } static uint32 GetLevelHP(uint8 tlevel); uint32 GetZoneID() const; //for perl uint16 GetInstanceVersion() const; //for perl @@ -1596,7 +1595,7 @@ protected: StatBonuses aabonuses; uint16 petid; uint16 ownerid; - PetType type_of_pet; + uint8 type_of_pet; int16 petpower; uint32 follow_id; uint32 follow_dist; @@ -1825,8 +1824,8 @@ protected: Timer viral_timer; // MobAI stuff - eStandingPetOrder pStandingPetOrder; - eStandingPetOrder m_previous_pet_order; + uint8 m_pet_order; + uint8 m_previous_pet_order; uint32 minLastFightingDelayMoving; uint32 maxLastFightingDelayMoving; float pAggroRange = 0; diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index f39797c10..173fae7a5 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1397,8 +1397,8 @@ void Mob::AI_Process() { else if (AI_movement_timer->Check() && !IsRooted()) { if (IsPet()) { // we're a pet, do as we're told - switch (pStandingPetOrder) { - case SPO_Follow: { + switch (m_pet_order) { + case PetOrder::Follow: { Mob *owner = GetOwner(); if (owner == nullptr) { @@ -1447,18 +1447,18 @@ void Mob::AI_Process() { break; } - case SPO_Sit: { + case PetOrder::Sit: { SetAppearance(eaSitting, false); break; } - case SPO_Guard: { + case PetOrder::Guard: { //only NPCs can guard stuff. (forced by where the guard movement code is in the AI) if (IsNPC()) { CastToNPC()->NextGuardPosition(); } break; } - case SPO_FeignDeath: { + case PetOrder::Feign: { SetAppearance(eaDead, false); break; } diff --git a/zone/npc.cpp b/zone/npc.cpp index c0b2954fd..de97d0fb5 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -4014,7 +4014,7 @@ void NPC::SetTaunting(bool is_taunting) { taunting = is_taunting; if (IsPet() && IsPetOwnerClient()) { - GetOwner()->CastToClient()->SetPetCommandState(PET_BUTTON_TAUNT, is_taunting); + GetOwner()->CastToClient()->SetPetCommandState(PetButton::Taunt, is_taunting); } } diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp index 326114030..dd06db33b 100644 --- a/zone/perl_mob.cpp +++ b/zone/perl_mob.cpp @@ -1114,11 +1114,16 @@ uint16 Perl_Mob_GetOwnerID(Mob* self) // @categories Script Utility, Pet return self->GetOwnerID(); } -int Perl_Mob_GetPetType(Mob* self) // @categories Script Utility, Pet +uint8 Perl_Mob_GetPetType(Mob* self) // @categories Script Utility, Pet { return self->GetPetType(); } +std::string Perl_Mob_GetPetTypeName(Mob* self) // @categories Script Utility, Pet +{ + return PetType::GetName(self->GetPetType()); +} + int Perl_Mob_GetBodyType(Mob* self) // @categories Stats and Attributes { return self->GetBodyType(); @@ -1254,12 +1259,12 @@ float Perl_Mob_GetAssistRange(Mob* self) // @categories Stats and Attributes, Ha return self->GetAssistRange(); } -void Perl_Mob_SetPetOrder(Mob* self, int order) // @categories Pet +void Perl_Mob_SetPetOrder(Mob* self, uint8 pet_order) // @categories Pet { - self->SetPetOrder(static_cast(order)); + self->SetPetOrder(pet_order); } -int Perl_Mob_GetPetOrder(Mob* self) // @categories Script Utility, Pet +uint8 Perl_Mob_GetPetOrder(Mob* self) // @categories Script Utility, Pet { return self->GetPetOrder(); } @@ -3597,6 +3602,11 @@ perl::array Perl_Mob_GetTimers(Mob* self) return a; } +void Perl_Mob_SetPetType(Mob* self, uint8 pet_type) +{ + self->SetPetType(pet_type); +} + void perl_register_mob() { perl::interpreter perl(PERL_GET_THX); @@ -3926,6 +3936,7 @@ void perl_register_mob() package.add("GetPetID", &Perl_Mob_GetPetID); package.add("GetPetOrder", &Perl_Mob_GetPetOrder); package.add("GetPetType", &Perl_Mob_GetPetType); + package.add("GetPetTypeName", &Perl_Mob_GetPetTypeName); package.add("GetPhR", &Perl_Mob_GetPhR); package.add("GetRace", &Perl_Mob_GetRace); package.add("GetRaceName", &Perl_Mob_GetRaceName); @@ -4187,6 +4198,7 @@ void perl_register_mob() package.add("SetPet", &Perl_Mob_SetPet); package.add("SetPetID", &Perl_Mob_SetPetID); package.add("SetPetOrder", &Perl_Mob_SetPetOrder); + package.add("SetPetType", &Perl_Mob_SetPetType); package.add("SetRace", &Perl_Mob_SetRace); package.add("SetRunAnimSpeed", &Perl_Mob_SetRunAnimSpeed); package.add("SetRunning", &Perl_Mob_SetRunning); diff --git a/zone/pets.cpp b/zone/pets.cpp index 37028e60a..2c8db2d31 100644 --- a/zone/pets.cpp +++ b/zone/pets.cpp @@ -267,7 +267,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, } //this takes ownership of the npc_type data - auto npc = new Pet(npc_type, this, (PetType)record.petcontrol, spell_id, record.petpower); + auto npc = new Pet(npc_type, this, record.petcontrol, spell_id, record.petpower); // Now that we have an actual object to interact with, load // the base items for the pet. These are always loaded @@ -295,7 +295,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, SetPetID(npc->GetID()); // We need to handle PetType 5 (petHatelist), add the current target to the hatelist of the pet - if (record.petcontrol == petTargetLock) + if (record.petcontrol == PetType::TargetLock) { Mob* m_target = GetTarget(); @@ -341,7 +341,7 @@ void NPC::TryDepopTargetLockedPets(Mob* current_target) { return; } //Use when pets are given petype 5 - if (IsPet() && GetPetType() == petTargetLock && GetPetTargetLockID()) { + if (IsPet() && GetPetType() == PetType::TargetLock && GetPetTargetLockID()) { CastSpell(SPELL_UNSUMMON_SELF, GetID()); //Live like behavior, damages self for 20K if (!HasDied()) { Kill(); //Ensure pet dies if over 20k HP. @@ -356,11 +356,11 @@ void NPC::TryDepopTargetLockedPets(Mob* current_target) { /* This is why the pets ghost - pets were being spawned too far away from its npc owner and some into walls or objects (+10), this sometimes creates the "ghost" effect. I changed to +2 (as close as I could get while it still looked good). I also noticed this can happen if an NPC is spawned on the same spot of another or in a related bad spot.*/ -Pet::Pet(NPCType *type_data, Mob *owner, PetType type, uint16 spell_id, int16 power) +Pet::Pet(NPCType *type_data, Mob *owner, uint8 pet_type, uint16 spell_id, int16 power) : NPC(type_data, 0, owner->GetPosition() + glm::vec4(2.0f, 2.0f, 0.0f, 0.0f), GravityBehavior::Water) { GiveNPCTypeData(type_data); - SetPetType(type); + SetPetType(pet_type); SetPetPower(power); SetOwnerID(owner ? owner->GetID() : 0); SetPetSpellID(spell_id); @@ -374,8 +374,8 @@ Pet::Pet(NPCType *type_data, Mob *owner, PetType type, uint16 spell_id, int16 po if (owner && owner->IsClient()) { if (!(owner->CastToClient()->ClientVersionBit() & EQ::versions::maskUFAndLater)) { if ( - (GetPetType() != petFamiliar && GetPetType() != petAnimation) || - aabonuses.PetCommands[PET_TAUNT] + (GetPetType() != PetType::Familiar && GetPetType() != PetType::Animation) || + aabonuses.PetCommands[PetCommand::Taunt] ) { SetTaunting(true); } @@ -587,7 +587,7 @@ void NPC::SetPetState(SpellBuff_Struct *pet_buffs, uint32 *items) { if (item2) { bool noDrop = (item2->NoDrop == 0); // Field is reverse logic - bool petCanHaveNoDrop = (RuleB(Pets, CanTakeNoDrop) && _CLIENTPET(this) && GetPetType() <= petOther); + bool petCanHaveNoDrop = (RuleB(Pets, CanTakeNoDrop) && _CLIENTPET(this) && GetPetType() <= PetType::Normal); if (!noDrop || petCanHaveNoDrop) { AddLootDrop(item2, LootdropEntriesRepository::NewNpcEntity(), true); diff --git a/zone/pets.h b/zone/pets.h index f8ab50eca..dc656fb08 100644 --- a/zone/pets.h +++ b/zone/pets.h @@ -6,7 +6,7 @@ struct NPCType; class Pet : public NPC { public: - Pet(NPCType *type_data, Mob *owner, PetType type, uint16 spell_id, int16 power); + Pet(NPCType *type_data, Mob *owner, uint8 pet_type, uint16 spell_id, int16 power); virtual bool CheckSpellLevelRestriction(Mob *caster, uint16 spell_id); }; diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index 4ce6bd150..b1101e9c6 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -1907,7 +1907,7 @@ void NPC::DoClassAttacks(Mob *target) { target->GetBodyType() != BodyType::Undead && taunt_time && type_of_pet && - type_of_pet != petTargetLock && + type_of_pet != PetType::TargetLock && DistanceSquared(GetPosition(), target->GetPosition()) <= (RuleI(Pets, PetTauntRange) * RuleI(Pets, PetTauntRange)) ) { GetOwner()->MessageString(Chat::PetResponse, PET_TAUNTING); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index e99028737..71b3b2024 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -803,19 +803,19 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove caster->SetPet(this); SetOwnerID(caster->GetID()); - SetPetOrder(SPO_Follow); + SetPetOrder(PetOrder::Follow); SetAppearance(eaStanding); // Client has saved previous pet sit/stand - make all new pets // stand and follow on charm. if (caster->IsClient()) { Client *cpet = caster->CastToClient(); - cpet->SetPetCommandState(PET_BUTTON_SIT,0); - cpet->SetPetCommandState(PET_BUTTON_FOLLOW, 1); - cpet->SetPetCommandState(PET_BUTTON_GUARD, 0); - cpet->SetPetCommandState(PET_BUTTON_STOP, 0); + cpet->SetPetCommandState(PetButton::Sit, PetButtonState::Off); + cpet->SetPetCommandState(PetButton::Follow, PetButtonState::On); + cpet->SetPetCommandState(PetButton::Guard, PetButtonState::Off); + cpet->SetPetCommandState(PetButton::Stop, PetButtonState::Off); } - SetPetType(petCharmed); + SetPetType(PetType::Charmed); // This was done in AddBuff, but we were not a pet yet, so // the target windows didn't get updated. @@ -1308,18 +1308,18 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove if (IsClient() && pet) { auto c = CastToClient(); if (c->ClientVersionBit() & EQ::versions::maskUFAndLater) { - c->SetPetCommandState(PET_BUTTON_SIT, 0); - c->SetPetCommandState(PET_BUTTON_STOP, 0); - c->SetPetCommandState(PET_BUTTON_REGROUP, 0); - c->SetPetCommandState(PET_BUTTON_FOLLOW, 1); - c->SetPetCommandState(PET_BUTTON_GUARD, 0); + c->SetPetCommandState(PetButton::Sit, PetButtonState::Off); + c->SetPetCommandState(PetButton::Stop, PetButtonState::Off); + c->SetPetCommandState(PetButton::Regroup, PetButtonState::Off); + c->SetPetCommandState(PetButton::Follow, PetButtonState::On); + c->SetPetCommandState(PetButton::Guard, PetButtonState::Off); // Creating pet from spell - taunt always false // If suspended pet - that will be restore there // If logging in, client will send toggle - c->SetPetCommandState(PET_BUTTON_HOLD, 0); - c->SetPetCommandState(PET_BUTTON_GHOLD, 0); - c->SetPetCommandState(PET_BUTTON_FOCUS, 0); - c->SetPetCommandState(PET_BUTTON_SPELLHOLD, 0); + c->SetPetCommandState(PetButton::Hold, PetButtonState::Off); + c->SetPetCommandState(PetButton::GreaterHold, PetButtonState::Off); + c->SetPetCommandState(PetButton::Focus, PetButtonState::Off); + c->SetPetCommandState(PetButton::SpellHold, PetButtonState::Off); } } } @@ -1618,7 +1618,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove GetOwnerID() && // I'm a pet caster && // there's a caster caster->GetID() == GetOwnerID() && // and it's my master - GetPetType() != petCharmed + GetPetType() != PetType::Charmed ) { uint16 pet_spellid = CastToNPC()->GetPetSpellID(); @@ -4427,7 +4427,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) SendAppearancePacket(AppearanceType::Pet, 0, true, true); Mob* owner = GetOwner(); SetOwnerID(0); - SetPetType(petNone); + SetPetType(PetType::None); SetHeld(false); SetGHeld(false); SetNoCast(false); diff --git a/zone/zoning.cpp b/zone/zoning.cpp index f857a6e20..96ad15dbc 100644 --- a/zone/zoning.cpp +++ b/zone/zoning.cpp @@ -709,7 +709,7 @@ void Client::ProcessMovePC(uint32 zoneID, uint32 instance_id, float x, float y, //if they have a pet and they are staying in zone, move with them Mob *p = GetPet(); if(p != nullptr){ - p->SetPetOrder(SPO_Follow); + p->SetPetOrder(PetOrder::Follow); p->GMMove(x+15, y, z); //so it dosent have to run across the map. } }