Files
qt5-legatus-legacy/Lts/Proxies/HighLevelArchitecture/Guez/damage_model.cpp
T
2026-08-13 18:33:10 +02:00

285 lines
12 KiB
C++
Executable File

/**
* @RDE_HEADER@
* Damage state transaformation from/to HLA <-> Excon, see ICD, 4.4.3.5.6 - Damage Model
* $Id$
* $HeadURL$
* $Author$
*/
#include "damage_model.h"
#include <QTimer>
#include <QDateTime>
namespace HighLevelArchitecture
{
// ICD, 4.4.3.5.6 - Damage Model
// es sind dort nich alle definiert, die Reihenfolge ist DamageState - FirePower - Immobilized
DamageModel::DamageModel(const IdentifierStruct &is,
const rpr2::TacticalStatusStruct &state)
: m_is(is)
{
initTimer();
setTacticalStatusStruct(state, QDateTime::currentMSecsSinceEpoch());
}
DamageModel::DamageModel(const rpr2::TacticalStatusStruct &state)
{
setTacticalStatusStruct(state, QDateTime::currentMSecsSinceEpoch());
}
rpr2::DamageStatusEnum32::ET DamageModel::damageState(qint64 simTimeMSec) const
{
int idx = indexForTime(simTimeMSec);
if (idx < 0)
return rpr2::DamageStatusEnum32::NoDamage;
// Todo: Correct?!?
switch (m_tacticalStates.at(idx).tss.TacticalStatus)
{
case rpr2::TacticalStatusEnum8::CombatReady:
return rpr2::DamageStatusEnum32::NoDamage;
case rpr2::TacticalStatusEnum8::Immobilized:
case rpr2::TacticalStatusEnum8::ImmobilizedVisible:
case rpr2::TacticalStatusEnum8::LightHit:
return rpr2::DamageStatusEnum32::SlightDamage;
case rpr2::TacticalStatusEnum8::WeaponKill:
case rpr2::TacticalStatusEnum8::WeaponKillVisible:
case rpr2::TacticalStatusEnum8::MediumHit:
case rpr2::TacticalStatusEnum8::HeavyHit:
return rpr2::DamageStatusEnum32::ModerateDamage;
case rpr2::TacticalStatusEnum8::TotalKill:
return rpr2::DamageStatusEnum32::Destroyed;
case rpr2::TacticalStatusEnum8::HitWithoutEffect:
case rpr2::TacticalStatusEnum8::TemporaryFailure:
case rpr2::TacticalStatusEnum8::NearMiss:
return rpr2::DamageStatusEnum32::NoDamage;
}
return rpr2::DamageStatusEnum32::NoDamage;
}
rpr2::TotalStatusEnum32::ET DamageModel::totalState(qint64 simTimeMSec) const
{
int idx = indexForTime(simTimeMSec);
if (idx < 0)
return rpr2::TotalStatusEnum32::CombatReady;
return m_tacticalStates.at(idx).tss.TotalStatus;
}
bool DamageModel::immobilized(qint64 simTimeMSec) const
{
int idx = indexForTime(simTimeMSec);
if (idx < 0)
return false;
return m_tacticalStates.at(idx).tss.TotalStatus & (rpr2::TotalStatusEnum32::Immobilized | rpr2::TotalStatusEnum32::ImmobilizedVisible);
}
bool DamageModel::firePowerDisabled(qint64 simTimeMSec) const
{
int idx = indexForTime(simTimeMSec);
if (idx < 0)
return false;
return m_tacticalStates.at(idx).tss.TotalStatus & (rpr2::TotalStatusEnum32::WeaponKill | rpr2::TotalStatusEnum32::WeaponKillVisible);
}
static inline bool checkManipulationChanged(const rpr2::TacticalStatusStruct &oldTss,
const rpr2::TacticalStatusStruct &newTss)
{
return
(oldTss.TotalStatus & rpr2::TotalStatusEnum32::Manipulation) !=
(newTss.TotalStatus & rpr2::TotalStatusEnum32::Manipulation);
}
void DamageModel::setTacticalStatusStruct(const rpr2::TacticalStatusStruct &state, qint64 simTimeMSec)
{
bool bManipulationChanged = true;
const int idx = indexForTime(simTimeMSec);
if (idx > 0 && m_tacticalStates.at(idx).timeStamp == simTimeMSec)
{
// already there...
if (state == m_tacticalStates.at(idx).tss)
return;
bManipulationChanged = checkManipulationChanged(m_tacticalStates.at(idx).tss, state);
m_tacticalStates[idx].tss = state;
}
else
{
if (idx >= 0)
bManipulationChanged = checkManipulationChanged(m_tacticalStates.at(idx).tss, state);
TacticalStatusStructWithTimeStamp tssTs;
tssTs.tss = state;
tssTs.timeStamp = simTimeMSec;
m_tacticalStates.insert(idx + 1, std::move(tssTs)); // idx = -1 -> oldest, will become index 0
}
while (m_tacticalStates.size() > 10)
m_tacticalStates.pop_front();
if (bManipulationChanged)
emit playerManipulationChanged(m_is.entityNumber(), state.TotalStatus & rpr2::TotalStatusEnum32::Manipulation, simTimeMSec);
}
void DamageModel::setTacticalStatusStructWithTimestamp(TacticalStatusStructWithTimeStamp &tssTs, const rpr2::HitResultEnum16::ET &state, qint64 simTimeMSec)
{
switch (state)
{
case rpr2::HitResultEnum16::Reset:
tssTs.tss.TotalStatus = rpr2::TotalStatusEnum32::CombatReady;
tssTs.tss.TacticalStatus = rpr2::TacticalStatusEnum8::CombatReady;
break;
case rpr2::HitResultEnum16::LightDamage:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::LightHit);
tssTs.tss.TacticalStatus = tssTs.tss.TacticalStatus > rpr2::TacticalStatusEnum8::LightHit ? tssTs.tss.TacticalStatus : rpr2::TacticalStatusEnum8::LightHit;
break;
case rpr2::HitResultEnum16::MediumDamage:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::MediumHit);
tssTs.tss.TacticalStatus = tssTs.tss.TacticalStatus > rpr2::TacticalStatusEnum8::MediumHit ? tssTs.tss.TacticalStatus : rpr2::TacticalStatusEnum8::MediumHit;
break;
case rpr2::HitResultEnum16::HeavyDamage:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::HeavyHit);
tssTs.tss.TacticalStatus = tssTs.tss.TacticalStatus > rpr2::TacticalStatusEnum8::HeavyHit ? tssTs.tss.TacticalStatus : rpr2::TacticalStatusEnum8::HeavyHit;
break;
case rpr2::HitResultEnum16::MobilityKill:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::Immobilized);
tssTs.tss.TacticalStatus = tssTs.tss.TacticalStatus > rpr2::TacticalStatusEnum8::Immobilized ? tssTs.tss.TacticalStatus : rpr2::TacticalStatusEnum8::Immobilized;
break;
case rpr2::HitResultEnum16::MobilityKillVisible:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::ImmobilizedVisible);
tssTs.tss.TacticalStatus = tssTs.tss.TacticalStatus > rpr2::TacticalStatusEnum8::ImmobilizedVisible ? tssTs.tss.TacticalStatus : rpr2::TacticalStatusEnum8::ImmobilizedVisible;
break;
case rpr2::HitResultEnum16::WeaponDamage:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::WeaponKill);
tssTs.tss.TacticalStatus = tssTs.tss.TacticalStatus > rpr2::TacticalStatusEnum8::WeaponKill ? tssTs.tss.TacticalStatus : rpr2::TacticalStatusEnum8::WeaponKill;
break;
case rpr2::HitResultEnum16::WeaponDamageVisible:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::WeaponKillVisible);
tssTs.tss.TacticalStatus = tssTs.tss.TacticalStatus > rpr2::TacticalStatusEnum8::WeaponKillVisible ? tssTs.tss.TacticalStatus : rpr2::TacticalStatusEnum8::WeaponKillVisible;
break;
case rpr2::HitResultEnum16::TemporaryFailure:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::TemporaryFailure);
break;
case rpr2::HitResultEnum16::NearMiss:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::NearMiss);
break;
case rpr2::HitResultEnum16::Contaminated:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::CContamination);
break;
case rpr2::HitResultEnum16::CheatingKill:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::Manipulation);
tssTs.tss.TacticalStatus = rpr2::TacticalStatusEnum8::TotalKill;
break;
case rpr2::HitResultEnum16::HitWithNoEffect:
tssTs.tss.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::HitWithoutEffect);
break;
default:
break;
}
tssTs.tss.VulnerabilityKind = 0;
tssTs.timeStamp = simTimeMSec;
}
void DamageModel::setTacticalStatus(const rpr2::HitResultEnum16::ET &state, qint64 simTimeMSec)
{
const int idx = indexForTime(simTimeMSec);
if (idx > 0 && m_tacticalStates.at(idx).timeStamp == simTimeMSec)
{
TacticalStatusStructWithTimeStamp tssTs;
setTacticalStatusStructWithTimestamp(tssTs, state, simTimeMSec); // Convert for comparison...
// already there...
if (tssTs.tss.TacticalStatus == m_tacticalStates.at(idx).tss.TacticalStatus)
return;
// When he WAS manipulated and is now being reset, also reset manipulation:
if (tssTs.tss.TotalStatus & rpr2::TotalStatusEnum32::Manipulation &&
state == rpr2::HitResultEnum16::Reset)
emit playerManipulationChanged(m_is.entityNumber(), false, simTimeMSec);
setTacticalStatusStructWithTimestamp(m_tacticalStates[idx], state, simTimeMSec);
}
else
{
TacticalStatusStructWithTimeStamp tssTs;
setTacticalStatusStructWithTimestamp(tssTs, state, simTimeMSec);
m_tacticalStates.insert(idx + 1, std::move(tssTs)); // idx = -1 -> oldest, will become index 0
}
while (m_tacticalStates.size() > 10)
m_tacticalStates.pop_front();
// Manipulation only occurs when cheatingKill is sent:
if (state == rpr2::HitResultEnum16::CheatingKill)
emit playerManipulationChanged(m_is.entityNumber(), true, simTimeMSec);
}
ProjectDataManagement::VulnerabilityState DamageModel::vulnerabilityState(qint64 simTimeMSec) const
{
int idx = indexForTime(simTimeMSec);
if (idx < 0)
return ProjectDataManagement::VulnerabilityState_def::CombatReady;
switch (m_tacticalStates.at(idx).tss.TacticalStatus)
{
case rpr2::TacticalStatusEnum8::CombatReady:
return ProjectDataManagement::VulnerabilityState_def::CombatReady;
case rpr2::TacticalStatusEnum8::LightHit:
return ProjectDataManagement::VulnerabilityState_def::LightDamage;
case rpr2::TacticalStatusEnum8::MediumHit:
return ProjectDataManagement::VulnerabilityState_def::MediumDamage;
case rpr2::TacticalStatusEnum8::HeavyHit:
return ProjectDataManagement::VulnerabilityState_def::HeavyDamage;
case rpr2::TacticalStatusEnum8::Immobilized:
return ProjectDataManagement::VulnerabilityState_def::MobilityKill;
case rpr2::TacticalStatusEnum8::ImmobilizedVisible:
return ProjectDataManagement::VulnerabilityState_def::VisibleMobilityKill;
case rpr2::TacticalStatusEnum8::WeaponKill:
return ProjectDataManagement::VulnerabilityState_def::WeaponSystemDamage;
case rpr2::TacticalStatusEnum8::WeaponKillVisible:
return ProjectDataManagement::VulnerabilityState_def::VisibleWeaponSystemDamage;
case rpr2::TacticalStatusEnum8::TotalKill:
return ProjectDataManagement::VulnerabilityState_def::CatastrophicKill;
case rpr2::TacticalStatusEnum8::TemporaryFailure:
return ProjectDataManagement::VulnerabilityState_def::TemporarySeverance;
case rpr2::TacticalStatusEnum8::NearMiss:
return ProjectDataManagement::VulnerabilityState_def::NearMiss;
case rpr2::TacticalStatusEnum8::HitWithoutEffect:
return ProjectDataManagement::VulnerabilityState_def::HitWithNoEffect;
}
return ProjectDataManagement::VulnerabilityState_def::CombatReady;
}
int DamageModel::indexForTime(qint64 simTimeMSec) const
{
const int s = m_tacticalStates.size();
if (simTimeMSec < 0 && s != 0) // = use current
return s - 1;
for (int i = s - 1; i >= 0; --i)
{
const auto &tss = m_tacticalStates.at(i);
if (tss.timeStamp <= simTimeMSec)
return i;
}
return -1;
}
void DamageModel::initTimer()
{
delete m_timer;
m_timer = new QTimer(this);
m_timer->setSingleShot(true);
m_timer->start(s_waitInterval);
connect(m_timer, &QTimer::timeout,
this, [this]()
{
emit damageStateChanged();
m_timer->deleteLater();
m_timer = nullptr;
});
}
} // namespace HighLevelArchitecture