diff --git a/dGame/dUtilities/Loot.cpp b/dGame/dUtilities/Loot.cpp index a03dbcae7..20549b401 100644 --- a/dGame/dUtilities/Loot.cpp +++ b/dGame/dUtilities/Loot.cpp @@ -335,7 +335,8 @@ void DropRegularLoot(Team& team, GameMessages::DropClientLoot& lootMsg, const bo DistrbuteMsgToTeam(lootMsg, team); } -void DropLoot(Entity* player, const LWOOBJID source, const std::map& rolledItems, uint32_t minCoins, uint32_t maxCoins, const bool noTeamLootOnDeath) { +// source: the DropClientLoot source object; spawnPosition: where the loot spawns +void DropLoot(Entity* player, const LWOOBJID source, const NiPoint3& spawnPosition, const std::map& rolledItems, uint32_t minCoins, uint32_t maxCoins, const bool noTeamLootOnDeath) { player = player->GetOwner(); // if the owner is overwritten, we collect that here const auto playerID = player->GetObjectID(); if (!player->IsPlayer()) { @@ -352,11 +353,6 @@ void DropLoot(Entity* player, const LWOOBJID source, const std::mapGetTeam(playerID); - GameMessages::GetPosition posMsg; - posMsg.target = source; - posMsg.Send(); - - const auto spawnPosition = posMsg.pos; auto* const objectsTable = CDClientManager::GetTable(); for (const auto& [lootLot, info] : rolledItems) { @@ -590,23 +586,36 @@ void Loot::GiveActivityLoot(Entity* player, const LWOOBJID source, uint32_t acti character->SetCoins(character->GetCoins() + coins, eLootSourceType::ACTIVITY, CoinSource::Object(*player)); } -void Loot::DropLoot(Entity* player, const LWOOBJID source, uint32_t matrixIndex, uint32_t minCoins, uint32_t maxCoins) { - player = player->GetOwner(); // if the owner is overwritten, we collect that here +namespace { + NiPoint3 GetDropSpawnPosition(const LWOOBJID object) { + GameMessages::GetPosition posMsg; + posMsg.target = object; + posMsg.Send(); + return posMsg.pos; + } - auto* scriptedActivityComponent = Game::entityManager->GetZoneControlEntity()->GetComponent(); - const bool noTeamLootOnDeath = scriptedActivityComponent ? scriptedActivityComponent->GetNoTeamLootOnDeath() : false; + void RollAndDropLoot(Entity* player, const LWOOBJID source, const NiPoint3& spawnPosition, uint32_t matrixIndex, uint32_t minCoins, uint32_t maxCoins) { + player = player->GetOwner(); // if the owner is overwritten, we collect that here - auto* inventoryComponent = player->GetComponent(); + auto* scriptedActivityComponent = Game::entityManager->GetZoneControlEntity()->GetComponent(); + const bool noTeamLootOnDeath = scriptedActivityComponent ? scriptedActivityComponent->GetNoTeamLootOnDeath() : false; - if (!inventoryComponent) - return; + auto* inventoryComponent = player->GetComponent(); - const auto result = ::RollLootMatrix(matrixIndex, LiveEvents::LootChanceMultiplier()); + if (!inventoryComponent) + return; - ::DropLoot(player, source, result, minCoins, maxCoins, noTeamLootOnDeath); + const auto result = ::RollLootMatrix(matrixIndex, LiveEvents::LootChanceMultiplier()); + + ::DropLoot(player, source, spawnPosition, result, minCoins, maxCoins, noTeamLootOnDeath); + } } -void Loot::DropActivityLoot(Entity* player, const LWOOBJID source, uint32_t activityID, int32_t rating) { +void Loot::DropLoot(Entity* player, const LWOOBJID source, uint32_t matrixIndex, uint32_t minCoins, uint32_t maxCoins) { + RollAndDropLoot(player, source, GetDropSpawnPosition(source), matrixIndex, minCoins, maxCoins); +} + +void Loot::DropActivityLoot(Entity* player, const LWOOBJID source, uint32_t activityID, int32_t rating, const bool fromPlayer) { CDActivityRewardsTable* activityRewardsTable = CDClientManager::GetTable(); std::vector activityRewards = activityRewardsTable->Query([activityID](CDActivityRewards entry) { return (entry.objectTemplate == activityID); }); @@ -623,5 +632,7 @@ void Loot::DropActivityLoot(Entity* player, const LWOOBJID source, uint32_t acti const auto [minCoins, maxCoins] = GetActivityCoinRange(*selectedReward); - DropLoot(player, source, selectedReward->LootMatrixIndex, minCoins, maxCoins); + // Live sent activity rewards from the player who earned them, spawning at the activity object + const auto dropSource = fromPlayer ? player->GetOwner()->GetObjectID() : source; + RollAndDropLoot(player, dropSource, GetDropSpawnPosition(source), selectedReward->LootMatrixIndex, minCoins, maxCoins); } diff --git a/dGame/dUtilities/Loot.h b/dGame/dUtilities/Loot.h index b05a7cf4c..f6bb0bd92 100644 --- a/dGame/dUtilities/Loot.h +++ b/dGame/dUtilities/Loot.h @@ -31,7 +31,12 @@ namespace Loot { void GiveActivityLoot(Entity* player, const LWOOBJID source, uint32_t activityID, int32_t rating = 0); void DropLoot(Entity* player, const LWOOBJID source, uint32_t matrixIndex, uint32_t minCoins, uint32_t maxCoins); void DropItem(Entity& player, GameMessages::DropClientLoot& lootMsg, bool useTeam = false, bool forceFfa = false); - void DropActivityLoot(Entity* player, const LWOOBJID source, uint32_t activityID, int32_t rating = 0); + /** + * Drops the loot of an activity's reward for the given rating, spawning at the source object. + * fromPlayer: the DropClientLoot source is the player instead of the object, as live sent quickbuild, chest and + * wishing well rewards (use_position true, spawn position the object's). + */ + void DropActivityLoot(Entity* player, const LWOOBJID source, uint32_t activityID, int32_t rating = 0, bool fromPlayer = true); /** * The coin range {min, max} of an ActivityRewards row, as live rolled it: the reward's ChallengeRating is the diff --git a/dScripts/02_server/Map/General/GrowingFlower.cpp b/dScripts/02_server/Map/General/GrowingFlower.cpp index 2c3929e20..12ccce8f2 100644 --- a/dScripts/02_server/Map/General/GrowingFlower.cpp +++ b/dScripts/02_server/Map/General/GrowingFlower.cpp @@ -16,7 +16,8 @@ void GrowingFlower::OnSkillEventFired(Entity* self, Entity* target, const std::s auto* scriptedActivityComponent = self->GetComponent(); if (scriptedActivityComponent != nullptr) { - Loot::DropActivityLoot(target, self->GetObjectID(), scriptedActivityComponent->GetActivityID(), 0); + // No live samples of this drop: kept sourced from the flower + Loot::DropActivityLoot(target, self->GetObjectID(), scriptedActivityComponent->GetActivityID(), 0, false); } auto* missionComponent = target->GetComponent(); diff --git a/dScripts/02_server/Map/VE/VeMissionConsole.cpp b/dScripts/02_server/Map/VE/VeMissionConsole.cpp index 443c9a570..bf731d232 100644 --- a/dScripts/02_server/Map/VE/VeMissionConsole.cpp +++ b/dScripts/02_server/Map/VE/VeMissionConsole.cpp @@ -7,7 +7,8 @@ #include "eTerminateType.h" void VeMissionConsole::OnUse(Entity* self, Entity* user) { - Loot::DropActivityLoot(user, self->GetObjectID(), 12551); + // No live samples of this drop: kept sourced from the console + Loot::DropActivityLoot(user, self->GetObjectID(), 12551, 0, false); auto* inventoryComponent = user->GetComponent(); if (inventoryComponent != nullptr) {