218 lines
6.9 KiB
C++
218 lines
6.9 KiB
C++
#include "ShipStatsPanel.h"
|
|
|
|
#include <QLabel>
|
|
#include <QString>
|
|
#include <QVBoxLayout>
|
|
|
|
#include "GameConfig.h"
|
|
#include "ShipStatsCalculator.h"
|
|
#include "ThreatCostCalculator.h"
|
|
|
|
namespace
|
|
{
|
|
|
|
QString fmt(float value)
|
|
{
|
|
return QString::number(static_cast<double>(value), 'f', 1);
|
|
}
|
|
|
|
QLabel* makeSectionHeader(const QString& text, QWidget* parent)
|
|
{
|
|
QLabel* label = new QLabel(text, parent);
|
|
QFont f = label->font();
|
|
f.setBold(true);
|
|
label->setFont(f);
|
|
return label;
|
|
}
|
|
|
|
QLabel* makeStatLabel(QWidget* parent)
|
|
{
|
|
return new QLabel(parent);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
|
ShipStatsPanel::ShipStatsPanel(const GameConfig* config, QWidget* parent)
|
|
: QWidget(parent)
|
|
, m_config(config)
|
|
{
|
|
QVBoxLayout* layout = new QVBoxLayout(this);
|
|
layout->setContentsMargins(4, 4, 4, 4);
|
|
layout->setSpacing(2);
|
|
layout->setAlignment(Qt::AlignTop);
|
|
|
|
// Hull stats — always visible.
|
|
m_hpLabel = makeStatLabel(this);
|
|
m_speedLabel = makeStatLabel(this);
|
|
m_sensorRangeLabel = makeStatLabel(this);
|
|
m_mainAccelLabel = makeStatLabel(this);
|
|
m_maneuveringAccelLabel = makeStatLabel(this);
|
|
m_angularAccelLabel = makeStatLabel(this);
|
|
m_maxRotSpeedLabel = makeStatLabel(this);
|
|
m_cargoCapacityLabel = makeStatLabel(this);
|
|
m_cargoCapacityLabel->setVisible(false);
|
|
|
|
layout->addWidget(m_hpLabel);
|
|
layout->addWidget(m_speedLabel);
|
|
layout->addWidget(m_sensorRangeLabel);
|
|
layout->addWidget(m_mainAccelLabel);
|
|
layout->addWidget(m_maneuveringAccelLabel);
|
|
layout->addWidget(m_angularAccelLabel);
|
|
layout->addWidget(m_maxRotSpeedLabel);
|
|
layout->addWidget(m_cargoCapacityLabel);
|
|
|
|
// Weapon capability section.
|
|
m_weaponSection = new QWidget(this);
|
|
{
|
|
QVBoxLayout* sl = new QVBoxLayout(m_weaponSection);
|
|
sl->setContentsMargins(0, 4, 0, 0);
|
|
sl->setSpacing(2);
|
|
sl->addWidget(makeSectionHeader(tr("Weapons"), m_weaponSection));
|
|
m_weaponDpsLabel = makeStatLabel(m_weaponSection);
|
|
m_weaponRangeLabel = makeStatLabel(m_weaponSection);
|
|
sl->addWidget(m_weaponDpsLabel);
|
|
sl->addWidget(m_weaponRangeLabel);
|
|
}
|
|
m_weaponSection->setVisible(false);
|
|
layout->addWidget(m_weaponSection);
|
|
|
|
// Salvage capability section.
|
|
m_salvageSection = new QWidget(this);
|
|
{
|
|
QVBoxLayout* sl = new QVBoxLayout(m_salvageSection);
|
|
sl->setContentsMargins(0, 4, 0, 0);
|
|
sl->setSpacing(2);
|
|
sl->addWidget(makeSectionHeader(tr("Salvage"), m_salvageSection));
|
|
m_salvageRateLabel = makeStatLabel(m_salvageSection);
|
|
m_salvageRangeLabel = makeStatLabel(m_salvageSection);
|
|
sl->addWidget(m_salvageRateLabel);
|
|
sl->addWidget(m_salvageRangeLabel);
|
|
}
|
|
m_salvageSection->setVisible(false);
|
|
layout->addWidget(m_salvageSection);
|
|
|
|
// Repair capability section.
|
|
m_repairSection = new QWidget(this);
|
|
{
|
|
QVBoxLayout* sl = new QVBoxLayout(m_repairSection);
|
|
sl->setContentsMargins(0, 4, 0, 0);
|
|
sl->setSpacing(2);
|
|
sl->addWidget(makeSectionHeader(tr("Repair"), m_repairSection));
|
|
m_repairRateLabel = makeStatLabel(m_repairSection);
|
|
m_repairRangeLabel = makeStatLabel(m_repairSection);
|
|
sl->addWidget(m_repairRateLabel);
|
|
sl->addWidget(m_repairRangeLabel);
|
|
}
|
|
m_repairSection->setVisible(false);
|
|
layout->addWidget(m_repairSection);
|
|
|
|
// Threat cost — debug-only, initially hidden.
|
|
m_threatCostLabel = makeStatLabel(this);
|
|
m_threatCostLabel->setVisible(false);
|
|
layout->addWidget(m_threatCostLabel);
|
|
|
|
layout->addStretch();
|
|
}
|
|
|
|
void ShipStatsPanel::refresh(const std::string& shipId,
|
|
const std::vector<PlacedModule>& modules)
|
|
{
|
|
const ShipStats stats = calculateShipStats(*m_config, shipId, modules);
|
|
const QString hpText = tr("HP: %1").arg(static_cast<int>(stats.hp + 0.5f));
|
|
applyStats(stats, hpText);
|
|
|
|
const double threat = calculateShipThreatCost(m_config->threatCosts, *m_config,
|
|
shipId, modules);
|
|
setThreatCost(threat);
|
|
}
|
|
|
|
void ShipStatsPanel::refreshFromLive(const ShipStats& stats, float currentHp)
|
|
{
|
|
const QString hpText = tr("HP: %1 / %2")
|
|
.arg(static_cast<int>(currentHp + 0.5f))
|
|
.arg(static_cast<int>(stats.hp + 0.5f));
|
|
applyStats(stats, hpText);
|
|
}
|
|
|
|
void ShipStatsPanel::applyStats(const ShipStats& stats, const QString& hpText)
|
|
{
|
|
m_hpLabel->setText(hpText);
|
|
m_speedLabel->setText(
|
|
tr("Max Speed: %1 tiles/s").arg(fmt(stats.maxSpeed_tps)));
|
|
m_sensorRangeLabel->setText(
|
|
tr("Sensor Range: %1 tiles").arg(fmt(stats.sensorRange_tiles)));
|
|
m_mainAccelLabel->setText(
|
|
tr("Main Accel: %1 tiles/s\xc2\xb2").arg(fmt(stats.mainAcceleration_tpss)));
|
|
m_maneuveringAccelLabel->setText(
|
|
tr("Maneuvering Accel: %1 tiles/s\xc2\xb2").arg(fmt(stats.maneuveringAcceleration_tpss)));
|
|
m_angularAccelLabel->setText(
|
|
tr("Angular Accel: %1 rad/s\xc2\xb2").arg(fmt(stats.angularAcceleration_radpss)));
|
|
m_maxRotSpeedLabel->setText(
|
|
tr("Max Rotation: %1 rad/s").arg(fmt(stats.maxRotationSpeed_radps)));
|
|
|
|
// Cargo capacity is shown only when the ship can actually hold cargo
|
|
// (REQ-MOD-UI-STATS-PANEL).
|
|
if (stats.cargoCapacity > 0)
|
|
{
|
|
m_cargoCapacityLabel->setText(
|
|
tr("Cargo Capacity: %1").arg(stats.cargoCapacity));
|
|
m_cargoCapacityLabel->setVisible(true);
|
|
}
|
|
else
|
|
{
|
|
m_cargoCapacityLabel->setVisible(false);
|
|
}
|
|
|
|
if (stats.weapons.has_value())
|
|
{
|
|
m_weaponDpsLabel->setText(
|
|
tr("DPS: %1").arg(fmt(stats.weapons->combinedDps)));
|
|
m_weaponRangeLabel->setText(
|
|
tr("Range: %1 tiles").arg(fmt(stats.weapons->maxRange_tiles)));
|
|
m_weaponSection->setVisible(true);
|
|
}
|
|
else
|
|
{
|
|
m_weaponSection->setVisible(false);
|
|
}
|
|
|
|
if (stats.salvage.has_value())
|
|
{
|
|
m_salvageRateLabel->setText(
|
|
tr("Collection Rate: %1/s").arg(fmt(stats.salvage->combinedCollectionRate)));
|
|
m_salvageRangeLabel->setText(
|
|
tr("Range: %1 tiles").arg(fmt(stats.salvage->maxRange_tiles)));
|
|
m_salvageSection->setVisible(true);
|
|
}
|
|
else
|
|
{
|
|
m_salvageSection->setVisible(false);
|
|
}
|
|
|
|
if (stats.repair.has_value())
|
|
{
|
|
m_repairRateLabel->setText(
|
|
tr("Repair Rate: %1 HP/s").arg(fmt(stats.repair->combinedRepairRate_hps)));
|
|
m_repairRangeLabel->setText(
|
|
tr("Range: %1 tiles").arg(fmt(stats.repair->maxRange_tiles)));
|
|
m_repairSection->setVisible(true);
|
|
}
|
|
else
|
|
{
|
|
m_repairSection->setVisible(false);
|
|
}
|
|
}
|
|
|
|
void ShipStatsPanel::setThreatCost(double cost)
|
|
{
|
|
m_threatCostLabel->setText(tr("Threat Cost: %1").arg(cost, 0, 'f', 1));
|
|
m_threatCostLabel->setVisible(m_debugDraw);
|
|
}
|
|
|
|
void ShipStatsPanel::setDebugDrawEnabled(bool enabled)
|
|
{
|
|
m_debugDraw = enabled;
|
|
m_threatCostLabel->setVisible(m_debugDraw);
|
|
}
|