mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 10:53:44 +00:00
feat(loot): smashables use the level's smashable_loot_matrix
A level object's smashable_loot_matrix replaces the DestructibleComponent LootMatrixIndex when smashable_loot_matrix_set is true or absent and the matrix is not -1, as the client resolves it (LWODestroyableComponent::LoadConfigData 0x00c44cb0). DLU only read the key in BaseInteractDropLootServer, so tagged smashables dropped their template's loot. Resolution in DestroyableComponent::GetLevelLootMatrix, with tests. No wire change. In game: smash level smashables that carry smashable_loot_matrix_set=1 (11 level objects in the 1.10.64 levels) and ones with a matrix but no _set key; they drop the level's loot instead of the template's. Ordinary smashables (smashable_loot_matrix_set=0) drop what they did before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -493,6 +493,13 @@ void Entity::Initialize() {
|
||||
comp->SetFaction(levelFactions->front(), true);
|
||||
for (const auto faction : *levelFactions | std::views::drop(1)) comp->AddFaction(faction, true);
|
||||
}
|
||||
|
||||
// Level files can give a smashable its own loot matrix in place of the template's
|
||||
const auto levelLootMatrix = DestroyableComponent::GetLevelLootMatrix(*this);
|
||||
if (!m_Character && levelLootMatrix) {
|
||||
comp->SetLootMatrixID(levelLootMatrix.value());
|
||||
Loot::CacheMatrix(levelLootMatrix.value());
|
||||
}
|
||||
}
|
||||
|
||||
const auto characterID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CHARACTER);
|
||||
|
||||
@@ -806,6 +806,15 @@ std::optional<std::vector<int32_t>> DestroyableComponent::GetLevelFactions(const
|
||||
return factions;
|
||||
}
|
||||
|
||||
std::optional<int32_t> DestroyableComponent::GetLevelLootMatrix(const Entity& entity) {
|
||||
if (entity.HasVar(u"smashable_loot_matrix_set") && !entity.GetVar<bool>(u"smashable_loot_matrix_set")) return std::nullopt;
|
||||
if (!entity.HasVar(u"smashable_loot_matrix")) return std::nullopt;
|
||||
|
||||
const auto lootMatrix = entity.GetVar<int32_t>(u"smashable_loot_matrix");
|
||||
if (lootMatrix == -1) return std::nullopt;
|
||||
return lootMatrix;
|
||||
}
|
||||
|
||||
void DestroyableComponent::SetFaction(int32_t factionID, bool ignoreChecks) {
|
||||
m_FactionIDs.clear();
|
||||
m_EnemyFactionIDs.clear();
|
||||
|
||||
@@ -377,6 +377,14 @@ public:
|
||||
*/
|
||||
static std::optional<std::vector<int32_t>> GetLevelFactions(const Entity& entity);
|
||||
|
||||
/**
|
||||
* The loot matrix a level object's smashable_loot_matrix gives it in place of the template's LootMatrixIndex,
|
||||
* resolved as the client does (LWODestroyableComponent::LoadConfigData 0x00c44cb0): used when
|
||||
* smashable_loot_matrix_set is true or absent, unless the matrix is -1.
|
||||
* @return the loot matrix, or nullopt when the template's stays
|
||||
*/
|
||||
static std::optional<int32_t> GetLevelLootMatrix(const Entity& entity);
|
||||
|
||||
/**
|
||||
* Returns the ID of the entity that killed this entity, if any
|
||||
* @return the ID of the entity that killed this entity, if any
|
||||
|
||||
@@ -44,3 +44,33 @@ TEST_F(DestroyableLevelConfigTests, OverrideFactionFalseIgnoresSetFaction) {
|
||||
entity->SetVar<bool>(u"override_faction", false);
|
||||
EXPECT_FALSE(DestroyableComponent::GetLevelFactions(*entity));
|
||||
}
|
||||
|
||||
TEST_F(DestroyableLevelConfigTests, NoLootMatrixKeysKeepTheTemplateLootMatrix) {
|
||||
EXPECT_FALSE(DestroyableComponent::GetLevelLootMatrix(*entity));
|
||||
entity->SetVar<bool>(u"smashable_loot_matrix_set", true);
|
||||
EXPECT_FALSE(DestroyableComponent::GetLevelLootMatrix(*entity));
|
||||
}
|
||||
|
||||
TEST_F(DestroyableLevelConfigTests, LootMatrixWithoutTheSetKeyIsUsed) {
|
||||
entity->SetVar<int32_t>(u"smashable_loot_matrix", 748);
|
||||
EXPECT_EQ(DestroyableComponent::GetLevelLootMatrix(*entity), 748);
|
||||
}
|
||||
|
||||
TEST_F(DestroyableLevelConfigTests, LootMatrixWithTheSetKeyTrueIsUsed) {
|
||||
entity->SetVar<int32_t>(u"smashable_loot_matrix", 352);
|
||||
entity->SetVar<bool>(u"smashable_loot_matrix_set", true);
|
||||
EXPECT_EQ(DestroyableComponent::GetLevelLootMatrix(*entity), 352);
|
||||
}
|
||||
|
||||
TEST_F(DestroyableLevelConfigTests, LootMatrixWithTheSetKeyFalseIsIgnored) {
|
||||
entity->SetVar<int32_t>(u"smashable_loot_matrix", 227);
|
||||
entity->SetVar<bool>(u"smashable_loot_matrix_set", false);
|
||||
EXPECT_FALSE(DestroyableComponent::GetLevelLootMatrix(*entity));
|
||||
}
|
||||
|
||||
TEST_F(DestroyableLevelConfigTests, LootMatrixMinusOneIsIgnored) {
|
||||
entity->SetVar<int32_t>(u"smashable_loot_matrix", -1);
|
||||
EXPECT_FALSE(DestroyableComponent::GetLevelLootMatrix(*entity));
|
||||
entity->SetVar<bool>(u"smashable_loot_matrix_set", true);
|
||||
EXPECT_FALSE(DestroyableComponent::GetLevelLootMatrix(*entity));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user