/** * @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 #include 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(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(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(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(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(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(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(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(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::TemporaryFailure); break; case rpr2::HitResultEnum16::NearMiss: tssTs.tss.TotalStatus = static_cast(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::NearMiss); break; case rpr2::HitResultEnum16::Contaminated: tssTs.tss.TotalStatus = static_cast(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::CContamination); break; case rpr2::HitResultEnum16::CheatingKill: tssTs.tss.TotalStatus = static_cast(tssTs.tss.TotalStatus | rpr2::TotalStatusEnum32::Manipulation); tssTs.tss.TacticalStatus = rpr2::TacticalStatusEnum8::TotalKill; break; case rpr2::HitResultEnum16::HitWithNoEffect: tssTs.tss.TotalStatus = static_cast(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