Implement REQ-UI-SHIP-BEHAVIOR: show selected ship's current behavior

Add a live behavior label to the ship stats panel that names the ship's
top-priority behavior (Retreating/Engaging/Salvaging/Repairing/Rallying/
Standby/Advancing) as resolved by the AiSystem selection pass. Wired into
both the in-game selected building panel and the balancing InspectWindow,
for player and enemy ships. The label is hidden in the static design
preview.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DZR44tA8sn4dPqDzAVXyps
This commit is contained in:
2026-07-14 21:09:43 +02:00
parent 89faaf89b7
commit c6a634ac03
4 changed files with 50 additions and 0 deletions

View File

@@ -14,6 +14,7 @@
#include "HealthComponent.h" #include "HealthComponent.h"
#include "InspectWindowClosedEvent.h" #include "InspectWindowClosedEvent.h"
#include "ModuleOwnerComponent.h" #include "ModuleOwnerComponent.h"
#include "SelectedBehaviorComponent.h"
#include "ShipIdentityComponent.h" #include "ShipIdentityComponent.h"
#include "ShipStatsCalculator.h" #include "ShipStatsCalculator.h"
#include "ShipStatsPanel.h" #include "ShipStatsPanel.h"
@@ -278,6 +279,8 @@ void InspectWindow::handleEvent(std::shared_ptr<const EntitySelectedEvent> event
const ShipStats stats = buildShipStatsFromEntity(admin, entity); const ShipStats stats = buildShipStatsFromEntity(admin, entity);
m_entityStatsPanel->refreshFromLive(stats, health.hp); m_entityStatsPanel->refreshFromLive(stats, health.hp);
m_entityStatsPanel->setBehavior(
admin.get<SelectedBehaviorComponent>(entity).winner);
m_entityStatsPanel->show(); m_entityStatsPanel->show();
m_stationStatsLabel->hide(); m_stationStatsLabel->hide();
} }
@@ -355,6 +358,8 @@ void InspectWindow::refreshEntityStats()
{ {
const ShipStats stats = buildShipStatsFromEntity(admin, entity); const ShipStats stats = buildShipStatsFromEntity(admin, entity);
m_entityStatsPanel->refreshFromLive(stats, health.hp); m_entityStatsPanel->refreshFromLive(stats, health.hp);
m_entityStatsPanel->setBehavior(
admin.get<SelectedBehaviorComponent>(entity).winner);
} }
else if (admin.hasAll<StationBodyComponent>(entity)) else if (admin.hasAll<StationBodyComponent>(entity))
{ {

View File

@@ -21,6 +21,7 @@
#include "FactionComponent.h" #include "FactionComponent.h"
#include "HealthComponent.h" #include "HealthComponent.h"
#include "ModuleOwnerComponent.h" #include "ModuleOwnerComponent.h"
#include "SelectedBehaviorComponent.h"
#include "ShipIdentityComponent.h" #include "ShipIdentityComponent.h"
#include "ShipStatsCalculator.h" #include "ShipStatsCalculator.h"
#include "ShipStatsPanel.h" #include "ShipStatsPanel.h"
@@ -948,6 +949,8 @@ void SelectedBuildingPanel::buildEntityShip(entt::entity entity)
const ShipStats stats = buildShipStatsFromEntity(admin, entity); const ShipStats stats = buildShipStatsFromEntity(admin, entity);
m_entityStatsPanel->refreshFromLive(stats, health.hp); m_entityStatsPanel->refreshFromLive(stats, health.hp);
m_entityStatsPanel->setBehavior(
admin.get<SelectedBehaviorComponent>(entity).winner);
m_entityStatsPanel->setDebugDrawEnabled(m_debugDraw); m_entityStatsPanel->setDebugDrawEnabled(m_debugDraw);
for (const ShipDef& def : m_config->ships.ships) for (const ShipDef& def : m_config->ships.ships)
@@ -1027,6 +1030,8 @@ void SelectedBuildingPanel::refreshEntityStats()
{ {
const ShipStats stats = buildShipStatsFromEntity(admin, entity); const ShipStats stats = buildShipStatsFromEntity(admin, entity);
m_entityStatsPanel->refreshFromLive(stats, health.hp); m_entityStatsPanel->refreshFromLive(stats, health.hp);
m_entityStatsPanel->setBehavior(
admin.get<SelectedBehaviorComponent>(entity).winner);
} }
else if (admin.hasAll<StationBodyComponent>(entity)) else if (admin.hasAll<StationBodyComponent>(entity))
{ {

View File

@@ -42,6 +42,12 @@ ShipStatsPanel::ShipStatsPanel(const GameConfig* config, QWidget* parent)
layout->setSpacing(2); layout->setSpacing(2);
layout->setAlignment(Qt::AlignTop); layout->setAlignment(Qt::AlignTop);
// Current behavior — live entities only; hidden in the static design
// preview (REQ-UI-SHIP-BEHAVIOR).
m_behaviorLabel = makeSectionHeader(QString(), this);
m_behaviorLabel->setVisible(false);
layout->addWidget(m_behaviorLabel);
// Hull stats — always visible. // Hull stats — always visible.
m_hpLabel = makeStatLabel(this); m_hpLabel = makeStatLabel(this);
m_speedLabel = makeStatLabel(this); m_speedLabel = makeStatLabel(this);
@@ -125,6 +131,9 @@ void ShipStatsPanel::refresh(const std::string& shipId,
const double threat = calculateShipThreatCost(m_config->threatCosts, *m_config, const double threat = calculateShipThreatCost(m_config->threatCosts, *m_config,
shipId, modules); shipId, modules);
setThreatCost(threat); setThreatCost(threat);
// The static design preview has no live behavior to show.
m_behaviorLabel->setVisible(false);
} }
void ShipStatsPanel::refreshFromLive(const ShipStats& stats, float currentHp) void ShipStatsPanel::refreshFromLive(const ShipStats& stats, float currentHp)
@@ -204,6 +213,32 @@ void ShipStatsPanel::applyStats(const ShipStats& stats, const QString& hpText)
} }
} }
void ShipStatsPanel::setBehavior(BehaviorKind kind)
{
QString label;
switch (kind)
{
case BehaviorKind::Retreat: label = tr("Retreating"); break;
case BehaviorKind::Attack: label = tr("Engaging"); break;
case BehaviorKind::SalvageScrap:
case BehaviorKind::DeliverScrap: label = tr("Salvaging"); break;
case BehaviorKind::Repair: label = tr("Repairing"); break;
case BehaviorKind::Rally: label = tr("Rallying"); break;
case BehaviorKind::Standby: label = tr("Standby"); break;
case BehaviorKind::Advance: label = tr("Advancing"); break;
case BehaviorKind::None: break;
}
if (label.isEmpty())
{
m_behaviorLabel->setVisible(false);
return;
}
m_behaviorLabel->setText(tr("Behavior: %1").arg(label));
m_behaviorLabel->setVisible(true);
}
void ShipStatsPanel::setThreatCost(double cost) void ShipStatsPanel::setThreatCost(double cost)
{ {
m_threatCostLabel->setText(tr("Threat Cost: %1").arg(cost, 0, 'f', 1)); m_threatCostLabel->setText(tr("Threat Cost: %1").arg(cost, 0, 'f', 1));

View File

@@ -6,6 +6,7 @@
#include <QWidget> #include <QWidget>
#include "BehaviorKind.h"
#include "ShipLayout.h" #include "ShipLayout.h"
#include "ShipStatsCalculator.h" #include "ShipStatsCalculator.h"
@@ -24,6 +25,9 @@ public:
void refreshFromLive(const ShipStats& stats, float currentHp); void refreshFromLive(const ShipStats& stats, float currentHp);
// Displays the ship's current top-priority behavior (REQ-UI-SHIP-BEHAVIOR).
void setBehavior(BehaviorKind kind);
void setThreatCost(double cost); void setThreatCost(double cost);
void setDebugDrawEnabled(bool enabled); void setDebugDrawEnabled(bool enabled);
@@ -33,6 +37,7 @@ private:
const GameConfig* m_config; const GameConfig* m_config;
bool m_debugDraw = false; bool m_debugDraw = false;
QLabel* m_behaviorLabel;
QLabel* m_hpLabel; QLabel* m_hpLabel;
QLabel* m_speedLabel; QLabel* m_speedLabel;
QLabel* m_sensorRangeLabel; QLabel* m_sensorRangeLabel;