From ec6253c80cc03ee81b91f11c3318e28ddd937342 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Wed, 15 Oct 2025 20:36:45 -0700 Subject: [PATCH 1/3] fix: coin dupe on same team (#1911) * feat: Loot rework * Allow dupe powerup pickups * change default team loot to shared * fix: coin dupe on team --- dGame/dComponents/DestroyableComponent.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index 8b654f9f..f037f860 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -773,7 +773,15 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType coinsTotal -= coinsToLose; - Loot::DropLoot(m_Parent, m_Parent->GetObjectID(), -1, coinsToLose, coinsToLose); + GameMessages::DropClientLoot lootMsg{}; + lootMsg.target = m_Parent->GetObjectID(); + lootMsg.ownerID = m_Parent->GetObjectID(); + lootMsg.currency = coinsToLose; + lootMsg.spawnPos = m_Parent->GetPosition(); + lootMsg.sourceID = source; + lootMsg.item = LOT_NULL; + lootMsg.Send(); + lootMsg.Send(m_Parent->GetSystemAddress()); character->SetCoins(coinsTotal, eLootSourceType::PICKUP); } } From 4c9c773ec5ec14def9605673dc6254ca9f9b6e37 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Thu, 16 Oct 2025 12:13:38 -0700 Subject: [PATCH 2/3] fix: powerup drops and hardcore loot drops (#1914) tested the following are now functional ag buff station tiki torch ve rocket part boxes ns statue property behavior extra items from full inventory hardcore drops (items and coins) --- dGame/dComponents/DestroyableComponent.cpp | 27 +++++++++++-- dGame/dComponents/InventoryComponent.cpp | 9 ++++- dGame/dGameMessages/GameMessages.cpp | 38 ------------------- dGame/dGameMessages/GameMessages.h | 1 - dGame/dPropertyBehaviors/Strip.cpp | 10 ++++- dGame/dUtilities/Loot.cpp | 18 +++++---- dScripts/02_server/Map/GF/GfTikiTorch.cpp | 10 ++++- .../Objects/AgSurvivalBuffStation.cpp | 10 ++++- dScripts/ai/AG/AgImagSmashable.cpp | 10 ++++- dScripts/ai/NS/NsQbImaginationStatue.cpp | 11 +++++- 10 files changed, 86 insertions(+), 58 deletions(-) diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index f037f860..fabcd3ef 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -982,7 +982,14 @@ void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source) { for (const auto item : itemMap | std::views::values) { // Don't drop excluded items or null ones if (!item || Game::entityManager->GetHardcoreExcludedItemDrops().contains(item->GetLot())) continue; - GameMessages::SendDropClientLoot(m_Parent, source, item->GetLot(), 0, m_Parent->GetPosition(), item->GetCount()); + GameMessages::DropClientLoot lootMsg{}; + lootMsg.target = m_Parent->GetObjectID(); + lootMsg.ownerID = m_Parent->GetObjectID(); + lootMsg.sourceID = m_Parent->GetObjectID(); + lootMsg.item = item->GetLot(); + lootMsg.count = 1; + lootMsg.spawnPos = m_Parent->GetPosition(); + for (int i = 0; i < item->GetCount(); i++) Loot::DropItem(*m_Parent, lootMsg); item->SetCount(0, false, false); } Game::entityManager->SerializeEntity(m_Parent); @@ -1005,12 +1012,24 @@ void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source) { //drop all coins: constexpr auto MAX_TO_DROP_PER_GM = 100'000; + GameMessages::DropClientLoot lootMsg{}; + lootMsg.target = m_Parent->GetObjectID(); + lootMsg.ownerID = m_Parent->GetObjectID(); + lootMsg.spawnPos = m_Parent->GetPosition(); + lootMsg.sourceID = source; + lootMsg.item = LOT_NULL; + lootMsg.Send(); + lootMsg.Send(m_Parent->GetSystemAddress()); while (coinsToDrop > MAX_TO_DROP_PER_GM) { LOG("Dropping 100,000, %llu left", coinsToDrop); - GameMessages::SendDropClientLoot(m_Parent, source, LOT_NULL, MAX_TO_DROP_PER_GM, m_Parent->GetPosition()); - coinsToDrop -= MAX_TO_DROP_PER_GM; + lootMsg.currency = 100'000; + lootMsg.Send(); + lootMsg.Send(m_Parent->GetSystemAddress()); + coinsToDrop -= 100'000; } - GameMessages::SendDropClientLoot(m_Parent, source, LOT_NULL, coinsToDrop, m_Parent->GetPosition()); + lootMsg.currency = coinsToDrop; + lootMsg.Send(); + lootMsg.Send(m_Parent->GetSystemAddress()); } return; } diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index 6bd690f8..212572ae 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -282,7 +282,14 @@ void InventoryComponent::AddItem( case 1: for (size_t i = 0; i < size; i++) { - GameMessages::SendDropClientLoot(this->m_Parent, this->m_Parent->GetObjectID(), lot, 0, this->m_Parent->GetPosition(), 1); + GameMessages::DropClientLoot lootMsg{}; + lootMsg.target = m_Parent->GetObjectID(); + lootMsg.ownerID = m_Parent->GetObjectID(); + lootMsg.sourceID = m_Parent->GetObjectID(); + lootMsg.item = lot; + lootMsg.count = 1; + lootMsg.spawnPos = m_Parent->GetPosition(); + Loot::DropItem(*m_Parent, lootMsg); } break; diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 42fd2a58..522f4741 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -1067,44 +1067,6 @@ void GameMessages::SendSetNetworkScriptVar(Entity* entity, const SystemAddress& SEND_PACKET; } -void GameMessages::SendDropClientLoot(Entity* entity, const LWOOBJID& sourceID, LOT item, int currency, NiPoint3 spawnPos, int count) { - if (Game::config->GetValue("disable_drops") == "1" || !entity) { - return; - } - - bool bUsePosition = false; - NiPoint3 finalPosition; - LWOOBJID lootID = LWOOBJID_EMPTY; - LWOOBJID owner = entity->GetObjectID(); - - if (item != LOT_NULL && item != 0) { - lootID = ObjectIDManager::GenerateObjectID(); - - Loot::Info info; - info.id = lootID; - info.count = count; - info.lot = item; - entity->AddLootItem(info); - } - - if (item == LOT_NULL && currency != 0) { - entity->RegisterCoinDrop(currency); - } - - if (spawnPos != NiPoint3Constant::ZERO) { - bUsePosition = true; - - //Calculate where the loot will go: - uint16_t degree = GeneralUtils::GenerateRandomNumber(0, 360); - - double rad = degree * 3.14 / 180; - double sin_v = sin(rad) * 4.2; - double cos_v = cos(rad) * 4.2; - - finalPosition = NiPoint3(static_cast(spawnPos.GetX() + sin_v), spawnPos.GetY(), static_cast(spawnPos.GetZ() + cos_v)); - } -} - void GameMessages::SendSetPlayerControlScheme(Entity* entity, eControlScheme controlScheme) { CBITSTREAM; CMSGHEADER; diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index 4f9ce78b..5c682075 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -153,7 +153,6 @@ namespace GameMessages { void SendStop2DAmbientSound(Entity* entity, bool force, std::string audioGUID, bool result = false); void SendPlay2DAmbientSound(Entity* entity, std::string audioGUID, bool result = false); void SendSetNetworkScriptVar(Entity* entity, const SystemAddress& sysAddr, std::string data); - void SendDropClientLoot(Entity* entity, const LWOOBJID& sourceID, LOT item, int currency, NiPoint3 spawnPos = NiPoint3Constant::ZERO, int count = 1); void SendSetPlayerControlScheme(Entity* entity, eControlScheme controlScheme); void SendPlayerReachedRespawnCheckpoint(Entity* entity, const NiPoint3& position, const NiQuaternion& rotation); diff --git a/dGame/dPropertyBehaviors/Strip.cpp b/dGame/dPropertyBehaviors/Strip.cpp index fcbad8c2..330284a9 100644 --- a/dGame/dPropertyBehaviors/Strip.cpp +++ b/dGame/dPropertyBehaviors/Strip.cpp @@ -13,6 +13,7 @@ #include "dChatFilter.h" #include "DluAssert.h" +#include "Loot.h" template <> void Strip::HandleMsg(AddStripMessage& msg) { @@ -148,7 +149,14 @@ void Strip::Spawn(LOT lot, Entity& entity) { // Spawns a specific drop for all void Strip::SpawnDrop(LOT dropLOT, Entity& entity) { for (auto* const player : PlayerManager::GetAllPlayers()) { - GameMessages::SendDropClientLoot(player, entity.GetObjectID(), dropLOT, 0, entity.GetPosition()); + GameMessages::DropClientLoot lootMsg{}; + lootMsg.target = player->GetObjectID(); + lootMsg.ownerID = player->GetObjectID(); + lootMsg.sourceID = entity.GetObjectID(); + lootMsg.item = dropLOT; + lootMsg.count = 1; + lootMsg.spawnPos = entity.GetPosition(); + Loot::DropItem(*player, lootMsg); } } diff --git a/dGame/dUtilities/Loot.cpp b/dGame/dUtilities/Loot.cpp index 656ff61f..0b88f5af 100644 --- a/dGame/dUtilities/Loot.cpp +++ b/dGame/dUtilities/Loot.cpp @@ -93,17 +93,19 @@ std::map RollLootMatrix(uint32_t matrixIndex) { // Generates a 'random' final position for the loot drop based on its input spawn position. void CalcFinalDropPos(GameMessages::DropClientLoot& lootMsg) { - lootMsg.bUsePosition = true; + if (lootMsg.spawnPos != NiPoint3Constant::ZERO) { + lootMsg.bUsePosition = true; - //Calculate where the loot will go: - uint16_t degree = GeneralUtils::GenerateRandomNumber(0, 360); + //Calculate where the loot will go: + uint16_t degree = GeneralUtils::GenerateRandomNumber(0, 360); - double rad = degree * 3.14 / 180; - double sin_v = sin(rad) * 4.2; - double cos_v = cos(rad) * 4.2; + double rad = degree * 3.14 / 180; + double sin_v = sin(rad) * 4.2; + double cos_v = cos(rad) * 4.2; - const auto [x, y, z] = lootMsg.spawnPos; - lootMsg.finalPosition = NiPoint3(static_cast(x + sin_v), y, static_cast(z + cos_v)); + const auto [x, y, z] = lootMsg.spawnPos; + lootMsg.finalPosition = NiPoint3(static_cast(x + sin_v), y, static_cast(z + cos_v)); + } } // Visually drop the loot to all team members, though only the lootMsg.ownerID can pick it up diff --git a/dScripts/02_server/Map/GF/GfTikiTorch.cpp b/dScripts/02_server/Map/GF/GfTikiTorch.cpp index e61abd76..da55a77f 100644 --- a/dScripts/02_server/Map/GF/GfTikiTorch.cpp +++ b/dScripts/02_server/Map/GF/GfTikiTorch.cpp @@ -7,6 +7,7 @@ #include "eReplicaComponentType.h" #include "RenderComponent.h" #include "eTerminateType.h" +#include "Loot.h" void GfTikiTorch::OnStartup(Entity* self) { LightTorch(self); @@ -22,7 +23,14 @@ void GfTikiTorch::OnUse(Entity* self, Entity* killer) { self->SetI64(u"userID", killer->GetObjectID()); for (int i = 0; i < m_numspawn; i++) { - GameMessages::SendDropClientLoot(killer, self->GetObjectID(), 935, 0, self->GetPosition()); + GameMessages::DropClientLoot lootMsg{}; + lootMsg.target = killer->GetObjectID(); + lootMsg.ownerID = killer->GetObjectID(); + lootMsg.sourceID = self->GetObjectID(); + lootMsg.item = 935; + lootMsg.count = 1; + lootMsg.spawnPos = self->GetPosition(); + Loot::DropItem(*killer, lootMsg); } self->AddTimer("InteractionCooldown", 4); diff --git a/dScripts/02_server/Objects/AgSurvivalBuffStation.cpp b/dScripts/02_server/Objects/AgSurvivalBuffStation.cpp index 1a7cac11..16395a4e 100644 --- a/dScripts/02_server/Objects/AgSurvivalBuffStation.cpp +++ b/dScripts/02_server/Objects/AgSurvivalBuffStation.cpp @@ -4,6 +4,7 @@ #include "GameMessages.h" #include "SkillComponent.h" #include "TeamManager.h" +#include "Loot.h" void AgSurvivalBuffStation::OnQuickBuildComplete(Entity* self, Entity* target) { auto destroyableComponent = self->GetComponent(); @@ -55,7 +56,14 @@ void AgSurvivalBuffStation::OnTimerDone(Entity* self, std::string timerName) { for (auto memberID : team) { auto member = Game::entityManager->GetEntity(memberID); if (member != nullptr && !member->GetIsDead()) { - GameMessages::SendDropClientLoot(member, self->GetObjectID(), powerupToDrop, 0, self->GetPosition()); + GameMessages::DropClientLoot lootMsg{}; + lootMsg.target = member->GetObjectID(); + lootMsg.ownerID = member->GetObjectID(); + lootMsg.sourceID = self->GetObjectID(); + lootMsg.item = powerupToDrop; + lootMsg.count = 1; + lootMsg.spawnPos = self->GetPosition(); + Loot::DropItem(*member, lootMsg, true, true); } } } diff --git a/dScripts/ai/AG/AgImagSmashable.cpp b/dScripts/ai/AG/AgImagSmashable.cpp index 2a35ed9a..7d67cc29 100644 --- a/dScripts/ai/AG/AgImagSmashable.cpp +++ b/dScripts/ai/AG/AgImagSmashable.cpp @@ -5,6 +5,7 @@ #include "EntityInfo.h" #include "DestroyableComponent.h" #include "eReplicaComponentType.h" +#include "Loot.h" void AgImagSmashable::OnDie(Entity* self, Entity* killer) { bool maxImagGreaterThanZero = false; @@ -18,7 +19,14 @@ void AgImagSmashable::OnDie(Entity* self, Entity* killer) { if (maxImagGreaterThanZero) { int amount = GeneralUtils::GenerateRandomNumber(0, 3); for (int i = 0; i < amount; ++i) { - GameMessages::SendDropClientLoot(killer, self->GetObjectID(), 935, 0, self->GetPosition()); + GameMessages::DropClientLoot lootMsg{}; + lootMsg.target = killer->GetObjectID(); + lootMsg.ownerID = killer->GetObjectID(); + lootMsg.sourceID = self->GetObjectID(); + lootMsg.item = 935; + lootMsg.count = 1; + lootMsg.spawnPos = self->GetPosition(); + Loot::DropItem(*killer, lootMsg); } } } diff --git a/dScripts/ai/NS/NsQbImaginationStatue.cpp b/dScripts/ai/NS/NsQbImaginationStatue.cpp index 0d080d54..2a0b2107 100644 --- a/dScripts/ai/NS/NsQbImaginationStatue.cpp +++ b/dScripts/ai/NS/NsQbImaginationStatue.cpp @@ -1,6 +1,7 @@ #include "NsQbImaginationStatue.h" #include "EntityManager.h" #include "GameMessages.h" +#include "Loot.h" void NsQbImaginationStatue::OnStartup(Entity* self) { @@ -35,6 +36,12 @@ void NsQbImaginationStatue::SpawnLoot(Entity* self) { if (player == nullptr) return; - GameMessages::SendDropClientLoot(player, self->GetObjectID(), 935, 0); - GameMessages::SendDropClientLoot(player, self->GetObjectID(), 935, 0); + GameMessages::DropClientLoot lootMsg{}; + lootMsg.target = player->GetObjectID(); + lootMsg.ownerID = player->GetObjectID(); + lootMsg.sourceID = self->GetObjectID(); + lootMsg.item = 935; + lootMsg.count = 1; + Loot::DropItem(*player, lootMsg); + Loot::DropItem(*player, lootMsg); } From f3a5f60d81cb5582cf30170a3cc5797bcec25c7a Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Thu, 16 Oct 2025 12:15:02 -0700 Subject: [PATCH 3/3] feat: more destroyable debug info (#1912) * feat: more destroyable info * Change type and remove duplicate value --- dGame/Entity.cpp | 2 + dGame/dComponents/DestroyableComponent.cpp | 110 +++++++++++++++++---- dGame/dComponents/DestroyableComponent.h | 5 + dGame/dGameMessages/GameMessages.h | 1 + 4 files changed, 99 insertions(+), 19 deletions(-) diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index fee53aef..7d8046e0 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -424,6 +424,7 @@ void Entity::Initialize() { comp->SetIsSmashable(destCompData[0].isSmashable); comp->SetLootMatrixID(destCompData[0].LootMatrixIndex); + comp->SetCurrencyIndex(destCompData[0].CurrencyIndex); Loot::CacheMatrix(destCompData[0].LootMatrixIndex); // Now get currency information @@ -2252,6 +2253,7 @@ bool Entity::MsgRequestServerObjectInfo(GameMessages::GameMsg& msg) { response.Insert("objectID", std::to_string(m_ObjectID)); response.Insert("serverInfo", true); GameMessages::GetObjectReportInfo info{}; + info.clientID = requestInfo.clientId; info.bVerbose = requestInfo.bVerbose; info.info = response.InsertArray("data"); auto& objectInfo = info.info->PushDebug("Object Details"); diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index fabcd3ef..0658757c 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -3,6 +3,9 @@ #include "Logger.h" #include "Game.h" #include "dConfig.h" +#include "CDLootMatrixTable.h" +#include "CDLootTableTable.h" +#include "CDRarityTableTable.h" #include "Amf3.h" #include "AmfSerialize.h" @@ -1060,38 +1063,89 @@ void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source) { bool DestroyableComponent::OnGetObjectReportInfo(GameMessages::GameMsg& msg) { auto& reportInfo = static_cast(msg); - auto& destroyableInfo = reportInfo.info->PushDebug("Destroyable"); - destroyableInfo.PushDebug("Health") = m_iHealth; - destroyableInfo.PushDebug("Max Health") = m_fMaxHealth; - destroyableInfo.PushDebug("Armor") = m_iArmor; - destroyableInfo.PushDebug("Max Armor") = m_fMaxArmor; - destroyableInfo.PushDebug("Imagination") = m_iImagination; - destroyableInfo.PushDebug("Max Imagination") = m_fMaxImagination; - destroyableInfo.PushDebug("Damage To Absorb") = m_DamageToAbsorb; + destroyableInfo.PushDebug("DestructibleComponent DB Table Template ID") = m_ComponentID; + + if (m_CurrencyIndex == -1) { + destroyableInfo.PushDebug("Has Loot Currency") = false; + } else { + destroyableInfo.PushDebug("Loot Currency ID") = m_CurrencyIndex; + auto& detailedCoinInfo = destroyableInfo.PushDebug("Coin Info"); + detailedCoinInfo.PushDebug("Min Coins") = m_MinCoins; + detailedCoinInfo.PushDebug("Max Coins") = m_MaxCoins; + } + + if (m_LootMatrixID == -1 || m_LootMatrixID == 0) { + destroyableInfo.PushDebug("Has Loot Matrix") = false; + } else { + auto& lootInfo = destroyableInfo.PushDebug("Loot Info"); + lootInfo.PushDebug("Loot Matrix ID") = m_LootMatrixID; + auto* const componentsRegistryTable = CDClientManager::GetTable(); + auto* const itemComponentTable = CDClientManager::GetTable(); + auto* const lootMatrixTable = CDClientManager::GetTable(); + auto* const lootTableTable = CDClientManager::GetTable(); + auto* const rarityTableTable = CDClientManager::GetTable(); + + const auto& matrix = lootMatrixTable->GetMatrix(m_LootMatrixID); + + for (const auto& entry : matrix) { + auto& thisEntry = lootInfo.PushDebug("Loot table Index - " + std::to_string(entry.LootTableIndex)); + thisEntry.PushDebug("Percent chance to drop") = entry.percent * 100.0f; + thisEntry.PushDebug("Minimum amount to drop") = entry.minToDrop; + thisEntry.PushDebug("Maximum amount to drop") = entry.maxToDrop; + const auto& lootTable = lootTableTable->GetTable(entry.LootTableIndex); + const auto& rarityTable = rarityTableTable->GetRarityTable(entry.RarityTableIndex); + + auto& thisRarity = thisEntry.PushDebug("Rarity"); + for (const auto& rarity : rarityTable) { + thisRarity.PushDebug("Rarity " + std::to_string(rarity.rarity)) = rarity.randmax; + } + + auto& thisItems = thisEntry.PushDebug("Drop(s) Info"); + for (const auto& loot : lootTable) { + uint32_t itemComponentId = componentsRegistryTable->GetByIDAndType(loot.itemid, eReplicaComponentType::ITEM); + uint32_t rarity = itemComponentTable->GetItemComponentByID(itemComponentId).rarity; + auto title = "%[Objects_" + std::to_string(loot.itemid) + "_name] " + std::to_string(loot.itemid); + if (loot.MissionDrop) title += " - Mission Drop"; + thisItems.PushDebug(title); + } + } + } + + auto* const entity = Game::entityManager->GetEntity(reportInfo.clientID); + destroyableInfo.PushDebug("Is on your team") = entity ? IsFriend(entity) : false; + auto& stats = destroyableInfo.PushDebug("Statistics"); + stats.PushDebug("Health") = m_iHealth; + stats.PushDebug("Maximum Health") = m_fMaxHealth; + stats.PushDebug("Armor") = m_iArmor; + stats.PushDebug("Maximum Armor") = m_fMaxArmor; + stats.PushDebug("Imagination") = m_iImagination; + stats.PushDebug("Maximum Imagination") = m_fMaxImagination; + stats.PushDebug("Damage Absorption Points") = m_DamageToAbsorb; destroyableInfo.PushDebug("Is GM Immune") = m_IsGMImmune; destroyableInfo.PushDebug("Is Shielded") = m_IsShielded; destroyableInfo.PushDebug("Attacks To Block") = m_AttacksToBlock; destroyableInfo.PushDebug("Damage Reduction") = m_DamageReduction; - auto& factions = destroyableInfo.PushDebug("Factions"); - size_t i = 0; + std::stringstream factionsStream; for (const auto factionID : m_FactionIDs) { - factions.PushDebug(std::to_string(i++) + " " + std::to_string(factionID)) = ""; + factionsStream << factionID << " "; } - auto& enemyFactions = destroyableInfo.PushDebug("Enemy Factions"); - i = 0; + + destroyableInfo.PushDebug("Factions") = factionsStream.str(); + + factionsStream.str(""); for (const auto enemyFactionID : m_EnemyFactionIDs) { - enemyFactions.PushDebug(std::to_string(i++) + " " + std::to_string(enemyFactionID)) = ""; + factionsStream << enemyFactionID << " "; } + + destroyableInfo.PushDebug("Enemy Factions") = factionsStream.str(); + destroyableInfo.PushDebug("Is Smashable") = m_IsSmashable; - destroyableInfo.PushDebug("Is Dead") = m_IsDead; destroyableInfo.PushDebug("Is Smashed") = m_IsSmashed; destroyableInfo.PushDebug("Is Module Assembly") = m_IsModuleAssembly; destroyableInfo.PushDebug("Explode Factor") = m_ExplodeFactor; destroyableInfo.PushDebug("Has Threats") = m_HasThreats; - destroyableInfo.PushDebug("Loot Matrix ID") = m_LootMatrixID; - destroyableInfo.PushDebug("Min Coins") = m_MinCoins; - destroyableInfo.PushDebug("Max Coins") = m_MaxCoins; + destroyableInfo.PushDebug("Killer ID") = std::to_string(m_KillerID); // "Scripts"; idk what to do about scripts yet @@ -1106,7 +1160,25 @@ bool DestroyableComponent::OnGetObjectReportInfo(GameMessages::GameMsg& msg) { immuneCounts.PushDebug("Quickbuild Interrupt") = m_ImmuneToQuickbuildInterruptCount; immuneCounts.PushDebug("Pull To Point") = m_ImmuneToPullToPointCount; - destroyableInfo.PushDebug("Death Behavior") = m_DeathBehavior; + auto& deathInfo = destroyableInfo.PushDebug("Death Info"); + deathInfo.PushDebug("Is Dead") = m_IsDead; + switch (m_DeathBehavior) { + case 0: + deathInfo.PushDebug("Death Behavior") = "Fade"; + break; + case 1: + deathInfo.PushDebug("Death Behavior") = "Stay"; + break; + case 2: + deathInfo.PushDebug("Death Behavior") = "Immediate"; + break; + case -1: + deathInfo.PushDebug("Death Behavior") = "Invulnerable"; + break; + default: + deathInfo.PushDebug("Death Behavior") = "Other"; + break; + } destroyableInfo.PushDebug("Damage Cooldown Timer") = m_DamageCooldownTimer; return true; diff --git a/dGame/dComponents/DestroyableComponent.h b/dGame/dComponents/DestroyableComponent.h index c6bb0a98..9b3e46af 100644 --- a/dGame/dComponents/DestroyableComponent.h +++ b/dGame/dComponents/DestroyableComponent.h @@ -370,6 +370,8 @@ public: */ uint32_t GetLootMatrixID() const { return m_LootMatrixID; } + void SetCurrencyIndex(int32_t currencyIndex) { m_CurrencyIndex = currencyIndex; } + /** * Returns the ID of the entity that killed this entity, if any * @return the ID of the entity that killed this entity, if any @@ -587,6 +589,9 @@ private: */ uint32_t m_LootMatrixID; + // The currency index to determine how much loot to drop + int32_t m_CurrencyIndex{ -1 }; + /** * The min amount of coins that will drop when this entity is smashed */ diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index 5c682075..1b52d67a 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -793,6 +793,7 @@ namespace GameMessages { AMFArrayValue* info{}; AMFArrayValue* subCategory{}; bool bVerbose{}; + LWOOBJID clientID{}; GetObjectReportInfo() : GameMsg(MessageType::Game::GET_OBJECT_REPORT_INFO, eGameMasterLevel::DEVELOPER) {} };