feat(combat): destroyables keep their attack priority

DestructibleComponent.attack_priority is loaded onto the DestroyableComponent as a signed value. The client's
LWODestroyableComponent (LoadDataFromTemplate, 0x00c9f900) starts it at 1 and keeps 1 when the column is empty, and
answers GetAttackPriority with it; the server now does the same so TacArcs can order their targets by it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-09-29 20:58:12 -05:00
parent 044933ebee
commit e017c11aa2
4 changed files with 12 additions and 2 deletions

View File

@@ -31,7 +31,7 @@ void CDDestructibleComponentTable::LoadValuesFromDatabase() {
entry.armor = tableData.getFloatField("armor", -1.0f); entry.armor = tableData.getFloatField("armor", -1.0f);
entry.death_behavior = tableData.getIntField("death_behavior", -1); entry.death_behavior = tableData.getIntField("death_behavior", -1);
entry.isnpc = tableData.getIntField("isnpc", -1) == 1 ? true : false; entry.isnpc = tableData.getIntField("isnpc", -1) == 1 ? true : false;
entry.attack_priority = tableData.getIntField("attack_priority", -1); entry.attack_priority = tableData.getIntField("attack_priority", 1);
entry.isSmashable = tableData.getIntField("isSmashable", -1) == 1 ? true : false; entry.isSmashable = tableData.getIntField("isSmashable", -1) == 1 ? true : false;
entry.difficultyLevel = tableData.getIntField("difficultyLevel", -1); entry.difficultyLevel = tableData.getIntField("difficultyLevel", -1);

View File

@@ -15,7 +15,7 @@ struct CDDestructibleComponent {
float armor; //!< The amount of armor of the object float armor; //!< The amount of armor of the object
uint32_t death_behavior; //!< The behavior ID of the death behavior uint32_t death_behavior; //!< The behavior ID of the death behavior
bool isnpc; //!< Whether or not the object is an NPC bool isnpc; //!< Whether or not the object is an NPC
uint32_t attack_priority; //!< ??? int32_t attack_priority; //!< TacArc target order, lower first; 1 when unset
bool isSmashable; //!< Whether or not the object is smashable bool isSmashable; //!< Whether or not the object is smashable
int32_t difficultyLevel; //!< ??? int32_t difficultyLevel; //!< ???
}; };

View File

@@ -439,6 +439,7 @@ void Entity::Initialize() {
comp->SetIsSmashable(comp->GetIsSmashable() || destCompData[0].isSmashable); comp->SetIsSmashable(comp->GetIsSmashable() || destCompData[0].isSmashable);
comp->SetIsNPC(destCompData[0].isnpc); comp->SetIsNPC(destCompData[0].isnpc);
comp->SetAttackPriority(destCompData[0].attack_priority);
comp->SetLootMatrixID(destCompData[0].LootMatrixIndex); comp->SetLootMatrixID(destCompData[0].LootMatrixIndex);
comp->SetCurrencyIndex(destCompData[0].CurrencyIndex); comp->SetCurrencyIndex(destCompData[0].CurrencyIndex);

View File

@@ -253,6 +253,12 @@ public:
void SetIsNPC(bool value) { m_IsNPC = value; } void SetIsNPC(bool value) { m_IsNPC = value; }
bool GetIsNPC() const { return m_IsNPC; } bool GetIsNPC() const { return m_IsNPC; }
/**
* The DestructibleComponent's attack_priority: TacArcs that use attack priority target lower values first
*/
void SetAttackPriority(const int32_t value) { m_AttackPriority = value; }
int32_t GetAttackPriority() const { return m_AttackPriority; }
/** /**
* Returns the current is-dead value, this is mostly unused * Returns the current is-dead value, this is mostly unused
* @return the current is-dead value, this is mostly unused * @return the current is-dead value, this is mostly unused
@@ -606,6 +612,9 @@ private:
bool m_IsNPC = false; bool m_IsNPC = false;
// The client's LWODestroyableComponent starts at 1 and keeps it when the column is empty
int32_t m_AttackPriority = 1;
/** /**
* Whether this entity is dead. Unused, here for serialization * Whether this entity is dead. Unused, here for serialization
*/ */