mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-15 17:14:07 +00:00
fix(loot): DropClientLoot positions like live
Live DropClientLoot (12,501 decoded): use_position is set only when a player is the source (1,432, all activity rewards such as the dragon, Frakjaw and BONS chests); drops from enemies, smashables and chests leave it clear, so the client spawns the loot at the source object as it sees it and falls back to spawn_position only if that object is gone (LWODestroyableComponent::GetLootSpawnPos). Coins land where they spawn (final = spawn in all 3,158 coin drops); items land 10 units away (median 9.998, uniform direction) at spawn height. DLU always set use_position and scattered everything 4.2 units away. Inferred: the 10-unit rule for player-sourced items (live spread there ranges 0-58 units, source unknown). Check: kill enemies and smash crates: coins pop out of the object, items fly about 10 units away; open an activity chest (e.g. after a dragon or Frakjaw) and the loot still appears around you. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include "LiveEvents.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "CDComponentsRegistryTable.h"
|
||||
@@ -97,21 +98,24 @@ std::map<LOT, LootDropInfo> RollLootMatrix(uint32_t matrixIndex, float chanceMul
|
||||
return drops;
|
||||
}
|
||||
|
||||
// Generates a 'random' final position for the loot drop based on its input spawn position.
|
||||
void CalcFinalDropPos(GameMessages::DropClientLoot& lootMsg) {
|
||||
if (lootMsg.spawnPos != NiPoint3Constant::ZERO) {
|
||||
lootMsg.bUsePosition = true;
|
||||
void Loot::SetDropPositions(GameMessages::DropClientLoot& lootMsg, const bool sourceIsPlayer, const float angle) {
|
||||
if (lootMsg.spawnPos == NiPoint3Constant::ZERO) return;
|
||||
|
||||
//Calculate where the loot will go:
|
||||
uint16_t degree = GeneralUtils::GenerateRandomNumber<uint16_t>(0, 360);
|
||||
|
||||
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<float>(x + sin_v), y, static_cast<float>(z + cos_v));
|
||||
lootMsg.bUsePosition = sourceIsPlayer;
|
||||
if (lootMsg.currency > 0) {
|
||||
lootMsg.finalPosition = lootMsg.spawnPos;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto [x, y, z] = lootMsg.spawnPos;
|
||||
lootMsg.finalPosition = NiPoint3(x + std::sin(angle) * ITEM_DROP_DISTANCE, y, z + std::cos(angle) * ITEM_DROP_DISTANCE);
|
||||
}
|
||||
|
||||
// Picks where the loot lands, in a random direction.
|
||||
void CalcFinalDropPos(GameMessages::DropClientLoot& lootMsg) {
|
||||
const auto* const source = Game::entityManager->GetEntity(lootMsg.sourceID);
|
||||
const auto angle = GeneralUtils::GenerateRandomNumber<float>(0.0f, 6.28318531f);
|
||||
Loot::SetDropPositions(lootMsg, source && source->IsPlayer(), angle);
|
||||
}
|
||||
|
||||
// Visually drop the loot to all team members, though only the lootMsg.ownerID can pick it up
|
||||
|
||||
Reference in New Issue
Block a user