diff --git a/dCommon/dEnums/eHelpType.h b/dCommon/dEnums/eHelpType.h index c2fa70cd..6f6af172 100644 --- a/dCommon/dEnums/eHelpType.h +++ b/dCommon/dEnums/eHelpType.h @@ -3,6 +3,8 @@ #include +#include "magic_enum.hpp" + enum class eHelpType : int32_t { NONE = 0, UNLOCK_MINIMAP = 2, @@ -37,4 +39,10 @@ enum class eHelpType : int32_t { UI_INVENTORY_FULL_CANNOT_PICKUP_ITEM = 86 }; +template <> +struct magic_enum::customize::enum_range { + static constexpr int min = 0; + static constexpr int max = 86; +}; + #endif //!__EHELPTYPE__H__ diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index 161d7b91..ecca0d28 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -1204,7 +1204,7 @@ void InventoryComponent::SpawnPet(Item* item) { auto* current = PetComponent::GetActivePet(m_Parent->GetObjectID()); if (current != nullptr) { - current->Deactivate(); + current->Deactivate(eHelpType::PET_DESPAWN_BY_OWNER_HIBERNATE); if (current->GetDatabaseId() == item->GetSubKey()) { return; diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index c42ba2ac..fc277f0e 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -324,7 +324,7 @@ void PetComponent::OnUse(Entity* originator) { GameMessages::SendNotifyPetTamingPuzzleSelected(originator->GetObjectID(), bricks, originator->GetSystemAddress()); m_Tamer = originator->GetObjectID(); - SetFlag(PetFlag::IDLE, PetFlag::UNKNOWN4); //SetStatus(5); + SetFlag(PetFlag::IDLE, PetFlag::UNKNOWN4); currentActivities.insert_or_assign(m_Tamer, m_Parent->GetObjectID()); @@ -424,7 +424,7 @@ void PetComponent::TryBuild(uint32_t numBricks, bool clientFailed) { GameMessages::SendPetTamingTryBuildResult(m_Tamer, !clientFailed, numBricks, tamer->GetSystemAddress()); } -void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) { +void PetComponent::NotifyTamingBuildSuccess(const NiPoint3 position) { if (m_Tamer == LWOOBJID_EMPTY) return; auto* const tamer = Game::entityManager->GetEntity(m_Tamer); @@ -527,7 +527,7 @@ void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) { } } -void PetComponent::RequestSetPetName(std::u16string name) { +void PetComponent::RequestSetPetName(const std::u16string& name) { if (m_Tamer == LWOOBJID_EMPTY) { if (m_Owner != LWOOBJID_EMPTY) { auto* owner = GetOwner(); @@ -630,7 +630,7 @@ void PetComponent::ClientExitTamingMinigame(bool voluntaryExit) { currentActivities.erase(m_Tamer); - SetOnlyFlag(PetFlag::TAMEABLE); //SetStatus(PetFlag::TAMEABLE); + SetOnlyFlag(PetFlag::TAMEABLE); m_Tamer = LWOOBJID_EMPTY; m_Timer = 0; @@ -679,7 +679,7 @@ void PetComponent::ClientFailTamingMinigame() { currentActivities.erase(m_Tamer); - SetOnlyFlag(PetFlag::TAMEABLE); //SetStatus(PetFlag::TAMEABLE); + SetOnlyFlag(PetFlag::TAMEABLE); m_Tamer = LWOOBJID_EMPTY; m_Timer = 0; @@ -917,6 +917,7 @@ void PetComponent::StartInteractBouncer() { //GameMessages::SendHelp(user->GetObjectID(), eHelpType::PR_NEED_IMAGINATION, user->GetSystemAddress()); // Check if right message! return; } + GameMessages::SendHelp(user->GetObjectID(), eHelpType::PR_TOOLTIP_1ST_PET_JUMPED_ON_SWITCH, user->GetSystemAddress()); GameMessages::SendShowPetActionButton(m_Owner, ePetAbilityType::Invalid, false, user->GetSystemAddress()); @@ -954,7 +955,7 @@ void PetComponent::HandleInteractBouncer() { RenderComponent::PlayAnimation(petSwitchEntity, u"launch"); //u"engaged"); //TODO: Check if the timing on this is right // TODO: Need to freeze player movement until the bounce begins! - Command(NiPoint3Constant::ZERO, LWOOBJID_EMPTY, 1, GeneralUtils::CastUnderlyingType(PetEmote::ActivateSwitch), true); // Plays 'jump on switch' animation + Command(NiPoint3Constant::ZERO, LWOOBJID_EMPTY, 1, GeneralUtils::ToUnderlying(PetEmote::ActivateSwitch), true); // Plays 'jump on switch' animation StopInteract(); } m_Timer += 0.5f; @@ -970,7 +971,7 @@ void PetComponent::SetupInteractTreasureDig() { SetAbility(petAbility); UnsetFlag(PetFlag::IDLE); - SetFlag(PetFlag::ON_SWITCH, PetFlag::NOT_WAITING); //SetStatus(PetFlag::NOT_WAITING); // TODO: Double-check this is the right flag being set + SetFlag(PetFlag::ON_SWITCH, PetFlag::NOT_WAITING); // TODO: Double-check this is the right flag being set LOG_DEBUG("m_Flags = %d", m_Flags); Game::entityManager->SerializeEntity(m_Parent); // TODO: Double-check pet packet captures @@ -1007,7 +1008,7 @@ void PetComponent::StartInteractTreasureDig() { LOG_DEBUG("StartInteractTreasureDig() m_Flags = %d", m_Flags); Game::entityManager->SerializeEntity(m_Parent); - Command(NiPoint3Constant::ZERO, LWOOBJID_EMPTY, 1, GeneralUtils::CastUnderlyingType(PetEmote::DigTreasure), true); // Plays 'dig' animation + Command(NiPoint3Constant::ZERO, LWOOBJID_EMPTY, 1, GeneralUtils::ToUnderlying(PetEmote::DigTreasure), true); // Plays 'dig' animation m_Timer = 2.0f; } @@ -1028,7 +1029,7 @@ void PetComponent::HandleInteractTreasureDig() { } if (m_TimerBounce <= 0.0f) { - Command(NiPoint3Constant::ZERO, LWOOBJID_EMPTY, 1, GeneralUtils::CastUnderlyingType(PetEmote::Bounce), true); // Plays 'bounce' animation + Command(NiPoint3Constant::ZERO, LWOOBJID_EMPTY, 1, GeneralUtils::ToUnderlying(PetEmote::Bounce), true); // Plays 'bounce' animation m_TimerBounce = 1.0f; } @@ -1124,19 +1125,21 @@ void PetComponent::AddDrainImaginationTimer(Item* item, bool fromTaming) { } // If we are out of imagination despawn the pet. - if (playerDestroyableComponent->GetImagination() == 0) { - this->Deactivate(); + if (playerDestroyableComponent->GetImagination() < 1) { + this->Deactivate(eHelpType::PR_NO_IMAGINATION_HIBERNATE); auto playerEntity = playerDestroyableComponent->GetParent(); if (!playerEntity) return; - - GameMessages::SendUseItemRequirementsResponse(playerEntity->GetObjectID(), playerEntity->GetSystemAddress(), eUseItemResponse::NoImaginationForPet); } this->AddDrainImaginationTimer(item); }); } -void PetComponent::Deactivate() { +void PetComponent::Deactivate(const eHelpType msg) { + if (msg != eHelpType::NONE) { + GameMessages::SendHelp(m_Parent->GetObjectID(), msg, m_Parent->GetSystemAddress()); + } + GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), -1, u"despawn", "", LWOOBJID_EMPTY, 1, 1, true); GameMessages::SendMarkInventoryItemAsActive(m_Owner, false, eUnequippableActiveType::PET, m_ItemId, GetOwner()->GetSystemAddress()); diff --git a/dGame/dComponents/PetComponent.h b/dGame/dComponents/PetComponent.h index 218c98bc..568b86c0 100644 --- a/dGame/dComponents/PetComponent.h +++ b/dGame/dComponents/PetComponent.h @@ -196,7 +196,7 @@ public: * successfully). * @param name the name of the pet to set */ - void RequestSetPetName(std::u16string name); + void RequestSetPetName(const std::u16string& name); /** * Handles a notification of the client that the taming entity is leaving the minigame, either voluntary or because @@ -266,7 +266,7 @@ public: /** * Despawns the pet */ - void Deactivate(); + void Deactivate(eHelpType msg = eHelpType::NONE); /** * Removes the pet from the inventory diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 5146d32b..53a77777 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -3823,7 +3823,7 @@ void GameMessages::HandleDespawnPet(RakNet::BitStream& inStream, Entity* entity, if (bDeletePet) { petComponent->Release(); } else { - petComponent->Deactivate(); + petComponent->Deactivate(eHelpType::PET_DESPAWN_BY_OWNER_HIBERNATE); } } diff --git a/dGame/dInventory/Item.cpp b/dGame/dInventory/Item.cpp index d3f15315..d0acef4d 100644 --- a/dGame/dInventory/Item.cpp +++ b/dGame/dInventory/Item.cpp @@ -319,7 +319,7 @@ void Item::UseNonEquip(Item* item) { if (packageComponentId == 0) return; auto* packCompTable = CDClientManager::GetTable(); - auto packages = packCompTable->Query([=](const CDPackageComponent entry) {return entry.id == static_cast(packageComponentId); }); + auto packages = packCompTable->Query([packageComponentId](const CDPackageComponent entry) {return entry.id == static_cast(packageComponentId); }); auto success = !packages.empty(); if (success) { diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index c89694e8..817df797 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -59,6 +59,7 @@ #include "dpShapeSphere.h" #include "PossessableComponent.h" #include "PossessorComponent.h" +#include "StringifiedEnum.h" #include "HavokVehiclePhysicsComponent.h" #include "BuffComponent.h" #include "SkillComponent.h" @@ -81,6 +82,7 @@ #include "eControlScheme.h" #include "eConnectionType.h" #include "eChatInternalMessageType.h" +#include "eHelpType.h" #include "eMasterMessageType.h" #include "PlayerManager.h" @@ -674,6 +676,32 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } + // Send packet to display help message pop-up + if (chatCommand == "helpmsg") { + if (entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) { + const auto helpIdOpt = GeneralUtils::TryParse(args[0]); + if (!helpIdOpt) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid help message id."); + return; + } + + const eHelpType helpId = helpIdOpt.value(); + GameMessages::SendHelp(entity->GetObjectID(), helpId, sysAddr); + + // Convert and print enum string + const std::u16string msg = u"Sent help message '" + + GeneralUtils::ASCIIToUTF16(StringifiedEnum::ToString(helpId)) + + u"' (id: " + + GeneralUtils::to_u16string(GeneralUtils::ToUnderlying(helpId)) + + u')'; + + ChatPackets::SendSystemMessage(sysAddr, msg); + } else { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid command invocation."); + return; + } + } + if (chatCommand == "setflag" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) { const auto flagId = GeneralUtils::TryParse(args.at(0)); @@ -732,7 +760,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit petComponent->SetFlag(petFlag); - std::u16string msg = u"Set pet flag to " + (GeneralUtils::to_u16string(GeneralUtils::CastUnderlyingType(petFlag))); + std::u16string msg = u"Set pet flag to " + (GeneralUtils::to_u16string(GeneralUtils::ToUnderlying(petFlag))); ChatPackets::SendSystemMessage(sysAddr, msg); } diff --git a/docs/Commands.md b/docs/Commands.md index 265ab60d..fb1252d8 100644 --- a/docs/Commands.md +++ b/docs/Commands.md @@ -79,6 +79,7 @@ These commands are primarily for development and testing. The usage of many of t |getnavmeshheight|`/getnavmeshheight`|Displays the navmesh height at your current position.|8| |giveuscore|`/giveuscore `|Gives uscore.|8| |gmadditem|`/gmadditem (count)`|Adds the given item to your inventory by id.|8| +|helpmsg|`/helpmsg (help id)`|Display help message pop-up for a given id.|8| |inspect|`/inspect (-m \| -a \| -s \| -p \| -f (faction) \| -t)`|Finds the closest entity with the given component or LDF variable (ignoring players and racing cars), printing its ID, distance from the player, and whether it is sleeping, as well as the the IDs of all components the entity has. See [Detailed `/inspect` Usage](#detailed-inspect-usage) below.|8| |list-spawns|`/list-spawns`|Lists all the character spawn points in the zone. Additionally, this command will display the current scene that plays when the character lands in the next zone, if there is one.|8| |locrow|`/locrow`|Prints the your current position and rotation information to the console.|8|