177 lines
6.5 KiB
C++
177 lines
6.5 KiB
C++
#include "ShipStatsPanel.h"
|
|
|
|
#include <QString>
|
|
#include <QVBoxLayout>
|
|
|
|
#include "BarRow.h"
|
|
#include "GameConfig.h"
|
|
#include "SectionBox.h"
|
|
#include "SelectionNames.h"
|
|
#include "ShipStatsCalculator.h"
|
|
#include "StatRow.h"
|
|
#include "ThreatCostCalculator.h"
|
|
|
|
namespace
|
|
{
|
|
|
|
QString fmt(float value)
|
|
{
|
|
return QString::number(static_cast<double>(value), 'f', 1);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
|
ShipStatsPanel::ShipStatsPanel(const GameConfig* config, QWidget* parent)
|
|
: QWidget(parent)
|
|
, m_config(config)
|
|
{
|
|
QVBoxLayout* layout = new QVBoxLayout(this);
|
|
layout->setContentsMargins(0, 0, 0, 0);
|
|
layout->setSpacing(2);
|
|
layout->setAlignment(Qt::AlignTop);
|
|
|
|
// Hull stats -- always visible, except cargo capacity, which only a ship that can
|
|
// carry anything shows (REQ-MOD-UI-STATS-PANEL).
|
|
m_hpBar = new BarRow(tr("HP"), this);
|
|
m_speedRow = new StatRow(tr("Max speed"), this);
|
|
m_sensorRangeRow = new StatRow(tr("Sensor range"), this);
|
|
m_mainAccelRow = new StatRow(tr("Main accel"), this);
|
|
m_maneuveringAccelRow = new StatRow(tr("Maneuvering accel"), this);
|
|
m_angularAccelRow = new StatRow(tr("Angular accel"), this);
|
|
m_maxRotSpeedRow = new StatRow(tr("Max rotation"), this);
|
|
m_cargoCapacityRow = new StatRow(tr("Cargo capacity"), this);
|
|
m_cargoCapacityRow->hide();
|
|
|
|
layout->addWidget(m_hpBar);
|
|
layout->addWidget(m_speedRow);
|
|
layout->addWidget(m_sensorRangeRow);
|
|
layout->addWidget(m_mainAccelRow);
|
|
layout->addWidget(m_maneuveringAccelRow);
|
|
layout->addWidget(m_angularAccelRow);
|
|
layout->addWidget(m_maxRotSpeedRow);
|
|
layout->addWidget(m_cargoCapacityRow);
|
|
|
|
// One section per capability module type, each shown only while at least one such
|
|
// module is installed (REQ-MOD-UI-STATS-PANEL).
|
|
m_weaponSection = new SectionBox(tr("Weapons"), this);
|
|
m_weaponDpsRow = new StatRow(tr("DPS"), m_weaponSection);
|
|
m_weaponRangeRow = new StatRow(tr("Range"), m_weaponSection);
|
|
m_weaponSection->getContentLayout()->addWidget(m_weaponDpsRow);
|
|
m_weaponSection->getContentLayout()->addWidget(m_weaponRangeRow);
|
|
m_weaponSection->hide();
|
|
layout->addWidget(m_weaponSection);
|
|
|
|
m_salvageSection = new SectionBox(tr("Salvage"), this);
|
|
m_salvageRateRow = new StatRow(tr("Collection rate"), m_salvageSection);
|
|
m_salvageRangeRow = new StatRow(tr("Range"), m_salvageSection);
|
|
m_salvageSection->getContentLayout()->addWidget(m_salvageRateRow);
|
|
m_salvageSection->getContentLayout()->addWidget(m_salvageRangeRow);
|
|
m_salvageSection->hide();
|
|
layout->addWidget(m_salvageSection);
|
|
|
|
m_repairSection = new SectionBox(tr("Repair"), this);
|
|
m_repairRateRow = new StatRow(tr("Repair rate"), m_repairSection);
|
|
m_repairRangeRow = new StatRow(tr("Range"), m_repairSection);
|
|
m_repairSection->getContentLayout()->addWidget(m_repairRateRow);
|
|
m_repairSection->getContentLayout()->addWidget(m_repairRangeRow);
|
|
m_repairSection->hide();
|
|
layout->addWidget(m_repairSection);
|
|
|
|
// Live entities only; the design preview has no behavior to show
|
|
// (REQ-UI-SHIP-BEHAVIOR).
|
|
m_behaviorRow = new StatRow(tr("Behavior"), this);
|
|
m_behaviorRow->hide();
|
|
layout->addWidget(m_behaviorRow);
|
|
|
|
// Threat cost -- shown only while debug draw is active (REQ-UI-SHIP-STATS-PANEL).
|
|
m_threatCostRow = new StatRow(tr("Threat cost"), this);
|
|
m_threatCostRow->hide();
|
|
layout->addWidget(m_threatCostRow);
|
|
}
|
|
|
|
void ShipStatsPanel::setBehavior(BehaviorKind kind)
|
|
{
|
|
const QString label = getBehaviorLabel(kind);
|
|
m_behaviorRow->setValue(label);
|
|
m_behaviorRow->setVisible(!label.isEmpty());
|
|
}
|
|
|
|
void ShipStatsPanel::refresh(const std::string& shipId,
|
|
const std::vector<PlacedModule>& modules)
|
|
{
|
|
const ShipStats stats = calculateShipStats(*m_config, shipId, modules);
|
|
applyStats(stats, 1.0, QString::number(static_cast<int>(stats.hp + 0.5f)));
|
|
|
|
setThreatCost(calculateShipThreatCost(m_config->threatCosts, *m_config,
|
|
shipId, modules));
|
|
}
|
|
|
|
void ShipStatsPanel::refreshFromLive(const ShipStats& stats, float currentHp)
|
|
{
|
|
const double fraction = (stats.hp > 0.0f)
|
|
? static_cast<double>(currentHp) / stats.hp
|
|
: 0.0;
|
|
applyStats(stats, fraction, tr("%1 / %2")
|
|
.arg(static_cast<int>(currentHp + 0.5f))
|
|
.arg(static_cast<int>(stats.hp + 0.5f)));
|
|
}
|
|
|
|
void ShipStatsPanel::applyStats(const ShipStats& stats, double hpFraction,
|
|
const QString& hpText)
|
|
{
|
|
m_hpBar->setValue(hpFraction, hpText);
|
|
m_speedRow->setValue(tr("%1 tiles/s").arg(fmt(stats.maxSpeed_tps)));
|
|
m_sensorRangeRow->setValue(tr("%1 tiles").arg(fmt(stats.sensorRange_tiles)));
|
|
m_mainAccelRow->setValue(
|
|
tr("%1 tiles/s\xc2\xb2").arg(fmt(stats.mainAcceleration_tpss)));
|
|
m_maneuveringAccelRow->setValue(
|
|
tr("%1 tiles/s\xc2\xb2").arg(fmt(stats.maneuveringAcceleration_tpss)));
|
|
m_angularAccelRow->setValue(
|
|
tr("%1 rad/s\xc2\xb2").arg(fmt(stats.angularAcceleration_radpss)));
|
|
m_maxRotSpeedRow->setValue(tr("%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).
|
|
m_cargoCapacityRow->setVisible(stats.cargoCapacity > 0);
|
|
if (stats.cargoCapacity > 0)
|
|
{
|
|
m_cargoCapacityRow->setValue(QString::number(stats.cargoCapacity));
|
|
}
|
|
|
|
m_weaponSection->setVisible(stats.weapons.has_value());
|
|
if (stats.weapons.has_value())
|
|
{
|
|
m_weaponDpsRow->setValue(fmt(stats.weapons->combinedDps));
|
|
m_weaponRangeRow->setValue(tr("%1 tiles").arg(fmt(stats.weapons->maxRange_tiles)));
|
|
}
|
|
|
|
m_salvageSection->setVisible(stats.salvage.has_value());
|
|
if (stats.salvage.has_value())
|
|
{
|
|
m_salvageRateRow->setValue(
|
|
tr("%1 /s").arg(fmt(stats.salvage->combinedCollectionRate)));
|
|
m_salvageRangeRow->setValue(tr("%1 tiles").arg(fmt(stats.salvage->maxRange_tiles)));
|
|
}
|
|
|
|
m_repairSection->setVisible(stats.repair.has_value());
|
|
if (stats.repair.has_value())
|
|
{
|
|
m_repairRateRow->setValue(
|
|
tr("%1 HP/s").arg(fmt(stats.repair->combinedRepairRate_hps)));
|
|
m_repairRangeRow->setValue(tr("%1 tiles").arg(fmt(stats.repair->maxRange_tiles)));
|
|
}
|
|
}
|
|
|
|
void ShipStatsPanel::setThreatCost(double cost)
|
|
{
|
|
m_threatCostRow->setValue(QString::number(cost, 'f', 1));
|
|
m_threatCostRow->setVisible(m_debugDraw);
|
|
}
|
|
|
|
void ShipStatsPanel::setDebugDrawEnabled(bool enabled)
|
|
{
|
|
m_debugDraw = enabled;
|
|
m_threatCostRow->setVisible(m_debugDraw);
|
|
}
|