285 lines
12 KiB
C++
Executable File
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
|