Files
DarkflameServer/dGame/dUtilities/Loot.h
Aaron Kimbrell 898ae024f0 feat(loot): a picked up item says which object it dropped from
Live's AddItemToInventoryClientSync for a picked up drop had
_Metric_Souce_LOT_Int in its extra info on all 2,344 live pickups: the LOT
of the DropClientLoot's source object, 1 when a player was the source
(activity rewards and chests, which drop from the player). DLU sent none.

The drop remembers its source object's LOT when it is registered for the
player, and the pickup sends it. A source object already gone when it drops sends
no key. Package contents keep sending none, as live's did.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:45:59 -05:00

65 lines
3.0 KiB
C++

#pragma once
#include "dCommonVars.h"
#include "eLootSourceType.h"
#include <map>
#include <unordered_map>
#include <utility>
#include <vector>
class Entity;
struct CDActivityRewards;
struct CDCurrencyTable;
namespace GameMessages {
struct DropClientLoot;
};
namespace Loot {
struct Info {
LWOOBJID id = 0;
LOT lot = 0;
int32_t count = 0;
// The LOT of the object it dropped from (1 when a player was the source), 0 when that object was not found.
// Sent back as the item's source when it is picked up (LootMetrics::sourceLot).
LOT sourceLot = 0;
};
using Return = std::map<LOT, int32_t>;
Loot::Return RollLootMatrix(Entity* player, uint32_t matrixIndex);
void CacheMatrix(const uint32_t matrixIndex);
void GiveLoot(Entity* player, uint32_t matrixIndex, eLootSourceType lootSourceType = eLootSourceType::NONE);
void GiveLoot(Entity* player, const Loot::Return& result, eLootSourceType lootSourceType = eLootSourceType::NONE);
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);
/**
* 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
* CurrencyTable npcminlevel, and level 1 is used when the currency index has no row for that level.
* currencyRows are the CurrencyTable rows of the reward's CurrencyIndex. {0, 0} when neither level has a row.
*/
std::pair<uint32_t, uint32_t> GetActivityCoinRange(const std::vector<CDCurrencyTable>& currencyRows, uint32_t challengeRating);
std::pair<uint32_t, uint32_t> GetActivityCoinRange(const CDActivityRewards& reward);
// How far from where it spawns a dropped item lands, as live dropped them (median 10.0 units, uniform direction).
constexpr float ITEM_DROP_DISTANCE = 10.0f;
/**
* Fills DropClientLoot's use_position and final_position the way live did (12,501 live DropClientLoot).
* use_position is set only when a player is the source (activity rewards such as the dragon and BONS chests):
* otherwise the client spawns the loot at the source object where it is on the client, and only falls back
* to the spawn position if that object is gone. Coins land where they spawn; items land ITEM_DROP_DISTANCE away
* at the given angle (radians, around Y).
* Nothing is set when there is no spawn position.
*/
void SetDropPositions(GameMessages::DropClientLoot& lootMsg, bool sourceIsPlayer, float angle);
};