show team EHP in balancing target
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
#include <QVector2D>
|
||||
|
||||
@@ -86,12 +88,49 @@ ArenaSimulation::ArenaSimulation(const GameConfig& gameConfig,
|
||||
|
||||
placeStructures();
|
||||
spawnShips();
|
||||
computeTeamMaxEhp();
|
||||
|
||||
m_shipSystem->triggerRallyDeparture();
|
||||
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
std::string ArenaStatus::TeamStatus::ehpPercentText() const
|
||||
{
|
||||
if (maxEhp <= 0.0)
|
||||
{
|
||||
return "n/a";
|
||||
}
|
||||
const int percent = static_cast<int>(std::lround(100.0 * currentEhp / maxEhp));
|
||||
return std::to_string(percent) + "%";
|
||||
}
|
||||
|
||||
void ArenaSimulation::computeTeamMaxEhp()
|
||||
{
|
||||
m_teamMaxEhp[0] = 0.0;
|
||||
m_teamMaxEhp[1] = 0.0;
|
||||
|
||||
// Ships contribute their full max HP.
|
||||
m_admin.forEach<ShipIdentityComponent, FactionComponent, HealthComponent>(
|
||||
[this](entt::entity /*e*/, const ShipIdentityComponent& /*si*/,
|
||||
const FactionComponent& f, const HealthComponent& h)
|
||||
{
|
||||
m_teamMaxEhp[f.isEnemy ? 1 : 0] += static_cast<double>(h.maxHp);
|
||||
});
|
||||
|
||||
// Defence stations contribute their full max HP; the HQ is excluded.
|
||||
m_admin.forEach<StationBodyComponent, FactionComponent, HealthComponent>(
|
||||
[this](entt::entity e, const StationBodyComponent& /*sb*/,
|
||||
const FactionComponent& f, const HealthComponent& h)
|
||||
{
|
||||
if (m_admin.hasAll<HqProxyComponent>(e))
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_teamMaxEhp[f.isEnemy ? 1 : 0] += static_cast<double>(h.maxHp);
|
||||
});
|
||||
}
|
||||
|
||||
ArenaSimulation::~ArenaSimulation() = default;
|
||||
|
||||
BuildingId ArenaSimulation::allocateBuildingId()
|
||||
@@ -477,11 +516,39 @@ void ArenaSimulation::updateStatus()
|
||||
newStatus.finished = m_finished;
|
||||
newStatus.winnerTeam = m_winnerTeam;
|
||||
|
||||
// Live remaining HP of each team's ships and defence stations (HQ excluded);
|
||||
// the EHP-percentage numerator (denominator is the fixed m_teamMaxEhp).
|
||||
double currentEhp[2] = {0.0, 0.0};
|
||||
m_admin.forEach<ShipIdentityComponent, FactionComponent, HealthComponent>(
|
||||
[¤tEhp](entt::entity /*e*/, const ShipIdentityComponent& /*si*/,
|
||||
const FactionComponent& f, const HealthComponent& h)
|
||||
{
|
||||
if (h.hp > 0.0f)
|
||||
{
|
||||
currentEhp[f.isEnemy ? 1 : 0] += static_cast<double>(h.hp);
|
||||
}
|
||||
});
|
||||
m_admin.forEach<StationBodyComponent, FactionComponent, HealthComponent>(
|
||||
[this, ¤tEhp](entt::entity e, const StationBodyComponent& /*sb*/,
|
||||
const FactionComponent& f, const HealthComponent& h)
|
||||
{
|
||||
if (m_admin.hasAll<HqProxyComponent>(e))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (h.hp > 0.0f)
|
||||
{
|
||||
currentEhp[f.isEnemy ? 1 : 0] += static_cast<double>(h.hp);
|
||||
}
|
||||
});
|
||||
|
||||
for (int ti = 0; ti < 2; ++ti)
|
||||
{
|
||||
ArenaStatus::TeamStatus& teamStatus = newStatus.teams[ti];
|
||||
teamStatus.name = m_arenaConfig.teams[ti].name;
|
||||
teamStatus.threatLevel = m_teamThreat[ti];
|
||||
teamStatus.currentEhp = currentEhp[ti];
|
||||
teamStatus.maxEhp = m_teamMaxEhp[ti];
|
||||
|
||||
// HQ entry (always first).
|
||||
{
|
||||
|
||||
@@ -44,7 +44,16 @@ struct ArenaStatus
|
||||
{
|
||||
std::string name;
|
||||
double threatLevel = 0.0; // accumulated threat of the team's configured ships
|
||||
// Remaining durability of the team's ships and defence stations (HQ
|
||||
// excluded). currentEhp is summed live; maxEhp is the fixed full-HP
|
||||
// baseline. See ehpPercentText() for the displayed value.
|
||||
double currentEhp = 0.0;
|
||||
double maxEhp = 0.0;
|
||||
std::vector<Entry> entries; // HQ first, then ships, then stations
|
||||
|
||||
// Remaining EHP as a whole-number percentage ("NN%"), or "n/a" when the
|
||||
// team has no ships or stations (maxEhp == 0).
|
||||
std::string ehpPercentText() const;
|
||||
};
|
||||
|
||||
TeamStatus teams[2];
|
||||
@@ -82,6 +91,7 @@ private:
|
||||
BuildingId allocateBuildingId();
|
||||
void placeStructures();
|
||||
void spawnShips();
|
||||
void computeTeamMaxEhp();
|
||||
void tick();
|
||||
void tickDeaths();
|
||||
void updateStatus();
|
||||
@@ -115,6 +125,10 @@ private:
|
||||
// Static accumulated threat per team, computed once from the configured roster.
|
||||
double m_teamThreat[2] = {0.0, 0.0};
|
||||
|
||||
// Full-HP baseline per team (ships + defence stations, HQ excluded), computed
|
||||
// once after spawning; the EHP-percentage denominator.
|
||||
double m_teamMaxEhp[2] = {0.0, 0.0};
|
||||
|
||||
std::vector<BeamFiredEvent> m_beamFiredEvents;
|
||||
|
||||
mutable std::mutex m_statusMutex;
|
||||
|
||||
@@ -63,6 +63,8 @@ void ArenaWidget::buildLayout(const std::string& arenaName)
|
||||
team1Layout->addWidget(m_team1Header);
|
||||
m_team1Threat = new QLabel(this);
|
||||
team1Layout->addWidget(m_team1Threat);
|
||||
m_team1Ehp = new QLabel(this);
|
||||
team1Layout->addWidget(m_team1Ehp);
|
||||
m_team1Content = new QLabel(this);
|
||||
team1Layout->addWidget(m_team1Content);
|
||||
team1Layout->addStretch();
|
||||
@@ -75,6 +77,8 @@ void ArenaWidget::buildLayout(const std::string& arenaName)
|
||||
team2Layout->addWidget(m_team2Header);
|
||||
m_team2Threat = new QLabel(this);
|
||||
team2Layout->addWidget(m_team2Threat);
|
||||
m_team2Ehp = new QLabel(this);
|
||||
team2Layout->addWidget(m_team2Ehp);
|
||||
m_team2Content = new QLabel(this);
|
||||
team2Layout->addWidget(m_team2Content);
|
||||
team2Layout->addStretch();
|
||||
@@ -121,6 +125,7 @@ void ArenaWidget::updateStatus(const ArenaStatus& status)
|
||||
const ArenaStatus::TeamStatus& team = status.teams[ti];
|
||||
QLabel* header = (ti == 0) ? m_team1Header : m_team2Header;
|
||||
QLabel* threat = (ti == 0) ? m_team1Threat : m_team2Threat;
|
||||
QLabel* ehp = (ti == 0) ? m_team1Ehp : m_team2Ehp;
|
||||
QLabel* content = (ti == 0) ? m_team1Content : m_team2Content;
|
||||
|
||||
if (status.finished && status.winnerTeam == ti)
|
||||
@@ -133,6 +138,7 @@ void ArenaWidget::updateStatus(const ArenaStatus& status)
|
||||
}
|
||||
|
||||
threat->setText(tr("Threat: %1").arg(QString::number(team.threatLevel, 'f', 0)));
|
||||
ehp->setText(tr("EHP: %1").arg(QString::fromStdString(team.ehpPercentText())));
|
||||
|
||||
QString lines;
|
||||
for (const ArenaStatus::Entry& entry : team.entries)
|
||||
|
||||
@@ -40,6 +40,8 @@ private:
|
||||
QLabel* m_team2Header;
|
||||
QLabel* m_team1Threat;
|
||||
QLabel* m_team2Threat;
|
||||
QLabel* m_team1Ehp;
|
||||
QLabel* m_team2Ehp;
|
||||
QLabel* m_team1Content;
|
||||
QLabel* m_team2Content;
|
||||
QPushButton* m_inspectButton;
|
||||
|
||||
@@ -46,6 +46,7 @@ namespace
|
||||
header = QStringLiteral("[WON] ") + header;
|
||||
}
|
||||
header += QStringLiteral(" - threat %1").arg(QString::number(team.threatLevel, 'f', 0));
|
||||
header += QStringLiteral(" - EHP %1").arg(QString::fromStdString(team.ehpPercentText()));
|
||||
return escapeCell(header);
|
||||
}
|
||||
|
||||
|
||||
@@ -93,6 +93,8 @@ InspectWindow::InspectWindow(ArenaSimulation* sim, const GameConfig* config,
|
||||
team1Layout->addWidget(m_team1Header);
|
||||
m_team1Threat = new QLabel(infoPanel);
|
||||
team1Layout->addWidget(m_team1Threat);
|
||||
m_team1Ehp = new QLabel(infoPanel);
|
||||
team1Layout->addWidget(m_team1Ehp);
|
||||
m_team1Content = new QLabel(infoPanel);
|
||||
team1Layout->addWidget(m_team1Content);
|
||||
team1Layout->addStretch();
|
||||
@@ -104,6 +106,8 @@ InspectWindow::InspectWindow(ArenaSimulation* sim, const GameConfig* config,
|
||||
team2Layout->addWidget(m_team2Header);
|
||||
m_team2Threat = new QLabel(infoPanel);
|
||||
team2Layout->addWidget(m_team2Threat);
|
||||
m_team2Ehp = new QLabel(infoPanel);
|
||||
team2Layout->addWidget(m_team2Ehp);
|
||||
m_team2Content = new QLabel(infoPanel);
|
||||
team2Layout->addWidget(m_team2Content);
|
||||
team2Layout->addStretch();
|
||||
@@ -203,6 +207,7 @@ void InspectWindow::updateInfoPanel(const ArenaStatus& status)
|
||||
const ArenaStatus::TeamStatus& team = status.teams[ti];
|
||||
QLabel* header = (ti == 0) ? m_team1Header : m_team2Header;
|
||||
QLabel* threat = (ti == 0) ? m_team1Threat : m_team2Threat;
|
||||
QLabel* ehp = (ti == 0) ? m_team1Ehp : m_team2Ehp;
|
||||
QLabel* content = (ti == 0) ? m_team1Content : m_team2Content;
|
||||
|
||||
if (status.finished && status.winnerTeam == ti)
|
||||
@@ -215,6 +220,7 @@ void InspectWindow::updateInfoPanel(const ArenaStatus& status)
|
||||
}
|
||||
|
||||
threat->setText(tr("Threat: %1").arg(QString::number(team.threatLevel, 'f', 0)));
|
||||
ehp->setText(tr("EHP: %1").arg(QString::fromStdString(team.ehpPercentText())));
|
||||
|
||||
QString lines;
|
||||
for (const ArenaStatus::Entry& entry : team.entries)
|
||||
|
||||
@@ -58,6 +58,8 @@ private:
|
||||
QLabel* m_team2Header;
|
||||
QLabel* m_team1Threat;
|
||||
QLabel* m_team2Threat;
|
||||
QLabel* m_team1Ehp;
|
||||
QLabel* m_team2Ehp;
|
||||
QLabel* m_team1Content;
|
||||
QLabel* m_team2Content;
|
||||
QTimer* m_pollTimer;
|
||||
|
||||
Reference in New Issue
Block a user