#pragma once #include #include #include #include #include #include #include #include #include #include #include "Blueprint.h" #include "SchematicDropEvent.h" #include "BuildingType.h" #include "BuildingId.h" #include "FireEvent.h" #include "entt/entity/entity.hpp" #include "GameConfig.h" #include "Rotation.h" #include "Tick.h" #include "TickDriver.h" #include "VisualsConfig.h" class Simulation; class QPainter; struct QPointCompare { bool operator()(const QPoint& a, const QPoint& b) const { if (a.x() != b.x()) { return a.x() < b.x(); } return a.y() < b.y(); } }; class GameWorldView : public QOpenGLWidget { Q_OBJECT public: GameWorldView(Simulation* sim, const GameConfig* config, const VisualsConfig* visuals, QWidget* parent = nullptr); signals: void selectionChanged(const std::vector& ids); void gameOver(); void builderModeExited(); void blueprintModeExited(); void escapeMenuRequested(); void demolishModeChanged(bool active); public: double gameSpeed() const; public slots: void enterBuilderMode(BuildingType type); void exitBuilderMode(); void enterBlueprintMode(Blueprint blueprint); void exitBlueprintMode(); void toggleDemolishMode(); void setGameSpeed(double multiplier); void resetForNewGame(); protected: void initializeGL() override; void paintGL() override; void keyPressEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override; void mousePressEvent(QMouseEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override; void mouseReleaseEvent(QMouseEvent* event) override; private slots: void onFrame(); private: void drawTiles(QPainter& painter); void drawBuildings(QPainter& painter); void drawStations(QPainter& painter); void drawBeltItems(QPainter& painter); void drawScrap(QPainter& painter); void drawShips(QPainter& painter); void drawDebugSensorRanges(QPainter& painter); void drawBeams(QPainter& painter); void drawOverlays(QPainter& painter); void drawScreenSpace(QPainter& painter); float tilePx() const; float viewportWidthTiles() const; QPointF worldToWidget(QVector2D worldPos) const; QPointF tileToWidget(QPoint tile) const; QPoint widgetToTile(QPoint widgetPt) const; QRectF tileRect(QPoint tile) const; QRect viewportRect() const; float asteroidLeftEdge() const; float enemyStationRightEdge() const; void clampScroll(); bool isValidPlacement(BuildingType type, QPoint anchor, Rotation rot) const; const BuildingDef* findBuildingDef(BuildingType type) const; BuildingId buildingAtTile(QPoint tile) const; BuildingId siteAtTile(QPoint tile) const; void drawPortGlyph(QPainter& painter, QPoint bodyTile, Rotation direction, const QColor& color); void placeBlueprintAtTile(QPoint center); std::optional entityPosition(entt::entity entity) const; void stepSpeed(int delta); void placeAtTile(QPoint tile); struct ActiveBeam { FireEvent event; qint64 emittedWallMs; QVector2D targetOffset; }; struct ToastEntry { QString text; qint64 createdWallMs; }; static constexpr qint64 kBeamLifetimeMs = 300; static constexpr qint64 kToastLifetimeMs = 4000; static constexpr qint64 kToastFadeStartMs = 3500; static constexpr float kScrollSpeedTilesPerSec = 10.0f; Simulation* m_sim; const GameConfig* m_config; const VisualsConfig* m_visuals; TickDriver m_tickDriver; QElapsedTimer m_frameTimer; qint64 m_wallMs; std::mt19937 m_rng; double m_gameSpeedMultiplier; double m_prevNonZeroSpeed; float m_scrollXTiles; QTimer* m_renderTimer; std::vector m_activeBeams; std::vector m_toasts; std::optional m_builderType; Rotation m_ghostRotation; QPoint m_ghostTile; bool m_ghostValid; std::set m_beltDragTiles; bool m_dragging; std::optional m_blueprintMode; QPoint m_blueprintGhostTile; bool m_demolishMode; BuildingId m_demolishHoverBuildingId; bool m_debugDraw; std::vector m_selectedBuildingIds; bool m_boxSelecting; QPoint m_boxStartTile; QPoint m_boxCurrentTile; bool m_scrollLeft; bool m_scrollRight; bool m_gameOverShown; Tick m_lastTick = Tick(-1); int m_lastBlocks = -1; int m_lastBossCounter = -1; Tick m_lastBossCountdown = Tick(-1); };