From 136937184e2683fa38befdb8734fcd4866345d26 Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Fri, 17 Jun 2022 22:18:46 -0700 Subject: [PATCH 1/7] Add to common vars and dnet Added values to enums on dnet and common vars that were missing --- dCommon/dCommonVars.h | 6 ++++++ dNet/dMessageIdentifiers.h | 1 + 2 files changed, 7 insertions(+) diff --git a/dCommon/dCommonVars.h b/dCommon/dCommonVars.h index cbecdd37..a52a1dc6 100644 --- a/dCommon/dCommonVars.h +++ b/dCommon/dCommonVars.h @@ -415,6 +415,12 @@ enum eReplicaComponentType : int32_t { COMPONENT_TYPE_MODEL = 5398484 //look man idk }; +enum class UseItemResponse : uint32_t { + NoImaginationForPet = 1, + FailedPrecondition, + MountsNotAllowed +}; + /** * Represents the different types of inventories an entity may have */ diff --git a/dNet/dMessageIdentifiers.h b/dNet/dMessageIdentifiers.h index 8e20ab54..5b2ff639 100644 --- a/dNet/dMessageIdentifiers.h +++ b/dNet/dMessageIdentifiers.h @@ -376,6 +376,7 @@ enum GAME_MSG : unsigned short { GAME_MSG_NOTIFY_PET_TAMING_PUZZLE_SELECTED = 675, GAME_MSG_SHOW_PET_ACTION_BUTTON = 692, GAME_MSG_SET_EMOTE_LOCK_STATE = 693, + GAME_MSG_USE_ITEM_REQUIREMENTS_RESPONSE = 703, GAME_MSG_PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT = 713, GAME_MSG_DOWNLOAD_PROPERTY_DATA = 716, GAME_MSG_QUERY_PROPERTY_DATA = 717, From e28b084395ca77ce33861ab62161da9e0ff67a47 Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Fri, 17 Jun 2022 22:19:28 -0700 Subject: [PATCH 2/7] Add GM Added GM for UseItemRequirementsResponse that was missing in current implementation --- dGame/dGameMessages/GameMessages.cpp | 12 ++++++++++++ dGame/dGameMessages/GameMessages.h | 1 + 2 files changed, 13 insertions(+) diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 58aba14d..6e6236a6 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -1363,6 +1363,18 @@ void GameMessages::SendUseItemResult(Entity* entity, LOT templateID, bool useIte SEND_PACKET } +void GameMessages::SendUseItemRequirementsResponse(LWOOBJID objectID, const SystemAddress& sysAddr, UseItemResponse itemResponse) { + CBITSTREAM + CMSGHEADER + + bitStream.Write(objectID); + bitStream.Write(GAME_MSG::GAME_MSG_USE_ITEM_REQUIREMENTS_RESPONSE); + + bitStream.Write(itemResponse); + + SEND_PACKET +} + void GameMessages::SendMoveInventoryBatch(Entity* entity, uint32_t stackCount, int srcInv, int dstInv, const LWOOBJID& iObjID) { CBITSTREAM CMSGHEADER diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index 602cb4b2..1d42eebc 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -372,6 +372,7 @@ namespace GameMessages { void SendActivityPause(LWOOBJID objectId, bool pause = false, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); void SendStartActivityTime(LWOOBJID objectId, float_t startTime, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); void SendRequestActivityEnter(LWOOBJID objectId, const SystemAddress& sysAddr, bool bStart, LWOOBJID userID); + void SendUseItemRequirementsResponse(LWOOBJID objectID, const SystemAddress& sysAddr, UseItemResponse itemResponse); // SG: From 35ea3d35aed8a02c0f82740de71872bbca3f5575 Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Fri, 17 Jun 2022 23:53:09 -0700 Subject: [PATCH 3/7] Add pet imagination draining Address an issue where pets did not consume imagination when they were spawned. --- dGame/dComponents/InventoryComponent.cpp | 8 ++++ dGame/dComponents/PetComponent.cpp | 52 ++++++++++++++++++++++++ dGame/dComponents/PetComponent.h | 13 ++++++ 3 files changed, 73 insertions(+) diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index cf17b0ac..bc589e7b 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -1351,6 +1351,14 @@ void InventoryComponent::SpawnPet(Item* item) } } + // First check if we can summon the pet. You need 1 imagination to do so. + auto destroyableComponent = m_Parent->GetComponent(); + + if (destroyableComponent && destroyableComponent->GetImagination() <= 0) { + GameMessages::SendUseItemRequirementsResponse(m_Parent->GetObjectID(), m_Parent->GetSystemAddress(), UseItemResponse::NoImaginationForPet); + return; + } + EntityInfo info {}; info.lot = item->GetLot(); info.pos = m_Parent->GetPosition(); diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index a36d59e3..caefbf68 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -81,6 +81,20 @@ PetComponent::PetComponent(Entity* parent, uint32_t componentId) : Component(par if (!checkPreconditions.empty()) { SetPreconditions(checkPreconditions); } + // Get the imagination drain rate from the CDClient + auto query = CDClientDatabase::CreatePreppedStmt("SELECT imaginationDrainRate FROM PetComponent WHERE id = ?;"); + + query.bind(1, static_cast(componentId)); + + auto result = query.execQuery(); + + // Should a result not exist for this pet default to 60 seconds. + if (!result.eof() && !result.fieldIsNull(0)) { + imaginationDrainRate = result.getFloatField(0, 60.0f); + } else { + imaginationDrainRate = 60.0f; + } + result.finalize(); } void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) @@ -899,6 +913,8 @@ void PetComponent::Wander() void PetComponent::Activate(Item* item, bool registerPet) { + AddDrainImaginationTimer(item); + m_ItemId = item->GetId(); m_DatabaseId = item->GetSubKey(); @@ -968,6 +984,42 @@ void PetComponent::Activate(Item* item, bool registerPet) GameMessages::SendShowPetActionButton(m_Owner, 3, true, owner->GetSystemAddress()); } +void PetComponent::AddDrainImaginationTimer(Item* item) { + auto playerInventory = item->GetInventory(); + if (!playerInventory) return; + + auto playerInventoryComponent = playerInventory->GetComponent(); + if (!playerInventoryComponent) return; + + auto playerEntity = playerInventoryComponent->GetParent(); + if (!playerEntity) return; + + auto playerDestroyableComponent = playerEntity->GetComponent(); + if (!playerDestroyableComponent) return; + + // Drain by 1 when you summon pet or when this method is called + playerDestroyableComponent->Imagine(-1); + + // Set this to a variable so when this is called back from the player the timer doesn't fire off. + m_Parent->AddCallbackTimer(imaginationDrainRate, [playerDestroyableComponent, this, item](){ + if (!playerDestroyableComponent) { + Game::logger->Log("PetComponent", "No petComponent and/or no playerDestroyableComponent\n"); + return; + } + + // If we are out of imagination despawn the pet. + if (playerDestroyableComponent->GetImagination() == 0) { + this->Deactivate(); + auto playerEntity = playerDestroyableComponent->GetParent(); + if (!playerEntity) return; + + GameMessages::SendUseItemRequirementsResponse(playerEntity->GetObjectID(), playerEntity->GetSystemAddress(), UseItemResponse::NoImaginationForPet); + } + + this->AddDrainImaginationTimer(item); + }); +} + void PetComponent::Deactivate() { GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), -1, u"despawn", "", LWOOBJID_EMPTY, 1, 1, true); diff --git a/dGame/dComponents/PetComponent.h b/dGame/dComponents/PetComponent.h index 845cfe31..9139575a 100644 --- a/dGame/dComponents/PetComponent.h +++ b/dGame/dComponents/PetComponent.h @@ -203,6 +203,14 @@ public: */ static PetComponent* GetActivePet(LWOOBJID owner); + /** + * Adds the timer to the owner of this pet to drain imagination at the rate + * specified by the parameter imaginationDrainRate + * + * @param item The item that represents this pet in the inventory. + */ + void AddDrainImaginationTimer(Item* item); + private: /** @@ -346,4 +354,9 @@ private: * Preconditions that need to be met before an entity can tame this pet */ PreconditionExpression* m_Preconditions; + + /** + * The rate at which imagination is drained from the user for having the pet out. + */ + float imaginationDrainRate; }; \ No newline at end of file From e415d96a9ddf832ae396f242b350bd233658b03e Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Sat, 18 Jun 2022 00:03:27 -0700 Subject: [PATCH 4/7] Added config setting Added a config setting to allow players to disable pets consuming imagination. This value defaults to zero as a feature of DLU. --- dGame/dComponents/InventoryComponent.cpp | 3 ++- dGame/dComponents/PetComponent.cpp | 3 +++ resources/worldconfig.ini | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index bc589e7b..b7eae8bf 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -24,6 +24,7 @@ #include "dZoneManager.h" #include "PropertyManagementComponent.h" #include "DestroyableComponent.h" +#include "dConfig.h" InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document) : Component(parent) { @@ -1354,7 +1355,7 @@ void InventoryComponent::SpawnPet(Item* item) // First check if we can summon the pet. You need 1 imagination to do so. auto destroyableComponent = m_Parent->GetComponent(); - if (destroyableComponent && destroyableComponent->GetImagination() <= 0) { + if (Game::config->GetValue("pets_imagination") == "1" && destroyableComponent && destroyableComponent->GetImagination() <= 0) { GameMessages::SendUseItemRequirementsResponse(m_Parent->GetObjectID(), m_Parent->GetSystemAddress(), UseItemResponse::NoImaginationForPet); return; } diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index caefbf68..87f7278b 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -16,6 +16,7 @@ #include "../dWorldServer/ObjectIDManager.h" #include "Game.h" +#include "dConfig.h" #include "dChatFilter.h" #include "Database.h" @@ -985,6 +986,8 @@ void PetComponent::Activate(Item* item, bool registerPet) } void PetComponent::AddDrainImaginationTimer(Item* item) { + if (Game::config->GetValue("pets_imagination") == "0") return; + auto playerInventory = item->GetInventory(); if (!playerInventory) return; diff --git a/resources/worldconfig.ini b/resources/worldconfig.ini index b1fec1a6..bba17b38 100644 --- a/resources/worldconfig.ini +++ b/resources/worldconfig.ini @@ -57,3 +57,6 @@ check_fdb=0 # 0 or 1, DLU leaderboards will rate Avant Gardens Survival based on score by default. # This option should be set to 1 if you would like it to reflect the game when it was live (scoring based on time). classic_survival_scoring=0 + +# If this value is 1, pets will consume imagination as they did in live. if 0 they will not consume imagination at all. +pets_imagination=0 From 0774ab930da85725dabcf37ac6b32ef6c1e529c2 Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Sat, 18 Jun 2022 00:09:05 -0700 Subject: [PATCH 5/7] inverted config check Since most people are not regularly updating their config files, this needs to assume the value is disabled rather than enabled. --- dGame/dComponents/PetComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index 87f7278b..891f0d1d 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -986,7 +986,7 @@ void PetComponent::Activate(Item* item, bool registerPet) } void PetComponent::AddDrainImaginationTimer(Item* item) { - if (Game::config->GetValue("pets_imagination") == "0") return; + if (Game::config->GetValue("pets_imagination") != "1") return; auto playerInventory = item->GetInventory(); if (!playerInventory) return; From 2a0616d0e9a9f25ce6d0244bbe199cafdec6e85d Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Sat, 18 Jun 2022 00:14:24 -0700 Subject: [PATCH 6/7] Dont take imagination on initial tame --- dGame/dComponents/PetComponent.cpp | 14 +++++++------- dGame/dComponents/PetComponent.h | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index 891f0d1d..23dcf5e6 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -651,7 +651,7 @@ void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) inventoryComponent->SetDatabasePet(petSubKey, databasePet); - Activate(item, false); + Activate(item, false, true); m_Timer = 0; @@ -912,9 +912,9 @@ void PetComponent::Wander() m_Timer += (m_MovementAI->GetCurrentPosition().x - destination.x) / info.wanderSpeed; } -void PetComponent::Activate(Item* item, bool registerPet) +void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) { - AddDrainImaginationTimer(item); + AddDrainImaginationTimer(item, fromTaming); m_ItemId = item->GetId(); m_DatabaseId = item->GetSubKey(); @@ -985,9 +985,9 @@ void PetComponent::Activate(Item* item, bool registerPet) GameMessages::SendShowPetActionButton(m_Owner, 3, true, owner->GetSystemAddress()); } -void PetComponent::AddDrainImaginationTimer(Item* item) { +void PetComponent::AddDrainImaginationTimer(Item* item, bool fromTaming) { if (Game::config->GetValue("pets_imagination") != "1") return; - + auto playerInventory = item->GetInventory(); if (!playerInventory) return; @@ -1000,8 +1000,8 @@ void PetComponent::AddDrainImaginationTimer(Item* item) { auto playerDestroyableComponent = playerEntity->GetComponent(); if (!playerDestroyableComponent) return; - // Drain by 1 when you summon pet or when this method is called - playerDestroyableComponent->Imagine(-1); + // Drain by 1 when you summon pet or when this method is called, but not when we have just tamed this pet. + if (!fromTaming) playerDestroyableComponent->Imagine(-1); // Set this to a variable so when this is called back from the player the timer doesn't fire off. m_Parent->AddCallbackTimer(imaginationDrainRate, [playerDestroyableComponent, this, item](){ diff --git a/dGame/dComponents/PetComponent.h b/dGame/dComponents/PetComponent.h index 9139575a..913cbc56 100644 --- a/dGame/dComponents/PetComponent.h +++ b/dGame/dComponents/PetComponent.h @@ -82,7 +82,7 @@ public: * @param item the item to create the pet from * @param registerPet notifies the client that the pet was spawned, not necessary if this pet is being tamed */ - void Activate(Item* item, bool registerPet = true); + void Activate(Item* item, bool registerPet = true, bool fromTaming = false); /** * Despawns the pet @@ -209,7 +209,7 @@ public: * * @param item The item that represents this pet in the inventory. */ - void AddDrainImaginationTimer(Item* item); + void AddDrainImaginationTimer(Item* item, bool fromTaming = false); private: From 2e224cb15111bcbfcf5b1e6238f71699a8c7a049 Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Sat, 18 Jun 2022 13:25:34 -0700 Subject: [PATCH 7/7] update name Pets will take imagination by default now --- dGame/dComponents/InventoryComponent.cpp | 2 +- dGame/dComponents/PetComponent.cpp | 2 +- resources/worldconfig.ini | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index b7eae8bf..e47f5bb5 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -1355,7 +1355,7 @@ void InventoryComponent::SpawnPet(Item* item) // First check if we can summon the pet. You need 1 imagination to do so. auto destroyableComponent = m_Parent->GetComponent(); - if (Game::config->GetValue("pets_imagination") == "1" && destroyableComponent && destroyableComponent->GetImagination() <= 0) { + if (Game::config->GetValue("pets_take_imagination") == "1" && destroyableComponent && destroyableComponent->GetImagination() <= 0) { GameMessages::SendUseItemRequirementsResponse(m_Parent->GetObjectID(), m_Parent->GetSystemAddress(), UseItemResponse::NoImaginationForPet); return; } diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index 23dcf5e6..d54087aa 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -986,7 +986,7 @@ void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) } void PetComponent::AddDrainImaginationTimer(Item* item, bool fromTaming) { - if (Game::config->GetValue("pets_imagination") != "1") return; + if (Game::config->GetValue("pets_take_imagination") != "1") return; auto playerInventory = item->GetInventory(); if (!playerInventory) return; diff --git a/resources/worldconfig.ini b/resources/worldconfig.ini index bba17b38..a665f059 100644 --- a/resources/worldconfig.ini +++ b/resources/worldconfig.ini @@ -59,4 +59,4 @@ check_fdb=0 classic_survival_scoring=0 # If this value is 1, pets will consume imagination as they did in live. if 0 they will not consume imagination at all. -pets_imagination=0 +pets_take_imagination=1