mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 02:43:44 +00:00
feat(stats): heals, repairs and restores count what they applied
Live sent TotalArmorRepaired / TotalImaginationRestored with what a repair or restore applied, 0 included (1,050 and 2,148 zeros in the captures: a power-up picked up at full), and never a TotalDamageHealed or TotalDamageTaken of 0. DLU counted every change of the value instead, so setting stats up (loading, respawning, level changes) counted as healing and a heal at full health counted as 0 damage taken. Now Heal, Repair and Imagine count what they applied; health lost and imagination spent still count wherever they change. Check in game: pick up an armor or imagination power-up when full; the passport's Armor Repaired / Imagination Restored stay the same. Take damage and heal; Damage Taken and Damage Healed go up by what the bar shows. Respawn: Damage Healed doesn't jump. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -585,15 +585,16 @@ std::optional<StatisticID> CharacterComponent::GetPowerUpStatistic(const LOT lot
|
||||
}
|
||||
|
||||
void CharacterComponent::TrackHealthDelta(int32_t health) {
|
||||
// Live sent no TotalDamageHealed or TotalDamageTaken of 0
|
||||
if (health > 0) {
|
||||
UpdatePlayerStatistic(TotalDamageHealed, health);
|
||||
} else {
|
||||
} else if (health < 0) {
|
||||
UpdatePlayerStatistic(TotalDamageTaken, -health);
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterComponent::TrackImaginationDelta(int32_t imagination) {
|
||||
if (imagination > 0) {
|
||||
if (imagination >= 0) {
|
||||
UpdatePlayerStatistic(TotalImaginationRestored, imagination);
|
||||
} else {
|
||||
UpdatePlayerStatistic(TotalImaginationUsed, -imagination);
|
||||
@@ -601,7 +602,7 @@ void CharacterComponent::TrackImaginationDelta(int32_t imagination) {
|
||||
}
|
||||
|
||||
void CharacterComponent::TrackArmorDelta(int32_t armor) {
|
||||
if (armor > 0) {
|
||||
if (armor >= 0) {
|
||||
UpdatePlayerStatistic(TotalArmorRepaired, armor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,19 +201,20 @@ public:
|
||||
static std::optional<StatisticID> GetPowerUpStatistic(LOT lot);
|
||||
|
||||
/**
|
||||
* Handles a change in health and updates the statistics
|
||||
* Handles a change in health and updates the statistics: healing applied (DestroyableComponent::Heal) or health lost
|
||||
* @param health the health delta
|
||||
*/
|
||||
void TrackHealthDelta(int32_t health);
|
||||
|
||||
/**
|
||||
* Handles a change in imagination and updates the statistics
|
||||
* Handles a change in imagination and updates the statistics: restored (DestroyableComponent::Imagine, 0 included)
|
||||
* or spent
|
||||
* @param imagination the imagination delta
|
||||
*/
|
||||
void TrackImaginationDelta(int32_t imagination);
|
||||
|
||||
/**
|
||||
* Handles a change in armor and updates the statistics
|
||||
* Handles armor repaired (DestroyableComponent::Repair, 0 included) and updates the statistics
|
||||
* @param armor the armor delta
|
||||
*/
|
||||
void TrackArmorDelta(int32_t armor);
|
||||
|
||||
@@ -208,8 +208,9 @@ void DestroyableComponent::UpdateXml(tinyxml2::XMLDocument& doc) {
|
||||
void DestroyableComponent::SetHealth(int32_t value) {
|
||||
m_DirtyHealth = true;
|
||||
|
||||
// Health lost counts as damage taken; healing counts where it is applied (Heal)
|
||||
auto* characterComponent = m_Parent->GetComponent<CharacterComponent>();
|
||||
if (characterComponent != nullptr) {
|
||||
if (characterComponent != nullptr && value < m_iHealth) {
|
||||
characterComponent->TrackHealthDelta(value - m_iHealth);
|
||||
}
|
||||
|
||||
@@ -251,11 +252,6 @@ void DestroyableComponent::SetArmor(int32_t value) {
|
||||
// If Destroyable Component already has zero armor do not trigger the passive ability again.
|
||||
bool hadArmor = m_iArmor > 0;
|
||||
|
||||
auto* characterComponent = m_Parent->GetComponent<CharacterComponent>();
|
||||
if (characterComponent != nullptr) {
|
||||
characterComponent->TrackArmorDelta(value - m_iArmor);
|
||||
}
|
||||
|
||||
m_iArmor = value;
|
||||
|
||||
auto* inventroyComponent = m_Parent->GetComponent<InventoryComponent>();
|
||||
@@ -294,8 +290,9 @@ void DestroyableComponent::SetMaxArmor(float value, bool playAnim) {
|
||||
void DestroyableComponent::SetImagination(int32_t value) {
|
||||
m_DirtyHealth = true;
|
||||
|
||||
// Imagination spent counts as used; restoring counts where it is applied (Imagine)
|
||||
auto* characterComponent = m_Parent->GetComponent<CharacterComponent>();
|
||||
if (characterComponent != nullptr) {
|
||||
if (characterComponent != nullptr && value < m_iImagination) {
|
||||
characterComponent->TrackImaginationDelta(value - m_iImagination);
|
||||
}
|
||||
|
||||
@@ -499,8 +496,12 @@ void DestroyableComponent::Heal(const uint32_t health) {
|
||||
|
||||
current = std::min(current, max);
|
||||
|
||||
const auto before = GetHealth();
|
||||
SetHealth(current);
|
||||
|
||||
auto* characterComponent = m_Parent->GetComponent<CharacterComponent>();
|
||||
if (characterComponent) characterComponent->TrackHealthDelta(GetHealth() - before);
|
||||
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
}
|
||||
|
||||
@@ -517,8 +518,13 @@ void DestroyableComponent::Imagine(const int32_t deltaImagination) {
|
||||
current = 0;
|
||||
}
|
||||
|
||||
const auto before = GetImagination();
|
||||
SetImagination(current);
|
||||
|
||||
// What was restored, 0 included (live sent TotalImaginationRestored 0 for a power-up picked up when full)
|
||||
auto* characterComponent = m_Parent->GetComponent<CharacterComponent>();
|
||||
if (characterComponent && deltaImagination > 0) characterComponent->TrackImaginationDelta(GetImagination() - before);
|
||||
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
}
|
||||
|
||||
@@ -531,8 +537,13 @@ void DestroyableComponent::Repair(const uint32_t armor) {
|
||||
|
||||
current = std::min(current, max);
|
||||
|
||||
const auto before = GetArmor();
|
||||
SetArmor(current);
|
||||
|
||||
// What was repaired, 0 included (live sent TotalArmorRepaired 0 when the armor was already full)
|
||||
auto* characterComponent = m_Parent->GetComponent<CharacterComponent>();
|
||||
if (characterComponent) characterComponent->TrackArmorDelta(GetArmor() - before);
|
||||
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
}
|
||||
|
||||
|
||||
@@ -174,3 +174,33 @@ TEST_F(PlayerStatisticTest, SmashingCountsEnemiesAndSmashables) {
|
||||
EXPECT_TRUE(Statistics(smash(false, false)).empty());
|
||||
killer->SetCharacter(nullptr);
|
||||
}
|
||||
|
||||
// Live: what a heal, repair or restore applied, 0 included for armor and imagination (a power-up picked up when full);
|
||||
// no TotalDamageHealed of 0
|
||||
TEST_F(PlayerStatisticTest, HealsRepairsAndRestoresCountWhatTheyApplied) {
|
||||
auto* destroyable = entity->AddComponent<DestroyableComponent>(-1);
|
||||
destroyable->SetMaxHealth(10.0f);
|
||||
destroyable->SetMaxArmor(10.0f);
|
||||
destroyable->SetMaxImagination(10.0f);
|
||||
destroyable->SetHealth(10);
|
||||
destroyable->SetArmor(8);
|
||||
destroyable->SetImagination(10);
|
||||
|
||||
const auto sent = [&](const std::function<void()>& action) {
|
||||
std::vector<std::pair<int32_t, int64_t>> out;
|
||||
for (const auto& statistic : Statistics(Capture(action))) out.emplace_back(statistic.updateID, statistic.updateValue);
|
||||
return out;
|
||||
};
|
||||
using Sent = std::vector<std::pair<int32_t, int64_t>>;
|
||||
|
||||
EXPECT_EQ(sent([&] { destroyable->Heal(5); }), Sent{});
|
||||
EXPECT_EQ(sent([&] { destroyable->Repair(5); }), (Sent{ { TotalArmorRepaired, 2 } }));
|
||||
EXPECT_EQ(sent([&] { destroyable->Repair(5); }), (Sent{ { TotalArmorRepaired, 0 } }));
|
||||
EXPECT_EQ(sent([&] { destroyable->Imagine(3); }), (Sent{ { TotalImaginationRestored, 0 } }));
|
||||
EXPECT_EQ(sent([&] { destroyable->Imagine(-4); }), (Sent{ { TotalImaginationUsed, 4 } }));
|
||||
EXPECT_EQ(sent([&] { destroyable->Imagine(6); }), (Sent{ { TotalImaginationRestored, 4 } }));
|
||||
EXPECT_EQ(sent([&] { destroyable->SetHealth(7); }), (Sent{ { TotalDamageTaken, 3 } }));
|
||||
EXPECT_EQ(sent([&] { destroyable->Heal(1); }), (Sent{ { TotalDamageHealed, 1 } }));
|
||||
// Setting stats up (loading, respawning) isn't healing
|
||||
EXPECT_EQ(sent([&] { destroyable->SetHealth(10); destroyable->SetArmor(10); destroyable->SetImagination(10); }), Sent{});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user