schematic selection dialog

This commit is contained in:
2026-06-13 12:00:05 +02:00
parent 1641189b75
commit 49f7129bd5
25 changed files with 453 additions and 268 deletions

View File

@@ -39,6 +39,7 @@
#include "BossWaveUpdatedEvent.h"
#include "BuildingBlocksChangedEvent.h"
#include "GameSpeedChangedEvent.h"
#include "SchematicChoicesAvailableEvent.h"
#include "TickAdvancedEvent.h"
namespace
@@ -68,31 +69,6 @@ Rotation rotateCounterClockwise(Rotation r)
return Rotation::East;
}
QString toDisplayName(const std::string& id)
{
QString result;
bool nextUpper = true;
for (char c : id)
{
if (c == '_')
{
result += ' ';
nextUpper = true;
}
else if (nextUpper)
{
result += static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
nextUpper = false;
}
else
{
result += c;
}
}
return result;
}
QPoint portBodyTile(QPoint portTile, Rotation direction)
{
switch (direction)
@@ -129,6 +105,7 @@ GameWorldView::GameWorldView(Simulation* sim, const GameConfig* config,
, m_scrollLeft(false)
, m_scrollRight(false)
, m_gameOverShown(false)
, m_schematicChoiceShown(false)
{
setFocusPolicy(Qt::StrongFocus);
setMouseTracking(true);
@@ -188,31 +165,6 @@ void GameWorldView::onFrame()
}
}
// Drain schematic drop events → toasts
{
const std::vector<SchematicDropEvent> drops =
m_sim->drainSchematicDropEvents();
for (const SchematicDropEvent& ev : drops)
{
const QString name = toDisplayName(ev.schematicId);
ToastEntry toast;
if (ev.isModuleSchematic)
{
toast.text = ev.wasNewUnlock
? tr("Module unlocked: ") + name
: name + tr(" production level -> ") + QString::number(ev.newLevel);
}
else
{
toast.text = ev.wasNewUnlock
? tr("Schematic unlocked: ") + name
: name + tr(" production level -> ") + QString::number(ev.newLevel);
}
toast.createdWallMs = m_wallMs;
m_toasts.push_back(toast);
}
}
// Expire old beams
{
std::vector<ActiveBeam> live;
@@ -226,19 +178,6 @@ void GameWorldView::onFrame()
m_activeBeams = std::move(live);
}
// Expire old toasts
{
std::vector<ToastEntry> live;
for (const ToastEntry& t : m_toasts)
{
if (m_wallMs - t.createdWallMs < kToastLifetimeMs)
{
live.push_back(t);
}
}
m_toasts = std::move(live);
}
// Apply held scroll
{
const float delta = kScrollSpeedTilesPerSec
@@ -276,6 +215,18 @@ void GameWorldView::onFrame()
}
}
// Schematic choice available
if (m_sim->hasSchematicChoicesPending() && !m_schematicChoiceShown)
{
m_schematicChoiceShown = true;
EventManager::getInstance()->sendEventImmediately(
std::make_shared<SchematicChoicesAvailableEvent>(m_sim->getPendingSchematicChoices()));
}
if (!m_sim->hasSchematicChoicesPending())
{
m_schematicChoiceShown = false;
}
// Game over check
if (m_sim->isGameOver() && !m_gameOverShown)
{
@@ -1097,41 +1048,8 @@ void GameWorldView::drawOverlays(QPainter& painter)
}
}
void GameWorldView::drawScreenSpace(QPainter& painter)
void GameWorldView::drawScreenSpace(QPainter& /*painter*/)
{
painter.resetTransform();
const int margin = 8;
const int toastW = 320;
const int toastH = 36;
const int spacing = 4;
QFont toastFont = painter.font();
toastFont.setPointSize(m_visuals->toast.fontSize);
painter.setFont(toastFont);
int y = margin;
for (const ToastEntry& toast : m_toasts)
{
const qint64 age = m_wallMs - toast.createdWallMs;
double opacity = 1.0;
if (age > kToastFadeStartMs)
{
opacity = 1.0 - static_cast<double>(age - kToastFadeStartMs)
/ static_cast<double>(kToastLifetimeMs - kToastFadeStartMs);
opacity = std::max(0.0, opacity);
}
painter.setOpacity(opacity);
const int x = width() - toastW - margin;
const QRect toastRect(x, y, toastW, toastH);
painter.fillRect(toastRect, m_visuals->toast.bg);
painter.setPen(m_visuals->toast.fg);
painter.drawText(toastRect.adjusted(8, 0, -8, 0),
Qt::AlignVCenter | Qt::AlignLeft, toast.text);
painter.setOpacity(1.0);
y += toastH + spacing;
}
}
// ---------------------------------------------------------------------------
@@ -1526,7 +1444,7 @@ void GameWorldView::resetForNewGame()
exitBuilderMode();
exitBlueprintMode();
m_activeBeams.clear();
m_toasts.clear();
m_schematicChoiceShown = false;
m_ghostRotation = Rotation::East;
m_ghostValid = false;
m_demolishMode = false;