switch to using own event system
This commit is contained in:
@@ -59,26 +59,43 @@ Simulation types shared across subsystems:
|
||||
- `Item` — `struct Item { ItemType type; }`. Items on belts have no persistent identity across ticks.
|
||||
- `Port` — `struct Port { QPoint tile; Rotation direction; }`. Identifies a belt-adjacent cell and the direction of flow across that cell.
|
||||
- `MovementIntent` — `struct MovementIntent { int priority; QVector2D target; }`. Priority follows the order declared under Movement Arbitration. Cleared at the start of each tick; the highest-priority write wins; `tickMovement` reads the winner.
|
||||
- `FireEvent` — `struct FireEvent { EntityId shooter; EntityId target; Tick emittedAt; }`. Transient record emitted each time a weapon fires (REQ-SHP-FIRING, REQ-SHP-FIRING-BEAM). Buffered in a sim-owned queue and drained by the renderer; see Sim → UI Events.
|
||||
- `WeaponFiredEvent` — `struct WeaponFiredEvent : public Event { entt::entity shooter; entt::entity target; Tick emittedAt; }`. Transient record emitted each time a weapon fires (REQ-SHP-FIRING, REQ-SHP-FIRING-BEAM). Buffered in a sim-owned vector during the tick, then drained and re-emitted via EventManager by the UI frame handler; see Sim → UI Events.
|
||||
- `SchematicChoiceOption` — `struct SchematicChoiceOption { string schematicId; SchematicType type; string displayName; bool isNewUnlock; int targetLevel; }`. Describes one option in the schematic choice dialog (REQ-DEF-SCHEMATIC-DROP). Up to three are generated when an enemy station set is destroyed. `SchematicType` is `Ship`, `Module`, or `Recipe`.
|
||||
- `SchematicChoicesAvailableEvent` — EventManager event carrying a `vector<SchematicChoiceOption>`. Sent by the UI each frame when pending choices are detected; handled by `MainWindow` which opens the schematic choice dialog.
|
||||
|
||||
## Sim → UI Events
|
||||
## Event System
|
||||
|
||||
The sim owns a per-frame event queue for weapon fires that the UI drains on each render. `FireEvent` records are one-shot signals not derivable from persistent state. Additional one-shot event types can be added here later (e.g., building-complete, unit-death flashes) without changing the pattern.
|
||||
All inter-component communication — both sim→UI and UI→UI — uses a unified `EventManager`/`EventHandler` system. No custom Qt signals/slots are used for inter-widget communication.
|
||||
|
||||
Implementation: a plain `std::vector<FireEvent>` owned by `Simulation`. Combat resolution (tick-order step 8) appends to it. The UI calls `simulation.drainFireEvents()` once per rendered frame, which returns the accumulated vector by move and clears the internal one. Beams are tracked by the renderer for 0.3 s of wall time (9 ticks at 30 Hz) using the events' `emittedAt` tick, then discarded. If either the shooter or target entity is gone when the renderer looks them up, the beam is dropped early.
|
||||
### EventManager
|
||||
|
||||
Schematic drops use a different pattern: when an enemy station set is destroyed, the simulation generates up to 3 `SchematicChoiceOption` entries and stores them as pending state. The UI polls `hasSchematicChoicesPending()` each frame and, when true, sends a `SchematicChoicesAvailableEvent` via the EventManager. `MainWindow` handles this event by pausing the game and opening a modal `SchematicChoiceDialog`. The player's selection is fed back via `applySchematicChoice(index)`, which applies the chosen schematic and clears the pending state.
|
||||
`EventManager` is a singleton (`EventManager::getInstance()`) that routes events to registered handlers.
|
||||
|
||||
We deliberately do **not** use `QObject` signals/slots or `QEvent` for the fire-event queue:
|
||||
- `sendEventImmediately(shared_ptr<Event>)` — synchronous dispatch to all handlers of the event's type.
|
||||
- `addEvent(shared_ptr<Event>)` — queues the event for later batch processing.
|
||||
- `processEvents()` — drains the queue, dispatching each event to its handlers.
|
||||
|
||||
- **Determinism.** A plain ordered vector preserves tick-order exactly; the queue is part of per-tick state, inspectable in tests.
|
||||
- **Sim/UI seam.** The sim exposes pull-style access only; the UI never subscribes into the sim, keeping the simulation/presentation split clean.
|
||||
- **Headless testability.** Catch2 tests read the queue directly after `tick()`; no event loop, no `QApplication`.
|
||||
- **Zero overhead.** Sim types remain plain structs — no `QObject`, no moc, no signal dispatch machinery.
|
||||
The EventManager is thread-safe (mutex-guarded).
|
||||
|
||||
If the number of event types grows past a handful, we can wrap them in a small `EventQueue<T>` template, still owned by the sim.
|
||||
### EventHandler
|
||||
|
||||
`EventHandler<T>` is a CRTP-style template that a class inherits to receive events of type `T`. It provides `registerForEvent()` / `unregisterForEvent()` and requires an override of `handleEvent(shared_ptr<const T>)`.
|
||||
|
||||
`CombinedEventHandler<Ts...>` is a variadic template for classes that handle multiple event types. It provides `registerForEvents()` / `unregisterForEvents()` and requires one `handleEvent` override per type.
|
||||
|
||||
### Sim → UI Events
|
||||
|
||||
The simulation layer stays free of EventManager — it uses a plain `std::vector<WeaponFiredEvent>` internally (owned by `CombatSystem`). This preserves determinism, tick-order fidelity, and headless testability (Catch2 tests read the queue directly via `drainWeaponFiredEvents()` after `tick()`).
|
||||
|
||||
The UI frame handler (`GameWorldView::onFrame` / `ArenaView::onFrame`) bridges the gap: each frame it calls `simulation.drainWeaponFiredEvents()`, then re-emits each `WeaponFiredEvent` via `EventManager::sendEventImmediately()`. Subscribers (the same view's `handleEvent(WeaponFiredEvent)`) create `ActiveBeam` records tracked for 0.3 s of wall time, then discarded. If either the shooter or target entity is gone when the renderer looks them up, the beam is dropped early.
|
||||
|
||||
Schematic drops: when an enemy station set is destroyed, the simulation generates up to 3 `SchematicChoiceOption` entries and stores them as pending state. The UI polls `hasSchematicChoicesPending()` each frame and, when true, sends a `SchematicChoicesAvailableEvent` via EventManager. `MainWindow` handles this event by pausing the game and opening a modal `SchematicChoiceDialog`. The player's selection is fed back via `applySchematicChoice(index)`.
|
||||
|
||||
### UI Events
|
||||
|
||||
All UI interactions — building selection, builder/blueprint mode transitions, speed changes, demolish mode, escape menu, layout dialog requests — are communicated via EventManager events rather than Qt signals/slots. Each event is a small struct inheriting `Event` (e.g., `SelectionChangedEvent`, `BuildingTypeSelectedEvent`, `SpeedChangeRequestedEvent`). Widgets register as `CombinedEventHandler` for the events they care about and emit events via `EventManager::sendEventImmediately()`.
|
||||
|
||||
Bidirectional interactions use separate request/notification event types to avoid infinite recursion (e.g., `ExitBuilderModeRequestedEvent` from `BuildButtonGrid` → `GameWorldView`, vs. `BuilderModeExitedEvent` from `GameWorldView` → `BuildButtonGrid`).
|
||||
|
||||
## Tick Order
|
||||
|
||||
@@ -91,7 +108,7 @@ Within a single simulation tick, subsystems run in this fixed order. The order i
|
||||
5. **Building → belt push** — buildings push items from output buffer onto the belt tile at their output port (REQ-MAT-OUTPUT-PORT).
|
||||
6. **Belt tick** — advance items along belt tiles; apply splitter routing (REQ-BLD-SPLITTER).
|
||||
7. **Ship behavior systems** — clear `MovementIntent` on each ship, then run `tickThreatResponse`, `tickScrapCollector`, `tickRepairBehavior`, `tickHomeReturn` in any order (arbitration is via intent priority).
|
||||
8. **Combat resolution** — ships and defence stations acquire targets, fire, apply damage; queue deaths. Each fire appends a `FireEvent` to the sim's fire-event queue (REQ-SHP-FIRING-BEAM).
|
||||
8. **Combat resolution** — ships and defence stations acquire targets, fire, apply damage; queue deaths. Each fire appends a `WeaponFiredEvent` to the sim's weapon-fired-event queue (REQ-SHP-FIRING-BEAM).
|
||||
9. **Deaths & loot** — process queued deaths: drop scrap (REQ-RES-SCRAP-DROP); if a full enemy-defence-station set was destroyed this tick, generate up to 3 schematic choice options (REQ-DEF-SCHEMATIC-DROP) stored as pending state for the UI to present; remove entities.
|
||||
10. **`tickMovement`** — advance ship positions based on final `MovementIntent`.
|
||||
11. **Scrap despawn** — decrement scrap timers; remove expired scrap (REQ-RES-SCRAP-DROP).
|
||||
@@ -283,7 +300,7 @@ The game world is rendered by a single `GameWorldView` widget that inherits `QOp
|
||||
|
||||
### Threading
|
||||
|
||||
Sim and UI run on the same thread for v1. `paintEvent` reads sim state directly without locks. If profiling later justifies moving the sim to a worker thread, the pull-style `drainFireEvents()` / `getPendingSchematicChoices()` / `applySchematicChoice()` / `forEachVisualItem()` APIs already support a clean snapshot-and-render split; a single mutex at the sim boundary would suffice.
|
||||
Sim and UI run on the same thread for v1. `paintEvent` reads sim state directly without locks. If profiling later justifies moving the sim to a worker thread, the pull-style `drainWeaponFiredEvents()` / `getPendingSchematicChoices()` / `applySchematicChoice()` / `forEachVisualItem()` APIs already support a clean snapshot-and-render split; a single mutex at the sim boundary would suffice. The `ArenaSimulation` used by the balancing tool runs headlessly on a worker thread; fire events accumulate in its internal vector and are only drained when `ArenaView` drives `tickOnce()` on the main thread during interactive inspection.
|
||||
|
||||
### Layer Order (back to front)
|
||||
|
||||
@@ -292,7 +309,7 @@ Sim and UI run on the same thread for v1. `paintEvent` reads sim state directly
|
||||
3. **Belt items** — 10×10 colored squares emitted by `BeltSystem::forEachVisualItem`.
|
||||
4. **Scrap** — glyphs at world positions.
|
||||
5. **Ships** — colored arrows oriented by velocity; color keyed to role (player combat / salvage / repair / enemy).
|
||||
6. **Laser beams** — lines derived from live `FireEvent`s kept by the renderer for 0.3 s (REQ-SHP-FIRING-BEAM).
|
||||
6. **Laser beams** — lines derived from live `WeaponFiredEvent`s kept by the renderer for 0.3 s (REQ-SHP-FIRING-BEAM).
|
||||
7. **Build overlays** — ghost in builder mode (REQ-BLD-GHOST), demolish-mode tint, tile highlight under cursor, box-drag selection rectangle.
|
||||
8. **Screen-space UI** — screen-anchored elements, drawn after resetting the world-space transform.
|
||||
|
||||
|
||||
@@ -259,9 +259,9 @@ void ArenaSimulation::tick()
|
||||
m_aiSystem->tickSalvageBehavior(m_admin, *m_scrapSystem, *m_buildingSystem);
|
||||
|
||||
// Combat resolution (tick step 8).
|
||||
std::vector<FireEvent> fireEvents;
|
||||
m_combatSystem->tick(m_currentTick, m_admin, *m_buildingSystem, fireEvents);
|
||||
m_fireEvents.insert(m_fireEvents.end(), fireEvents.begin(), fireEvents.end());
|
||||
std::vector<WeaponFiredEvent> weaponFiredEvents;
|
||||
m_combatSystem->tick(m_currentTick, m_admin, *m_buildingSystem, weaponFiredEvents);
|
||||
m_weaponFiredEvents.insert(m_weaponFiredEvents.end(), weaponFiredEvents.begin(), weaponFiredEvents.end());
|
||||
m_combatSystem->applyPendingDamage(m_currentTick, m_admin);
|
||||
|
||||
// Deaths (tick step 9, simplified).
|
||||
@@ -393,10 +393,10 @@ void ArenaSimulation::tickOnce()
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<FireEvent> ArenaSimulation::drainFireEvents()
|
||||
std::vector<WeaponFiredEvent> ArenaSimulation::drainWeaponFiredEvents()
|
||||
{
|
||||
std::vector<FireEvent> result;
|
||||
result.swap(m_fireEvents);
|
||||
std::vector<WeaponFiredEvent> result;
|
||||
result.swap(m_weaponFiredEvents);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "BuildingId.h"
|
||||
|
||||
#include "entt/entity/entity.hpp"
|
||||
#include "FireEvent.h"
|
||||
#include "WeaponFiredEvent.h"
|
||||
#include "GameConfig.h"
|
||||
#include "Tick.h"
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
void requestStop();
|
||||
|
||||
void tickOnce();
|
||||
std::vector<FireEvent> drainFireEvents();
|
||||
std::vector<WeaponFiredEvent> drainWeaponFiredEvents();
|
||||
|
||||
ArenaStatus status() const;
|
||||
bool isFinished() const;
|
||||
@@ -104,7 +104,7 @@ private:
|
||||
int m_winnerTeam;
|
||||
std::atomic<bool> m_stopRequested;
|
||||
|
||||
std::vector<FireEvent> m_fireEvents;
|
||||
std::vector<WeaponFiredEvent> m_weaponFiredEvents;
|
||||
|
||||
mutable std::mutex m_statusMutex;
|
||||
ArenaStatus m_status;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "EventManager.h"
|
||||
#include "FacingComponent.h"
|
||||
#include "FactionComponent.h"
|
||||
#include "GameSpeedChangedEvent.h"
|
||||
#include "HealthComponent.h"
|
||||
#include "PositionComponent.h"
|
||||
#include "ScrapSystem.h"
|
||||
@@ -45,6 +46,13 @@ ArenaView::ArenaView(ArenaSimulation* sim, const VisualsConfig* visuals,
|
||||
connect(m_renderTimer, &QTimer::timeout, this, &ArenaView::onFrame);
|
||||
m_renderTimer->start();
|
||||
m_frameTimer.start();
|
||||
|
||||
registerForEvent();
|
||||
}
|
||||
|
||||
ArenaView::~ArenaView()
|
||||
{
|
||||
unregisterForEvent();
|
||||
}
|
||||
|
||||
void ArenaView::setGameSpeed(double multiplier)
|
||||
@@ -54,7 +62,8 @@ void ArenaView::setGameSpeed(double multiplier)
|
||||
m_prevNonZeroSpeed = multiplier;
|
||||
}
|
||||
m_gameSpeedMultiplier = multiplier;
|
||||
emit speedChanged(multiplier);
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<GameSpeedChangedEvent>(multiplier));
|
||||
}
|
||||
|
||||
double ArenaView::gameSpeed() const
|
||||
@@ -93,34 +102,17 @@ void ArenaView::onFrame()
|
||||
}
|
||||
}
|
||||
|
||||
// Emit fire events via EventManager
|
||||
{
|
||||
const std::vector<FireEvent> fires = m_sim->drainFireEvents();
|
||||
for (const FireEvent& fe : fires)
|
||||
const std::vector<WeaponFiredEvent> fires = m_sim->drainWeaponFiredEvents();
|
||||
for (const WeaponFiredEvent& fe : fires)
|
||||
{
|
||||
float maxRadius = 0.125f;
|
||||
if (m_sim->admin().isValid(fe.target)
|
||||
&& m_sim->admin().hasAll<StationBodyComponent>(fe.target))
|
||||
{
|
||||
const StationBodyComponent& sb = m_sim->admin().get<StationBodyComponent>(fe.target);
|
||||
const int shorter = std::min(sb.footprint.width(),
|
||||
sb.footprint.height());
|
||||
maxRadius = shorter / 2.0f;
|
||||
}
|
||||
|
||||
std::uniform_real_distribution<float> angleDist(0.0f, 6.28318530f);
|
||||
std::uniform_real_distribution<float> radiusDist(0.0f, maxRadius);
|
||||
const float angle = angleDist(m_rng);
|
||||
const float radius = radiusDist(m_rng);
|
||||
|
||||
ActiveBeam beam;
|
||||
beam.event = fe;
|
||||
beam.emittedWallMs = m_wallMs;
|
||||
beam.targetOffset = QVector2D(radius * std::cos(angle),
|
||||
radius * std::sin(angle));
|
||||
m_activeBeams.push_back(beam);
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<WeaponFiredEvent>(fe));
|
||||
}
|
||||
}
|
||||
|
||||
// Expire old beams
|
||||
{
|
||||
std::vector<ActiveBeam> live;
|
||||
for (const ActiveBeam& b : m_activeBeams)
|
||||
@@ -136,12 +128,36 @@ void ArenaView::onFrame()
|
||||
if (m_sim->isFinished() && !m_finishedEmitted)
|
||||
{
|
||||
m_finishedEmitted = true;
|
||||
emit finished();
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void ArenaView::handleEvent(std::shared_ptr<const WeaponFiredEvent> event)
|
||||
{
|
||||
float maxRadius = 0.125f;
|
||||
if (m_sim->admin().isValid(event->target)
|
||||
&& m_sim->admin().hasAll<StationBodyComponent>(event->target))
|
||||
{
|
||||
const StationBodyComponent& sb = m_sim->admin().get<StationBodyComponent>(event->target);
|
||||
const int shorter = std::min(sb.footprint.width(),
|
||||
sb.footprint.height());
|
||||
maxRadius = shorter / 2.0f;
|
||||
}
|
||||
|
||||
std::uniform_real_distribution<float> angleDist(0.0f, 6.28318530f);
|
||||
std::uniform_real_distribution<float> radiusDist(0.0f, maxRadius);
|
||||
const float angle = angleDist(m_rng);
|
||||
const float radius = radiusDist(m_rng);
|
||||
|
||||
ActiveBeam beam;
|
||||
beam.event = *event;
|
||||
beam.emittedWallMs = m_wallMs;
|
||||
beam.targetOffset = QVector2D(radius * std::cos(angle),
|
||||
radius * std::sin(angle));
|
||||
m_activeBeams.push_back(beam);
|
||||
}
|
||||
|
||||
void ArenaView::paintGL()
|
||||
{
|
||||
QPainter painter(this);
|
||||
@@ -414,4 +430,3 @@ void ArenaView::drawBeams(QPainter& painter)
|
||||
worldToWidget(*targetPos + beam.targetOffset));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
#include <QTimer>
|
||||
#include <QVector2D>
|
||||
|
||||
#include "FireEvent.h"
|
||||
#include "EventHandler.h"
|
||||
#include "WeaponFiredEvent.h"
|
||||
|
||||
#include "entt/entity/entity.hpp"
|
||||
#include "EntitySelectedEvent.h"
|
||||
@@ -20,23 +21,21 @@
|
||||
class ArenaSimulation;
|
||||
class QPainter;
|
||||
|
||||
class ArenaView : public QOpenGLWidget
|
||||
class ArenaView : public QOpenGLWidget,
|
||||
public EventHandler<WeaponFiredEvent>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ArenaView(ArenaSimulation* sim, const VisualsConfig* visuals,
|
||||
QWidget* parent = nullptr);
|
||||
~ArenaView() override;
|
||||
|
||||
void setGameSpeed(double multiplier);
|
||||
double gameSpeed() const;
|
||||
void togglePause();
|
||||
void stopRendering();
|
||||
|
||||
signals:
|
||||
void speedChanged(double multiplier);
|
||||
void finished();
|
||||
|
||||
protected:
|
||||
void paintGL() override;
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
@@ -45,6 +44,8 @@ private slots:
|
||||
void onFrame();
|
||||
|
||||
private:
|
||||
void handleEvent(std::shared_ptr<const WeaponFiredEvent> event) override;
|
||||
|
||||
void drawTiles(QPainter& painter);
|
||||
void drawBuildings(QPainter& painter);
|
||||
void drawStations(QPainter& painter);
|
||||
@@ -62,7 +63,7 @@ private:
|
||||
|
||||
struct ActiveBeam
|
||||
{
|
||||
FireEvent event;
|
||||
WeaponFiredEvent event;
|
||||
qint64 emittedWallMs;
|
||||
QVector2D targetOffset;
|
||||
};
|
||||
|
||||
@@ -3,8 +3,13 @@
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
ArenaWidget::ArenaWidget(const std::string& arenaName, QWidget* parent)
|
||||
#include "ArenaInspectRequestedEvent.h"
|
||||
#include "ArenaStartRequestedEvent.h"
|
||||
#include "EventManager.h"
|
||||
|
||||
ArenaWidget::ArenaWidget(int arenaIndex, const std::string& arenaName, QWidget* parent)
|
||||
: QFrame(parent)
|
||||
, m_arenaIndex(arenaIndex)
|
||||
, m_running(false)
|
||||
, m_wasFinished(false)
|
||||
{
|
||||
@@ -31,11 +36,17 @@ void ArenaWidget::buildLayout(const std::string& arenaName)
|
||||
titleRow->addStretch();
|
||||
|
||||
m_inspectButton = new QPushButton(tr("Inspect"), this);
|
||||
connect(m_inspectButton, &QPushButton::clicked, this, &ArenaWidget::inspectRequested);
|
||||
connect(m_inspectButton, &QPushButton::clicked, this, [this]() {
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<ArenaInspectRequestedEvent>(m_arenaIndex));
|
||||
});
|
||||
titleRow->addWidget(m_inspectButton);
|
||||
|
||||
m_startButton = new QPushButton(tr("Start"), this);
|
||||
connect(m_startButton, &QPushButton::clicked, this, &ArenaWidget::startRequested);
|
||||
connect(m_startButton, &QPushButton::clicked, this, [this]() {
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<ArenaStartRequestedEvent>(m_arenaIndex));
|
||||
});
|
||||
titleRow->addWidget(m_startButton);
|
||||
|
||||
outerLayout->addLayout(titleRow);
|
||||
|
||||
@@ -14,19 +14,16 @@ class ArenaWidget : public QFrame
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ArenaWidget(const std::string& arenaName, QWidget* parent = nullptr);
|
||||
ArenaWidget(int arenaIndex, const std::string& arenaName, QWidget* parent = nullptr);
|
||||
|
||||
void updateStatus(const ArenaStatus& status);
|
||||
void startSimulation();
|
||||
void resetToGrey();
|
||||
|
||||
signals:
|
||||
void startRequested();
|
||||
void inspectRequested();
|
||||
|
||||
private:
|
||||
void buildLayout(const std::string& arenaName);
|
||||
|
||||
int m_arenaIndex;
|
||||
QLabel* m_titleLabel;
|
||||
QLabel* m_team1Header;
|
||||
QLabel* m_team2Header;
|
||||
|
||||
@@ -48,14 +48,17 @@ BalancingWindow::BalancingWindow(const BalancingConfig& balancingConfig,
|
||||
m_pollTimer = new QTimer(this);
|
||||
connect(m_pollTimer, &QTimer::timeout, this, &BalancingWindow::pollStatuses);
|
||||
m_pollTimer->start(100);
|
||||
|
||||
registerForEvents();
|
||||
}
|
||||
|
||||
BalancingWindow::~BalancingWindow()
|
||||
{
|
||||
unregisterForEvents();
|
||||
|
||||
m_pollTimer->stop();
|
||||
if (m_inspectWindow)
|
||||
{
|
||||
m_inspectWindow->disconnect(this);
|
||||
delete m_inspectWindow;
|
||||
m_inspectWindow = nullptr;
|
||||
}
|
||||
@@ -81,16 +84,11 @@ void BalancingWindow::populateArenas(const BalancingConfig& balancingConfig)
|
||||
entry.config = arenaConfig;
|
||||
entry.simulation = std::make_unique<ArenaSimulation>(
|
||||
m_gameConfig, arenaConfig, m_nextSeed++);
|
||||
entry.widget = new ArenaWidget(arenaConfig.name, scrollContent);
|
||||
entry.widget = new ArenaWidget(index, arenaConfig.name, scrollContent);
|
||||
contentLayout->addWidget(entry.widget);
|
||||
|
||||
entry.widget->updateStatus(entry.simulation->status());
|
||||
|
||||
connect(entry.widget, &ArenaWidget::startRequested,
|
||||
this, [this, index]() { startArena(index); });
|
||||
connect(entry.widget, &ArenaWidget::inspectRequested,
|
||||
this, [this, index]() { inspectArena(index); });
|
||||
|
||||
m_arenas.push_back(std::move(entry));
|
||||
}
|
||||
|
||||
@@ -158,6 +156,21 @@ void BalancingWindow::startAll()
|
||||
}
|
||||
}
|
||||
|
||||
void BalancingWindow::handleEvent(std::shared_ptr<const ArenaStartRequestedEvent> event)
|
||||
{
|
||||
startArena(event->arenaIndex);
|
||||
}
|
||||
|
||||
void BalancingWindow::handleEvent(std::shared_ptr<const ArenaInspectRequestedEvent> event)
|
||||
{
|
||||
inspectArena(event->arenaIndex);
|
||||
}
|
||||
|
||||
void BalancingWindow::handleEvent(std::shared_ptr<const InspectWindowClosedEvent> /*event*/)
|
||||
{
|
||||
closeInspectWindow();
|
||||
}
|
||||
|
||||
void BalancingWindow::startArena(int index)
|
||||
{
|
||||
ArenaEntry& entry = m_arenas[index];
|
||||
@@ -179,7 +192,6 @@ void BalancingWindow::inspectArena(int index)
|
||||
{
|
||||
if (m_inspectWindow)
|
||||
{
|
||||
m_inspectWindow->disconnect(this);
|
||||
delete m_inspectWindow;
|
||||
m_inspectWindow = nullptr;
|
||||
|
||||
@@ -210,8 +222,6 @@ void BalancingWindow::inspectArena(int index)
|
||||
|
||||
m_inspectWindow = new InspectWindow(
|
||||
m_inspectedSim.get(), &m_gameConfig, &m_visuals, entry.config.name, nullptr);
|
||||
connect(m_inspectWindow, &InspectWindow::closed,
|
||||
this, &BalancingWindow::closeInspectWindow);
|
||||
|
||||
setMainControlsEnabled(false);
|
||||
m_inspectWindow->show();
|
||||
@@ -224,7 +234,6 @@ void BalancingWindow::closeInspectWindow()
|
||||
return;
|
||||
}
|
||||
|
||||
m_inspectWindow->disconnect(this);
|
||||
m_inspectWindow->deleteLater();
|
||||
m_inspectWindow = nullptr;
|
||||
|
||||
|
||||
@@ -10,15 +10,22 @@
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
#include "ArenaInspectRequestedEvent.h"
|
||||
#include "ArenaStartRequestedEvent.h"
|
||||
#include "ArenaWidget.h"
|
||||
#include "ArenaSimulation.h"
|
||||
#include "BalancingConfig.h"
|
||||
#include "EventHandler.h"
|
||||
#include "GameConfig.h"
|
||||
#include "InspectWindowClosedEvent.h"
|
||||
#include "VisualsConfig.h"
|
||||
|
||||
class InspectWindow;
|
||||
|
||||
class BalancingWindow : public QWidget
|
||||
class BalancingWindow : public QWidget,
|
||||
public CombinedEventHandler<ArenaStartRequestedEvent,
|
||||
ArenaInspectRequestedEvent,
|
||||
InspectWindowClosedEvent>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -30,15 +37,20 @@ public:
|
||||
QWidget* parent = nullptr);
|
||||
~BalancingWindow() override;
|
||||
|
||||
private:
|
||||
void handleEvent(std::shared_ptr<const ArenaStartRequestedEvent> event) override;
|
||||
void handleEvent(std::shared_ptr<const ArenaInspectRequestedEvent> event) override;
|
||||
void handleEvent(std::shared_ptr<const InspectWindowClosedEvent> event) override;
|
||||
|
||||
private slots:
|
||||
void pollStatuses();
|
||||
void reloadConfig();
|
||||
void startAll();
|
||||
|
||||
private:
|
||||
void startArena(int index);
|
||||
void inspectArena(int index);
|
||||
void closeInspectWindow();
|
||||
|
||||
private:
|
||||
void populateArenas(const BalancingConfig& balancingConfig);
|
||||
void stopAllArenas();
|
||||
void updateButtons();
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
|
||||
#include "ArenaView.h"
|
||||
#include "EntityAdmin.h"
|
||||
#include "EventManager.h"
|
||||
#include "HealthComponent.h"
|
||||
#include "InspectWindowClosedEvent.h"
|
||||
#include "ModuleOwnerComponent.h"
|
||||
#include "ShipIdentityComponent.h"
|
||||
#include "ShipStatsCalculator.h"
|
||||
@@ -76,9 +78,6 @@ InspectWindow::InspectWindow(ArenaSimulation* sim, const GameConfig* config,
|
||||
m_arenaView = new ArenaView(sim, visuals, this);
|
||||
mainLayout->addWidget(m_arenaView, 1);
|
||||
|
||||
connect(m_arenaView, &ArenaView::speedChanged,
|
||||
this, &InspectWindow::onSpeedChanged);
|
||||
|
||||
// Info panel (bottom)
|
||||
{
|
||||
QWidget* infoPanel = new QWidget(this);
|
||||
@@ -140,19 +139,20 @@ InspectWindow::InspectWindow(ArenaSimulation* sim, const GameConfig* config,
|
||||
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
|
||||
registerForEvent();
|
||||
registerForEvents();
|
||||
}
|
||||
|
||||
InspectWindow::~InspectWindow()
|
||||
{
|
||||
unregisterForEvent();
|
||||
unregisterForEvents();
|
||||
}
|
||||
|
||||
void InspectWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
m_arenaView->stopRendering();
|
||||
m_pollTimer->stop();
|
||||
emit closed();
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<InspectWindowClosedEvent>());
|
||||
event->accept();
|
||||
}
|
||||
|
||||
@@ -176,11 +176,11 @@ void InspectWindow::onSpeedButton(int index)
|
||||
}
|
||||
}
|
||||
|
||||
void InspectWindow::onSpeedChanged(double multiplier)
|
||||
void InspectWindow::handleEvent(std::shared_ptr<const GameSpeedChangedEvent> event)
|
||||
{
|
||||
for (int i = 0; i < kSpeedCount; ++i)
|
||||
{
|
||||
const bool active = (std::abs(kSpeeds[i] - multiplier) < 0.001);
|
||||
const bool active = (std::abs(kSpeeds[i] - event->speed) < 0.001);
|
||||
m_speedButtons[static_cast<std::size_t>(i)]->setChecked(active);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,13 +15,15 @@
|
||||
#include "EntitySelectedEvent.h"
|
||||
#include "EventHandler.h"
|
||||
#include "GameConfig.h"
|
||||
#include "GameSpeedChangedEvent.h"
|
||||
#include "VisualsConfig.h"
|
||||
|
||||
class ArenaView;
|
||||
class ShipStatsPanel;
|
||||
|
||||
class InspectWindow : public QWidget,
|
||||
public EventHandler<EntitySelectedEvent>
|
||||
public CombinedEventHandler<EntitySelectedEvent,
|
||||
GameSpeedChangedEvent>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -31,19 +33,16 @@ public:
|
||||
const std::string& arenaName, QWidget* parent = nullptr);
|
||||
~InspectWindow() override;
|
||||
|
||||
signals:
|
||||
void closed();
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent* event) override;
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
|
||||
private:
|
||||
void handleEvent(std::shared_ptr<const EntitySelectedEvent> event) override;
|
||||
void handleEvent(std::shared_ptr<const GameSpeedChangedEvent> event) override;
|
||||
|
||||
private slots:
|
||||
void onSpeedButton(int index);
|
||||
void onSpeedChanged(double multiplier);
|
||||
void pollStatus();
|
||||
|
||||
private:
|
||||
|
||||
@@ -6,7 +6,6 @@ SET(HDRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/EntityAdmin.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Blueprint.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BuildingId.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/FireEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ItemType.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Item.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Port.h
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Tick.h"
|
||||
|
||||
#include "entt/entity/entity.hpp"
|
||||
|
||||
// Transient record emitted each time a weapon fires (REQ-SHP-FIRING,
|
||||
// REQ-SHP-FIRING-BEAM). Buffered in a sim-owned queue and drained by the
|
||||
// renderer each frame to draw the 0.3-second laser beam.
|
||||
struct FireEvent
|
||||
{
|
||||
entt::entity shooter;
|
||||
entt::entity target;
|
||||
Tick emittedAt;
|
||||
};
|
||||
@@ -21,7 +21,7 @@ CombatSystem::CombatSystem(const GameConfig& config)
|
||||
void CombatSystem::tick(Tick currentTick,
|
||||
EntityAdmin& admin,
|
||||
BuildingSystem& /*buildings*/,
|
||||
std::vector<FireEvent>& outFireEvents)
|
||||
std::vector<WeaponFiredEvent>& outWeaponFiredEvents)
|
||||
{
|
||||
TRACE();
|
||||
// All weapons (ships and stations) are child entities linked via ModuleOwnerComponent.
|
||||
@@ -35,7 +35,7 @@ void CombatSystem::tick(Tick currentTick,
|
||||
}
|
||||
const PositionComponent& pos = admin.get<PositionComponent>(owner.owner);
|
||||
const FactionComponent& faction = admin.get<FactionComponent>(owner.owner);
|
||||
resolveWeapon(owner.owner, weapon, pos, faction, currentTick, admin, outFireEvents);
|
||||
resolveWeapon(owner.owner, weapon, pos, faction, currentTick, admin, outWeaponFiredEvents);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ void CombatSystem::resolveWeapon(
|
||||
const FactionComponent& ownFaction,
|
||||
Tick currentTick,
|
||||
EntityAdmin& admin,
|
||||
std::vector<FireEvent>& out)
|
||||
std::vector<WeaponFiredEvent>& out)
|
||||
{
|
||||
if (weapon.cooldownTicks > 0.0f)
|
||||
{
|
||||
@@ -115,7 +115,7 @@ void CombatSystem::resolveWeapon(
|
||||
m_pendingDamage.push_back({targetEntity, weapon.damage,
|
||||
currentTick + kWeaponImpactDelayTicks});
|
||||
|
||||
FireEvent evt;
|
||||
WeaponFiredEvent evt;
|
||||
evt.shooter = shipEntity;
|
||||
evt.target = targetEntity;
|
||||
evt.emittedAt = currentTick;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include "Building.h"
|
||||
#include "FactionComponent.h"
|
||||
#include "FireEvent.h"
|
||||
#include "WeaponFiredEvent.h"
|
||||
#include "GameConfig.h"
|
||||
#include "PositionComponent.h"
|
||||
#include "Tick.h"
|
||||
@@ -26,7 +26,7 @@ public:
|
||||
void tick(Tick currentTick,
|
||||
EntityAdmin& admin,
|
||||
BuildingSystem& buildings,
|
||||
std::vector<FireEvent>& outFireEvents);
|
||||
std::vector<WeaponFiredEvent>& outWeaponFiredEvents);
|
||||
|
||||
void applyPendingDamage(Tick currentTick, EntityAdmin& admin);
|
||||
|
||||
@@ -47,7 +47,7 @@ private:
|
||||
const FactionComponent& ownFaction,
|
||||
Tick currentTick,
|
||||
EntityAdmin& admin,
|
||||
std::vector<FireEvent>& out);
|
||||
std::vector<WeaponFiredEvent>& out);
|
||||
|
||||
const GameConfig& m_config;
|
||||
};
|
||||
|
||||
10
src/lib/eventsystem/event/ArenaInspectRequestedEvent.h
Normal file
10
src/lib/eventsystem/event/ArenaInspectRequestedEvent.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "Event.h"
|
||||
|
||||
class ArenaInspectRequestedEvent : public Event
|
||||
{
|
||||
public:
|
||||
explicit ArenaInspectRequestedEvent(int arenaIndex) : arenaIndex(arenaIndex) {}
|
||||
const int arenaIndex;
|
||||
};
|
||||
10
src/lib/eventsystem/event/ArenaStartRequestedEvent.h
Normal file
10
src/lib/eventsystem/event/ArenaStartRequestedEvent.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "Event.h"
|
||||
|
||||
class ArenaStartRequestedEvent : public Event
|
||||
{
|
||||
public:
|
||||
explicit ArenaStartRequestedEvent(int arenaIndex) : arenaIndex(arenaIndex) {}
|
||||
const int arenaIndex;
|
||||
};
|
||||
7
src/lib/eventsystem/event/BlueprintModeExitedEvent.h
Normal file
7
src/lib/eventsystem/event/BlueprintModeExitedEvent.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Event.h"
|
||||
|
||||
class BlueprintModeExitedEvent : public Event
|
||||
{
|
||||
};
|
||||
12
src/lib/eventsystem/event/BlueprintPlacementRequestedEvent.h
Normal file
12
src/lib/eventsystem/event/BlueprintPlacementRequestedEvent.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "Blueprint.h"
|
||||
#include "Event.h"
|
||||
|
||||
class BlueprintPlacementRequestedEvent : public Event
|
||||
{
|
||||
public:
|
||||
explicit BlueprintPlacementRequestedEvent(Blueprint blueprint)
|
||||
: blueprint(std::move(blueprint)) {}
|
||||
const Blueprint blueprint;
|
||||
};
|
||||
7
src/lib/eventsystem/event/BuilderModeExitedEvent.h
Normal file
7
src/lib/eventsystem/event/BuilderModeExitedEvent.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Event.h"
|
||||
|
||||
class BuilderModeExitedEvent : public Event
|
||||
{
|
||||
};
|
||||
11
src/lib/eventsystem/event/BuildingTypeSelectedEvent.h
Normal file
11
src/lib/eventsystem/event/BuildingTypeSelectedEvent.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "BuildingType.h"
|
||||
#include "Event.h"
|
||||
|
||||
class BuildingTypeSelectedEvent : public Event
|
||||
{
|
||||
public:
|
||||
explicit BuildingTypeSelectedEvent(BuildingType type) : type(type) {}
|
||||
const BuildingType type;
|
||||
};
|
||||
@@ -7,6 +7,23 @@ SET(HDRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/GameSpeedChangedEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BossWaveUpdatedEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/SchematicChoicesAvailableEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/SelectionChangedEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/GameOverEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BuilderModeExitedEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BlueprintModeExitedEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/EscapeMenuRequestedEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/DemolishModeChangedEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BuildingTypeSelectedEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ExitBuilderModeRequestedEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/DemolishModeToggleRequestedEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BlueprintPlacementRequestedEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ExitBlueprintModeRequestedEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/SpeedChangeRequestedEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/LayoutDialogRequestedEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/InspectWindowClosedEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ArenaStartRequestedEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ArenaInspectRequestedEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/WeaponFiredEvent.h
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
|
||||
10
src/lib/eventsystem/event/DemolishModeChangedEvent.h
Normal file
10
src/lib/eventsystem/event/DemolishModeChangedEvent.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "Event.h"
|
||||
|
||||
class DemolishModeChangedEvent : public Event
|
||||
{
|
||||
public:
|
||||
explicit DemolishModeChangedEvent(bool active) : active(active) {}
|
||||
const bool active;
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Event.h"
|
||||
|
||||
class DemolishModeToggleRequestedEvent : public Event
|
||||
{
|
||||
};
|
||||
7
src/lib/eventsystem/event/EscapeMenuRequestedEvent.h
Normal file
7
src/lib/eventsystem/event/EscapeMenuRequestedEvent.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Event.h"
|
||||
|
||||
class EscapeMenuRequestedEvent : public Event
|
||||
{
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Event.h"
|
||||
|
||||
class ExitBlueprintModeRequestedEvent : public Event
|
||||
{
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Event.h"
|
||||
|
||||
class ExitBuilderModeRequestedEvent : public Event
|
||||
{
|
||||
};
|
||||
7
src/lib/eventsystem/event/GameOverEvent.h
Normal file
7
src/lib/eventsystem/event/GameOverEvent.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Event.h"
|
||||
|
||||
class GameOverEvent : public Event
|
||||
{
|
||||
};
|
||||
7
src/lib/eventsystem/event/InspectWindowClosedEvent.h
Normal file
7
src/lib/eventsystem/event/InspectWindowClosedEvent.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Event.h"
|
||||
|
||||
class InspectWindowClosedEvent : public Event
|
||||
{
|
||||
};
|
||||
12
src/lib/eventsystem/event/LayoutDialogRequestedEvent.h
Normal file
12
src/lib/eventsystem/event/LayoutDialogRequestedEvent.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "BuildingId.h"
|
||||
#include "Event.h"
|
||||
|
||||
class LayoutDialogRequestedEvent : public Event
|
||||
{
|
||||
public:
|
||||
explicit LayoutDialogRequestedEvent(BuildingId shipyardId)
|
||||
: shipyardId(shipyardId) {}
|
||||
const BuildingId shipyardId;
|
||||
};
|
||||
14
src/lib/eventsystem/event/SelectionChangedEvent.h
Normal file
14
src/lib/eventsystem/event/SelectionChangedEvent.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "BuildingId.h"
|
||||
#include "Event.h"
|
||||
|
||||
class SelectionChangedEvent : public Event
|
||||
{
|
||||
public:
|
||||
explicit SelectionChangedEvent(std::vector<BuildingId> ids)
|
||||
: ids(std::move(ids)) {}
|
||||
const std::vector<BuildingId> ids;
|
||||
};
|
||||
10
src/lib/eventsystem/event/SpeedChangeRequestedEvent.h
Normal file
10
src/lib/eventsystem/event/SpeedChangeRequestedEvent.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "Event.h"
|
||||
|
||||
class SpeedChangeRequestedEvent : public Event
|
||||
{
|
||||
public:
|
||||
explicit SpeedChangeRequestedEvent(double multiplier) : multiplier(multiplier) {}
|
||||
const double multiplier;
|
||||
};
|
||||
17
src/lib/eventsystem/event/WeaponFiredEvent.h
Normal file
17
src/lib/eventsystem/event/WeaponFiredEvent.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "Event.h"
|
||||
#include "Tick.h"
|
||||
|
||||
#include "entt/entity/entity.hpp"
|
||||
|
||||
struct WeaponFiredEvent : public Event
|
||||
{
|
||||
WeaponFiredEvent() = default;
|
||||
WeaponFiredEvent(entt::entity shooter, entt::entity target, Tick emittedAt)
|
||||
: shooter(shooter), target(target), emittedAt(emittedAt) {}
|
||||
|
||||
entt::entity shooter = entt::null;
|
||||
entt::entity target = entt::null;
|
||||
Tick emittedAt = 0;
|
||||
};
|
||||
@@ -136,7 +136,7 @@ void Simulation::reset(unsigned int seed)
|
||||
m_playerStation2Entity = entt::null;
|
||||
m_currentEnemyStationEntities[0] = entt::null;
|
||||
m_currentEnemyStationEntities[1] = entt::null;
|
||||
m_fireEvents.clear();
|
||||
m_weaponFiredEvents.clear();
|
||||
m_pendingSchematicChoices.clear();
|
||||
|
||||
m_admin.clear();
|
||||
@@ -246,7 +246,7 @@ void Simulation::tick()
|
||||
|
||||
// Step 8: combat resolution
|
||||
m_combatSystem->tick(m_currentTick, m_admin,
|
||||
*m_buildingSystem, m_fireEvents);
|
||||
*m_buildingSystem, m_weaponFiredEvents);
|
||||
|
||||
// Step 8b: deferred damage whose impact tick has arrived
|
||||
m_combatSystem->applyPendingDamage(m_currentTick, m_admin);
|
||||
@@ -745,10 +745,10 @@ bool Simulation::isItemUnlocked(const std::string& itemId) const
|
||||
// Drains
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
std::vector<FireEvent> Simulation::drainFireEvents()
|
||||
std::vector<WeaponFiredEvent> Simulation::drainWeaponFiredEvents()
|
||||
{
|
||||
std::vector<FireEvent> result;
|
||||
result.swap(m_fireEvents);
|
||||
std::vector<WeaponFiredEvent> result;
|
||||
result.swap(m_weaponFiredEvents);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "BuildingType.h"
|
||||
#include "BuildingId.h"
|
||||
#include "EventHandler.h"
|
||||
#include "FireEvent.h"
|
||||
#include "WeaponFiredEvent.h"
|
||||
#include "GameConfig.h"
|
||||
#include "Rotation.h"
|
||||
#include "Tick.h"
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
|
||||
// Returns all fire events accumulated since the last drain, clearing the
|
||||
// internal queue. Call once per rendered frame (REQ-SHP-FIRING-BEAM).
|
||||
std::vector<FireEvent> drainFireEvents();
|
||||
std::vector<WeaponFiredEvent> drainWeaponFiredEvents();
|
||||
|
||||
// Returns the pending schematic choices (empty if no drop is pending).
|
||||
const std::vector<SchematicChoiceOption>& getPendingSchematicChoices() const;
|
||||
@@ -165,6 +165,6 @@ private:
|
||||
std::unique_ptr<WaveSystem> m_waveSystem;
|
||||
std::unique_ptr<CombatSystem> m_combatSystem;
|
||||
|
||||
std::vector<FireEvent> m_fireEvents;
|
||||
std::vector<WeaponFiredEvent> m_weaponFiredEvents;
|
||||
std::vector<SchematicChoiceOption> m_pendingSchematicChoices;
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "ConfigLoader.h"
|
||||
#include "EntityAdmin.h"
|
||||
#include "FactionComponent.h"
|
||||
#include "FireEvent.h"
|
||||
#include "WeaponFiredEvent.h"
|
||||
#include "HealthComponent.h"
|
||||
#include "HqProxyComponent.h"
|
||||
#include "ModuleOwnerComponent.h"
|
||||
@@ -111,7 +111,7 @@ TEST_CASE("CombatSystem: ship fires when cooldown=0 and target in range", "[comb
|
||||
|
||||
const float hpBefore = f.admin.get<HealthComponent>(player).hp;
|
||||
|
||||
std::vector<FireEvent> events;
|
||||
std::vector<WeaponFiredEvent> events;
|
||||
f.combat.tick(0, f.admin, f.buildings, events);
|
||||
f.combat.applyPendingDamage(5, f.admin);
|
||||
|
||||
@@ -135,16 +135,16 @@ TEST_CASE("CombatSystem: cooldown prevents firing before it expires", "[combat]"
|
||||
f.admin.get<WeaponComponent>(wc).cooldownTicks = 3.0f; // override to 3
|
||||
}
|
||||
|
||||
auto enemyFiredIn = [&enemy](const std::vector<FireEvent>& evts)
|
||||
auto enemyFiredIn = [&enemy](const std::vector<WeaponFiredEvent>& evts)
|
||||
{
|
||||
for (const FireEvent& evt : evts)
|
||||
for (const WeaponFiredEvent& evt : evts)
|
||||
{
|
||||
if (evt.shooter == enemy) { return true; }
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
std::vector<FireEvent> events;
|
||||
std::vector<WeaponFiredEvent> events;
|
||||
f.combat.tick(0, f.admin, f.buildings, events);
|
||||
REQUIRE_FALSE(enemyFiredIn(events));
|
||||
|
||||
@@ -165,7 +165,7 @@ TEST_CASE("CombatSystem: no fire when target is out of range", "[combat]")
|
||||
const entt::entity player = f.ships.spawn(combatDef->id, 1, QVector2D(500.0f, 0.0f), false);
|
||||
f.wireEnemyTarget(enemy, player);
|
||||
|
||||
std::vector<FireEvent> events;
|
||||
std::vector<WeaponFiredEvent> events;
|
||||
f.combat.tick(0, f.admin, f.buildings, events);
|
||||
REQUIRE(events.empty());
|
||||
}
|
||||
@@ -204,9 +204,9 @@ TEST_CASE("CombatSystem: player station fires at enemy ship in range", "[combat]
|
||||
|
||||
sim.tick();
|
||||
|
||||
const std::vector<FireEvent> events = sim.drainFireEvents();
|
||||
const std::vector<WeaponFiredEvent> events = sim.drainWeaponFiredEvents();
|
||||
bool stationFired = false;
|
||||
for (const FireEvent& evt : events)
|
||||
for (const WeaponFiredEvent& evt : events)
|
||||
{
|
||||
if (evt.shooter == stationEntity) { stationFired = true; }
|
||||
}
|
||||
@@ -242,9 +242,9 @@ TEST_CASE("CombatSystem: enemy station fires at player ship in range", "[combat]
|
||||
|
||||
sim.tick();
|
||||
|
||||
const std::vector<FireEvent> events = sim.drainFireEvents();
|
||||
const std::vector<WeaponFiredEvent> events = sim.drainWeaponFiredEvents();
|
||||
bool stationFired = false;
|
||||
for (const FireEvent& evt : events)
|
||||
for (const WeaponFiredEvent& evt : events)
|
||||
{
|
||||
if (evt.shooter == stationEntity) { stationFired = true; }
|
||||
}
|
||||
@@ -280,9 +280,9 @@ TEST_CASE("CombatSystem: player ship fires at enemy station in range", "[combat]
|
||||
|
||||
sim.tick();
|
||||
|
||||
const std::vector<FireEvent> events = sim.drainFireEvents();
|
||||
const std::vector<WeaponFiredEvent> events = sim.drainWeaponFiredEvents();
|
||||
bool playerFiredAtStation = false;
|
||||
for (const FireEvent& evt : events)
|
||||
for (const WeaponFiredEvent& evt : events)
|
||||
{
|
||||
if (evt.shooter == playerShip && evt.target == stationEntity)
|
||||
{
|
||||
@@ -308,7 +308,7 @@ TEST_CASE("CombatSystem: damage not applied before impact tick", "[combat]")
|
||||
|
||||
const float hpBefore = f.admin.get<HealthComponent>(player).hp;
|
||||
|
||||
std::vector<FireEvent> events;
|
||||
std::vector<WeaponFiredEvent> events;
|
||||
f.combat.tick(0, f.admin, f.buildings, events);
|
||||
|
||||
for (Tick t = 1; t < 5; ++t)
|
||||
@@ -330,7 +330,7 @@ TEST_CASE("CombatSystem: damage applied exactly at impact tick", "[combat]")
|
||||
|
||||
const float hpBefore = f.admin.get<HealthComponent>(player).hp;
|
||||
|
||||
std::vector<FireEvent> events;
|
||||
std::vector<WeaponFiredEvent> events;
|
||||
f.combat.tick(0, f.admin, f.buildings, events);
|
||||
f.combat.applyPendingDamage(5, f.admin);
|
||||
|
||||
@@ -347,7 +347,7 @@ TEST_CASE("CombatSystem: damage silently dropped if target already dead", "[comb
|
||||
const entt::entity player = f.ships.spawn(combatDef->id, 1, QVector2D(4.0f, 5.0f), false);
|
||||
f.wireEnemyTarget(enemy, player);
|
||||
|
||||
std::vector<FireEvent> events;
|
||||
std::vector<WeaponFiredEvent> events;
|
||||
f.combat.tick(0, f.admin, f.buildings, events);
|
||||
|
||||
f.ships.despawn(player);
|
||||
@@ -370,7 +370,7 @@ TEST_CASE("CombatSystem: damage still applied if shooter already dead", "[combat
|
||||
|
||||
const float hpBefore = f.admin.get<HealthComponent>(player).hp;
|
||||
|
||||
std::vector<FireEvent> events;
|
||||
std::vector<WeaponFiredEvent> events;
|
||||
f.combat.tick(0, f.admin, f.buildings, events);
|
||||
|
||||
f.ships.despawn(enemy);
|
||||
|
||||
@@ -43,22 +43,22 @@ TEST_CASE("Simulation::tick 10 times yields currentTick == 10", "[simulation]")
|
||||
REQUIRE(sim.currentTick() == 10);
|
||||
}
|
||||
|
||||
TEST_CASE("Simulation::drainFireEvents returns empty initially", "[simulation]")
|
||||
TEST_CASE("Simulation::drainWeaponFiredEvents returns empty initially", "[simulation]")
|
||||
{
|
||||
Simulation sim(loadConfig());
|
||||
|
||||
REQUIRE(sim.drainFireEvents().empty());
|
||||
REQUIRE(sim.drainWeaponFiredEvents().empty());
|
||||
}
|
||||
|
||||
TEST_CASE("Simulation::drainFireEvents clears queue on drain", "[simulation]")
|
||||
TEST_CASE("Simulation::drainWeaponFiredEvents clears queue on drain", "[simulation]")
|
||||
{
|
||||
Simulation sim(loadConfig());
|
||||
|
||||
// First drain: empty.
|
||||
sim.drainFireEvents();
|
||||
sim.drainWeaponFiredEvents();
|
||||
|
||||
// Second drain must also be empty (not a double-return).
|
||||
REQUIRE(sim.drainFireEvents().empty());
|
||||
REQUIRE(sim.drainWeaponFiredEvents().empty());
|
||||
}
|
||||
|
||||
TEST_CASE("Simulation::hasSchematicChoicesPending returns false initially", "[simulation]")
|
||||
|
||||
@@ -12,8 +12,11 @@
|
||||
#include <QScrollArea>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "BlueprintPlacementRequestedEvent.h"
|
||||
#include "BlueprintSerializer.h"
|
||||
#include "BuildingBlocksChangedEvent.h"
|
||||
#include "EventManager.h"
|
||||
#include "ExitBlueprintModeRequestedEvent.h"
|
||||
|
||||
#include "Building.h"
|
||||
#include "BuildingSystem.h"
|
||||
@@ -62,12 +65,12 @@ BlueprintPanel::BlueprintPanel(Simulation* sim, const GameConfig* config, QWidge
|
||||
connect(m_saveBtn, &QPushButton::clicked, this, &BlueprintPanel::onSaveClicked);
|
||||
connect(m_loadBtn, &QPushButton::clicked, this, &BlueprintPanel::onLoadClicked);
|
||||
|
||||
registerForEvent();
|
||||
registerForEvents();
|
||||
}
|
||||
|
||||
BlueprintPanel::~BlueprintPanel()
|
||||
{
|
||||
unregisterForEvent();
|
||||
unregisterForEvents();
|
||||
}
|
||||
|
||||
void BlueprintPanel::onSelectionChanged(const std::vector<BuildingId>& ids)
|
||||
@@ -114,7 +117,8 @@ void BlueprintPanel::onDeleteBlueprintClicked(int index)
|
||||
if (m_activeIndex == index)
|
||||
{
|
||||
m_activeIndex = -1;
|
||||
emit exitBlueprintModeRequested();
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<ExitBlueprintModeRequestedEvent>());
|
||||
}
|
||||
else if (m_activeIndex > index)
|
||||
{
|
||||
@@ -131,7 +135,8 @@ void BlueprintPanel::onBlueprintButtonClicked(int index)
|
||||
if (m_activeIndex == index)
|
||||
{
|
||||
clearActiveBlueprintButton();
|
||||
emit exitBlueprintModeRequested();
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<ExitBlueprintModeRequestedEvent>());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -142,7 +147,8 @@ void BlueprintPanel::onBlueprintButtonClicked(int index)
|
||||
|
||||
m_activeIndex = index;
|
||||
m_blueprintButtons[static_cast<std::size_t>(index)]->setChecked(true);
|
||||
emit blueprintPlacementRequested(m_blueprints[static_cast<std::size_t>(index)]);
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<BlueprintPlacementRequestedEvent>(m_blueprints[static_cast<std::size_t>(index)]));
|
||||
}
|
||||
|
||||
Blueprint BlueprintPanel::createBlueprintFromSelection() const
|
||||
@@ -312,7 +318,8 @@ void BlueprintPanel::onLoadClicked()
|
||||
|
||||
if (m_activeIndex >= 0)
|
||||
{
|
||||
emit exitBlueprintModeRequested();
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<ExitBlueprintModeRequestedEvent>());
|
||||
m_activeIndex = -1;
|
||||
}
|
||||
|
||||
@@ -350,3 +357,13 @@ void BlueprintPanel::refreshButtonStates()
|
||||
canAfford || m_activeIndex == i);
|
||||
}
|
||||
}
|
||||
|
||||
void BlueprintPanel::handleEvent(std::shared_ptr<const SelectionChangedEvent> event)
|
||||
{
|
||||
onSelectionChanged(event->ids);
|
||||
}
|
||||
|
||||
void BlueprintPanel::handleEvent(std::shared_ptr<const BlueprintModeExitedEvent> /*event*/)
|
||||
{
|
||||
clearActiveBlueprintButton();
|
||||
}
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
#include <QWidget>
|
||||
|
||||
#include "Blueprint.h"
|
||||
#include "BlueprintModeExitedEvent.h"
|
||||
#include "BuildingBlocksChangedEvent.h"
|
||||
#include "BuildingId.h"
|
||||
#include "EventHandler.h"
|
||||
#include "GameConfig.h"
|
||||
#include "SelectionChangedEvent.h"
|
||||
#include "Tick.h"
|
||||
|
||||
class Simulation;
|
||||
@@ -17,7 +19,9 @@ class QScrollArea;
|
||||
class QVBoxLayout;
|
||||
|
||||
class BlueprintPanel : public QWidget,
|
||||
public EventHandler<BuildingBlocksChangedEvent>
|
||||
public CombinedEventHandler<BuildingBlocksChangedEvent,
|
||||
SelectionChangedEvent,
|
||||
BlueprintModeExitedEvent>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -25,16 +29,10 @@ public:
|
||||
BlueprintPanel(Simulation* sim, const GameConfig* config, QWidget* parent = nullptr);
|
||||
~BlueprintPanel() override;
|
||||
|
||||
public slots:
|
||||
void onSelectionChanged(const std::vector<BuildingId>& ids);
|
||||
void clearActiveBlueprintButton();
|
||||
|
||||
signals:
|
||||
void blueprintPlacementRequested(Blueprint blueprint);
|
||||
void exitBlueprintModeRequested();
|
||||
|
||||
private:
|
||||
void handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event) override;
|
||||
void handleEvent(std::shared_ptr<const SelectionChangedEvent> event) override;
|
||||
void handleEvent(std::shared_ptr<const BlueprintModeExitedEvent> event) override;
|
||||
|
||||
private slots:
|
||||
void onCreateClicked();
|
||||
@@ -44,6 +42,8 @@ private slots:
|
||||
void onLoadClicked();
|
||||
|
||||
private:
|
||||
void onSelectionChanged(const std::vector<BuildingId>& ids);
|
||||
void clearActiveBlueprintButton();
|
||||
Blueprint createBlueprintFromSelection() const;
|
||||
int computeBlueprintCost(const Blueprint& bp) const;
|
||||
void rebuildButtons();
|
||||
|
||||
@@ -7,7 +7,11 @@
|
||||
#include <QSignalMapper>
|
||||
|
||||
#include "BuildingType.h"
|
||||
#include "BuildingTypeSelectedEvent.h"
|
||||
#include "DemolishModeToggleRequestedEvent.h"
|
||||
#include "DisplayName.h"
|
||||
#include "EventManager.h"
|
||||
#include "ExitBuilderModeRequestedEvent.h"
|
||||
|
||||
|
||||
BuildButtonGrid::BuildButtonGrid(const GameConfig* config, QWidget* parent)
|
||||
@@ -58,7 +62,17 @@ BuildButtonGrid::BuildButtonGrid(const GameConfig* config, QWidget* parent)
|
||||
m_demolishButton->setCheckable(true);
|
||||
m_demolishButton->setFixedHeight(48);
|
||||
layout->addWidget(m_demolishButton, row, col);
|
||||
connect(m_demolishButton, SIGNAL(clicked()), this, SIGNAL(demolishModeToggleRequested()));
|
||||
connect(m_demolishButton, &QPushButton::clicked, this, [this]() {
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<DemolishModeToggleRequestedEvent>());
|
||||
});
|
||||
|
||||
registerForEvents();
|
||||
}
|
||||
|
||||
BuildButtonGrid::~BuildButtonGrid()
|
||||
{
|
||||
unregisterForEvents();
|
||||
}
|
||||
|
||||
void BuildButtonGrid::updateAffordability(int buildingBlocks)
|
||||
@@ -72,11 +86,6 @@ void BuildButtonGrid::updateAffordability(int buildingBlocks)
|
||||
}
|
||||
}
|
||||
|
||||
void BuildButtonGrid::setDemolishModeActive(bool active)
|
||||
{
|
||||
m_demolishButton->setChecked(active);
|
||||
}
|
||||
|
||||
void BuildButtonGrid::clearActiveButton()
|
||||
{
|
||||
if (m_activeIndex >= 0 && m_activeIndex < static_cast<int>(m_buttons.size()))
|
||||
@@ -96,7 +105,8 @@ void BuildButtonGrid::onBuildButton(int index)
|
||||
if (m_activeIndex == index)
|
||||
{
|
||||
clearActiveButton();
|
||||
emit builderModeExited();
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<ExitBuilderModeRequestedEvent>());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -107,5 +117,16 @@ void BuildButtonGrid::onBuildButton(int index)
|
||||
|
||||
m_activeIndex = index;
|
||||
m_buttons[static_cast<std::size_t>(index)]->setChecked(true);
|
||||
emit buildingTypeSelected(m_types[static_cast<std::size_t>(index)]);
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<BuildingTypeSelectedEvent>(m_types[static_cast<std::size_t>(index)]));
|
||||
}
|
||||
|
||||
void BuildButtonGrid::handleEvent(std::shared_ptr<const BuilderModeExitedEvent> /*event*/)
|
||||
{
|
||||
clearActiveButton();
|
||||
}
|
||||
|
||||
void BuildButtonGrid::handleEvent(std::shared_ptr<const DemolishModeChangedEvent> event)
|
||||
{
|
||||
m_demolishButton->setChecked(event->active);
|
||||
}
|
||||
|
||||
@@ -5,28 +5,30 @@
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "BuilderModeExitedEvent.h"
|
||||
#include "BuildingType.h"
|
||||
#include "DemolishModeChangedEvent.h"
|
||||
#include "EventHandler.h"
|
||||
#include "GameConfig.h"
|
||||
|
||||
class QPushButton;
|
||||
|
||||
class BuildButtonGrid : public QWidget
|
||||
class BuildButtonGrid : public QWidget,
|
||||
public CombinedEventHandler<BuilderModeExitedEvent,
|
||||
DemolishModeChangedEvent>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
BuildButtonGrid(const GameConfig* config, QWidget* parent = nullptr);
|
||||
~BuildButtonGrid() override;
|
||||
|
||||
void updateAffordability(int buildingBlocks);
|
||||
void clearActiveButton();
|
||||
|
||||
signals:
|
||||
void buildingTypeSelected(BuildingType type);
|
||||
void builderModeExited();
|
||||
void demolishModeToggleRequested();
|
||||
|
||||
public slots:
|
||||
void setDemolishModeActive(bool active);
|
||||
private:
|
||||
void handleEvent(std::shared_ptr<const BuilderModeExitedEvent> event) override;
|
||||
void handleEvent(std::shared_ptr<const DemolishModeChangedEvent> event) override;
|
||||
|
||||
private slots:
|
||||
void onBuildButton(int index);
|
||||
|
||||
@@ -20,14 +20,17 @@
|
||||
#include "BeltSystem.h"
|
||||
#include "Building.h"
|
||||
#include "BuildingSystem.h"
|
||||
#include "DemolishModeChangedEvent.h"
|
||||
#include "EntityHitTest.h"
|
||||
#include "EntitySelectedEvent.h"
|
||||
#include "EventManager.h"
|
||||
#include "FacingComponent.h"
|
||||
#include "FactionComponent.h"
|
||||
#include "GameOverEvent.h"
|
||||
#include "HealthComponent.h"
|
||||
#include "PositionComponent.h"
|
||||
#include "ScrapSystem.h"
|
||||
#include "SelectionChangedEvent.h"
|
||||
#include "SensorRangeComponent.h"
|
||||
#include "ShipIdentityComponent.h"
|
||||
#include "ShipSystem.h"
|
||||
@@ -35,8 +38,11 @@
|
||||
#include "StationBodyComponent.h"
|
||||
#include "SurfaceMask.h"
|
||||
#include "Tick.h"
|
||||
#include "EscapeMenuRequestedEvent.h"
|
||||
#include "TracePrintRequestedEvent.h"
|
||||
#include "BossWaveUpdatedEvent.h"
|
||||
#include "BuilderModeExitedEvent.h"
|
||||
#include "BlueprintModeExitedEvent.h"
|
||||
#include "BuildingBlocksChangedEvent.h"
|
||||
#include "GameSpeedChangedEvent.h"
|
||||
#include "SchematicChoicesAvailableEvent.h"
|
||||
@@ -115,6 +121,13 @@ GameWorldView::GameWorldView(Simulation* sim, const GameConfig* config,
|
||||
connect(m_renderTimer, &QTimer::timeout, this, &GameWorldView::onFrame);
|
||||
m_renderTimer->start();
|
||||
m_frameTimer.start();
|
||||
|
||||
registerForEvents();
|
||||
}
|
||||
|
||||
GameWorldView::~GameWorldView()
|
||||
{
|
||||
unregisterForEvents();
|
||||
}
|
||||
|
||||
void GameWorldView::initializeGL()
|
||||
@@ -137,31 +150,13 @@ void GameWorldView::onFrame()
|
||||
}
|
||||
}
|
||||
|
||||
// Drain fire events → active beams
|
||||
// Emit fire events via EventManager
|
||||
{
|
||||
const std::vector<FireEvent> fires = m_sim->drainFireEvents();
|
||||
for (const FireEvent& fe : fires)
|
||||
const std::vector<WeaponFiredEvent> fires = m_sim->drainWeaponFiredEvents();
|
||||
for (const WeaponFiredEvent& fe : fires)
|
||||
{
|
||||
float maxRadius = 0.125f;
|
||||
if (m_sim->admin().isValid(fe.target)
|
||||
&& m_sim->admin().hasAll<StationBodyComponent>(fe.target))
|
||||
{
|
||||
const StationBodyComponent& sb = m_sim->admin().get<StationBodyComponent>(fe.target);
|
||||
const int shorter = std::min(sb.footprint.width(), sb.footprint.height());
|
||||
maxRadius = shorter / 2.0f;
|
||||
}
|
||||
|
||||
std::uniform_real_distribution<float> angleDist(0.0f, 6.28318530f);
|
||||
std::uniform_real_distribution<float> radiusDist(0.0f, maxRadius);
|
||||
const float angle = angleDist(m_rng);
|
||||
const float radius = radiusDist(m_rng);
|
||||
|
||||
ActiveBeam beam;
|
||||
beam.event = fe;
|
||||
beam.emittedWallMs = m_wallMs;
|
||||
beam.targetOffset = QVector2D(radius * std::cos(angle),
|
||||
radius * std::sin(angle));
|
||||
m_activeBeams.push_back(beam);
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<WeaponFiredEvent>(fe));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +227,8 @@ void GameWorldView::onFrame()
|
||||
{
|
||||
m_gameOverShown = true;
|
||||
m_gameSpeedMultiplier = 0.0;
|
||||
emit gameOver();
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<GameOverEvent>());
|
||||
}
|
||||
|
||||
update();
|
||||
@@ -1140,7 +1136,8 @@ void GameWorldView::keyPressEvent(QKeyEvent* event)
|
||||
}
|
||||
break;
|
||||
case Qt::Key_Escape:
|
||||
emit escapeMenuRequested();
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<EscapeMenuRequestedEvent>());
|
||||
break;
|
||||
case Qt::Key_Backspace:
|
||||
toggleDemolishMode();
|
||||
@@ -1227,7 +1224,8 @@ void GameWorldView::mousePressEvent(QMouseEvent* event)
|
||||
if (hitEntity != entt::null)
|
||||
{
|
||||
m_selectedBuildingIds.clear();
|
||||
emit selectionChanged(m_selectedBuildingIds);
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<SelectionChangedEvent>(m_selectedBuildingIds));
|
||||
m_selectedEntity = hitEntity;
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<EntitySelectedEvent>(hitEntity));
|
||||
@@ -1264,14 +1262,16 @@ void GameWorldView::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
m_selectedBuildingIds = { id };
|
||||
}
|
||||
emit selectionChanged(m_selectedBuildingIds);
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<SelectionChangedEvent>(m_selectedBuildingIds));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(event->modifiers() & Qt::ControlModifier))
|
||||
{
|
||||
m_selectedBuildingIds.clear();
|
||||
emit selectionChanged(m_selectedBuildingIds);
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<SelectionChangedEvent>(m_selectedBuildingIds));
|
||||
}
|
||||
m_boxSelecting = true;
|
||||
m_boxStartTile = tile;
|
||||
@@ -1370,12 +1370,13 @@ void GameWorldView::mouseReleaseEvent(QMouseEvent* event)
|
||||
if (!found) { m_selectedBuildingIds.push_back(id); }
|
||||
}
|
||||
}
|
||||
emit selectionChanged(m_selectedBuildingIds);
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<SelectionChangedEvent>(m_selectedBuildingIds));
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Slots
|
||||
// Methods (formerly slots)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void GameWorldView::toggleDemolishMode()
|
||||
@@ -1391,7 +1392,8 @@ void GameWorldView::toggleDemolishMode()
|
||||
if (m_blueprintMode.has_value()) { exitBlueprintMode(); }
|
||||
m_demolishMode = true;
|
||||
}
|
||||
emit demolishModeChanged(m_demolishMode);
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<DemolishModeChangedEvent>(m_demolishMode));
|
||||
}
|
||||
|
||||
void GameWorldView::enterBuilderMode(BuildingType type)
|
||||
@@ -1401,14 +1403,16 @@ void GameWorldView::enterBuilderMode(BuildingType type)
|
||||
m_ghostValid = false;
|
||||
m_demolishMode = false;
|
||||
m_blueprintMode.reset();
|
||||
emit demolishModeChanged(false);
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<DemolishModeChangedEvent>(false));
|
||||
}
|
||||
|
||||
void GameWorldView::enterBlueprintMode(Blueprint blueprint)
|
||||
{
|
||||
if (m_builderType.has_value()) { exitBuilderMode(); }
|
||||
m_demolishMode = false;
|
||||
emit demolishModeChanged(false);
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<DemolishModeChangedEvent>(false));
|
||||
m_blueprintGhostTile = m_ghostTile;
|
||||
m_blueprintMode = std::move(blueprint);
|
||||
}
|
||||
@@ -1416,7 +1420,8 @@ void GameWorldView::enterBlueprintMode(Blueprint blueprint)
|
||||
void GameWorldView::exitBlueprintMode()
|
||||
{
|
||||
m_blueprintMode.reset();
|
||||
emit blueprintModeExited();
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<BlueprintModeExitedEvent>());
|
||||
}
|
||||
|
||||
void GameWorldView::exitBuilderMode()
|
||||
@@ -1424,7 +1429,8 @@ void GameWorldView::exitBuilderMode()
|
||||
m_builderType.reset();
|
||||
m_beltDragTiles.clear();
|
||||
m_dragging = false;
|
||||
emit builderModeExited();
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<BuilderModeExitedEvent>());
|
||||
}
|
||||
|
||||
double GameWorldView::gameSpeed() const
|
||||
@@ -1454,7 +1460,8 @@ void GameWorldView::resetForNewGame()
|
||||
m_ghostValid = false;
|
||||
m_demolishMode = false;
|
||||
m_demolishHoverBuildingId = kInvalidBuildingId;
|
||||
emit demolishModeChanged(false);
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<DemolishModeChangedEvent>(false));
|
||||
m_selectedBuildingIds.clear();
|
||||
m_boxSelecting = false;
|
||||
m_scrollXTiles = 0.0f;
|
||||
@@ -1466,7 +1473,66 @@ void GameWorldView::resetForNewGame()
|
||||
m_lastBlocks = -1;
|
||||
m_lastBossCounter = -1;
|
||||
m_lastBossCountdown = Tick(-1);
|
||||
emit selectionChanged({});
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<SelectionChangedEvent>(std::vector<BuildingId>{}));
|
||||
setGameSpeed(1.0);
|
||||
update();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Event handlers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void GameWorldView::handleEvent(std::shared_ptr<const WeaponFiredEvent> event)
|
||||
{
|
||||
float maxRadius = 0.125f;
|
||||
if (m_sim->admin().isValid(event->target)
|
||||
&& m_sim->admin().hasAll<StationBodyComponent>(event->target))
|
||||
{
|
||||
const StationBodyComponent& sb = m_sim->admin().get<StationBodyComponent>(event->target);
|
||||
const int shorter = std::min(sb.footprint.width(), sb.footprint.height());
|
||||
maxRadius = shorter / 2.0f;
|
||||
}
|
||||
|
||||
std::uniform_real_distribution<float> angleDist(0.0f, 6.28318530f);
|
||||
std::uniform_real_distribution<float> radiusDist(0.0f, maxRadius);
|
||||
const float angle = angleDist(m_rng);
|
||||
const float radius = radiusDist(m_rng);
|
||||
|
||||
ActiveBeam beam;
|
||||
beam.event = *event;
|
||||
beam.emittedWallMs = m_wallMs;
|
||||
beam.targetOffset = QVector2D(radius * std::cos(angle),
|
||||
radius * std::sin(angle));
|
||||
m_activeBeams.push_back(beam);
|
||||
}
|
||||
|
||||
void GameWorldView::handleEvent(std::shared_ptr<const BuildingTypeSelectedEvent> event)
|
||||
{
|
||||
enterBuilderMode(event->type);
|
||||
}
|
||||
|
||||
void GameWorldView::handleEvent(std::shared_ptr<const ExitBuilderModeRequestedEvent> /*event*/)
|
||||
{
|
||||
exitBuilderMode();
|
||||
}
|
||||
|
||||
void GameWorldView::handleEvent(std::shared_ptr<const DemolishModeToggleRequestedEvent> /*event*/)
|
||||
{
|
||||
toggleDemolishMode();
|
||||
}
|
||||
|
||||
void GameWorldView::handleEvent(std::shared_ptr<const BlueprintPlacementRequestedEvent> event)
|
||||
{
|
||||
enterBlueprintMode(event->blueprint);
|
||||
}
|
||||
|
||||
void GameWorldView::handleEvent(std::shared_ptr<const ExitBlueprintModeRequestedEvent> /*event*/)
|
||||
{
|
||||
exitBlueprintMode();
|
||||
}
|
||||
|
||||
void GameWorldView::handleEvent(std::shared_ptr<const SpeedChangeRequestedEvent> event)
|
||||
{
|
||||
setGameSpeed(event->multiplier);
|
||||
}
|
||||
|
||||
@@ -13,10 +13,20 @@
|
||||
#include <QVector2D>
|
||||
|
||||
#include "Blueprint.h"
|
||||
#include "SchematicChoiceOption.h"
|
||||
#include "BlueprintModeExitedEvent.h"
|
||||
#include "BlueprintPlacementRequestedEvent.h"
|
||||
#include "BuilderModeExitedEvent.h"
|
||||
#include "BuildingType.h"
|
||||
#include "BuildingTypeSelectedEvent.h"
|
||||
#include "BuildingId.h"
|
||||
#include "FireEvent.h"
|
||||
#include "DemolishModeChangedEvent.h"
|
||||
#include "DemolishModeToggleRequestedEvent.h"
|
||||
#include "EventHandler.h"
|
||||
#include "ExitBlueprintModeRequestedEvent.h"
|
||||
#include "ExitBuilderModeRequestedEvent.h"
|
||||
#include "WeaponFiredEvent.h"
|
||||
#include "SchematicChoiceOption.h"
|
||||
#include "SpeedChangeRequestedEvent.h"
|
||||
|
||||
#include "entt/entity/entity.hpp"
|
||||
#include "EntitySelectedEvent.h"
|
||||
@@ -38,32 +48,24 @@ struct QPointCompare
|
||||
}
|
||||
};
|
||||
|
||||
class GameWorldView : public QOpenGLWidget
|
||||
class GameWorldView : public QOpenGLWidget,
|
||||
public CombinedEventHandler<WeaponFiredEvent,
|
||||
BuildingTypeSelectedEvent,
|
||||
ExitBuilderModeRequestedEvent,
|
||||
DemolishModeToggleRequestedEvent,
|
||||
BlueprintPlacementRequestedEvent,
|
||||
ExitBlueprintModeRequestedEvent,
|
||||
SpeedChangeRequestedEvent>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GameWorldView(Simulation* sim, const GameConfig* config,
|
||||
const VisualsConfig* visuals, QWidget* parent = nullptr);
|
||||
~GameWorldView() override;
|
||||
|
||||
signals:
|
||||
void selectionChanged(const std::vector<BuildingId>& ids);
|
||||
void gameOver();
|
||||
void builderModeExited();
|
||||
void blueprintModeExited();
|
||||
void escapeMenuRequested();
|
||||
void demolishModeChanged(bool active);
|
||||
|
||||
public:
|
||||
double gameSpeed() const;
|
||||
void resetFrameTimer();
|
||||
|
||||
public slots:
|
||||
void enterBuilderMode(BuildingType type);
|
||||
void exitBuilderMode();
|
||||
void enterBlueprintMode(Blueprint blueprint);
|
||||
void exitBlueprintMode();
|
||||
void toggleDemolishMode();
|
||||
void setGameSpeed(double multiplier);
|
||||
void resetForNewGame();
|
||||
|
||||
@@ -80,6 +82,14 @@ private slots:
|
||||
void onFrame();
|
||||
|
||||
private:
|
||||
void handleEvent(std::shared_ptr<const WeaponFiredEvent> event) override;
|
||||
void handleEvent(std::shared_ptr<const BuildingTypeSelectedEvent> event) override;
|
||||
void handleEvent(std::shared_ptr<const ExitBuilderModeRequestedEvent> event) override;
|
||||
void handleEvent(std::shared_ptr<const DemolishModeToggleRequestedEvent> event) override;
|
||||
void handleEvent(std::shared_ptr<const BlueprintPlacementRequestedEvent> event) override;
|
||||
void handleEvent(std::shared_ptr<const ExitBlueprintModeRequestedEvent> event) override;
|
||||
void handleEvent(std::shared_ptr<const SpeedChangeRequestedEvent> event) override;
|
||||
|
||||
void drawTiles(QPainter& painter);
|
||||
void drawBuildings(QPainter& painter);
|
||||
void drawStations(QPainter& painter);
|
||||
@@ -119,9 +129,15 @@ private:
|
||||
void stepSpeed(int delta);
|
||||
void placeAtTile(QPoint tile);
|
||||
|
||||
void enterBuilderMode(BuildingType type);
|
||||
void exitBuilderMode();
|
||||
void enterBlueprintMode(Blueprint blueprint);
|
||||
void exitBlueprintMode();
|
||||
void toggleDemolishMode();
|
||||
|
||||
struct ActiveBeam
|
||||
{
|
||||
FireEvent event;
|
||||
WeaponFiredEvent event;
|
||||
qint64 emittedWallMs;
|
||||
QVector2D targetOffset;
|
||||
};
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <QPushButton>
|
||||
#include <QSignalMapper>
|
||||
|
||||
#include "EventManager.h"
|
||||
#include "SpeedChangeRequestedEvent.h"
|
||||
#include "Tick.h"
|
||||
|
||||
const double HeaderBar::kSpeeds[] = { 0.0, 0.5, 1.0, 2.0, 10.0 };
|
||||
@@ -90,6 +92,7 @@ void HeaderBar::onSpeedButton(int index)
|
||||
{
|
||||
if (index >= 0 && index < kSpeedCount)
|
||||
{
|
||||
emit speedChanged(kSpeeds[index]);
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<SpeedChangeRequestedEvent>(kSpeeds[index]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,9 +26,6 @@ public:
|
||||
explicit HeaderBar(QWidget* parent = nullptr);
|
||||
~HeaderBar() override;
|
||||
|
||||
signals:
|
||||
void speedChanged(double multiplier);
|
||||
|
||||
private slots:
|
||||
void onSpeedButton(int index);
|
||||
|
||||
|
||||
@@ -53,52 +53,6 @@ MainWindow::MainWindow(Simulation* sim, const std::string& configDir, QWidget* p
|
||||
bottomLayout->addWidget(m_buildButtonGrid, 1);
|
||||
bottomLayout->addWidget(m_blueprintPanel, 1);
|
||||
|
||||
// Signals: game world → other panels
|
||||
connect(m_gameWorldView, &GameWorldView::selectionChanged,
|
||||
m_selectedBuildingPanel, &SelectedBuildingPanel::onSelectionChanged);
|
||||
|
||||
connect(m_gameWorldView, &GameWorldView::gameOver,
|
||||
this, &MainWindow::onGameOver);
|
||||
|
||||
connect(m_gameWorldView, &GameWorldView::escapeMenuRequested,
|
||||
this, &MainWindow::onEscapeMenuRequested);
|
||||
|
||||
connect(m_selectedBuildingPanel, &SelectedBuildingPanel::layoutDialogRequested,
|
||||
this, &MainWindow::onLayoutDialogRequested);
|
||||
|
||||
// Signals: build grid → game world
|
||||
connect(m_buildButtonGrid, &BuildButtonGrid::buildingTypeSelected,
|
||||
m_gameWorldView, &GameWorldView::enterBuilderMode);
|
||||
|
||||
connect(m_buildButtonGrid, &BuildButtonGrid::builderModeExited,
|
||||
m_gameWorldView, &GameWorldView::exitBuilderMode);
|
||||
|
||||
connect(m_gameWorldView, &GameWorldView::builderModeExited,
|
||||
m_buildButtonGrid, &BuildButtonGrid::clearActiveButton);
|
||||
|
||||
connect(m_buildButtonGrid, &BuildButtonGrid::demolishModeToggleRequested,
|
||||
m_gameWorldView, &GameWorldView::toggleDemolishMode);
|
||||
|
||||
connect(m_gameWorldView, &GameWorldView::demolishModeChanged,
|
||||
m_buildButtonGrid, &BuildButtonGrid::setDemolishModeActive);
|
||||
|
||||
// Signals: blueprint panel ↔ game world
|
||||
connect(m_gameWorldView, &GameWorldView::selectionChanged,
|
||||
m_blueprintPanel, &BlueprintPanel::onSelectionChanged);
|
||||
|
||||
connect(m_blueprintPanel, &BlueprintPanel::blueprintPlacementRequested,
|
||||
m_gameWorldView, &GameWorldView::enterBlueprintMode);
|
||||
|
||||
connect(m_blueprintPanel, &BlueprintPanel::exitBlueprintModeRequested,
|
||||
m_gameWorldView, &GameWorldView::exitBlueprintMode);
|
||||
|
||||
connect(m_gameWorldView, &GameWorldView::blueprintModeExited,
|
||||
m_blueprintPanel, &BlueprintPanel::clearActiveBlueprintButton);
|
||||
|
||||
// Signals: header bar → game world
|
||||
connect(m_headerBar, &HeaderBar::speedChanged,
|
||||
m_gameWorldView, &GameWorldView::setGameSpeed);
|
||||
|
||||
m_gameWorldView->setFocus();
|
||||
|
||||
connect(qApp, &QApplication::focusChanged, this, [this](QWidget*, QWidget* newWidget) {
|
||||
@@ -191,7 +145,7 @@ void MainWindow::handleEvent(std::shared_ptr<const SchematicChoicesAvailableEven
|
||||
m_gameWorldView->resetFrameTimer();
|
||||
}
|
||||
|
||||
void MainWindow::onEscapeMenuRequested()
|
||||
void MainWindow::handleEvent(std::shared_ptr<const EscapeMenuRequestedEvent> /*event*/)
|
||||
{
|
||||
const double prevSpeed = m_gameWorldView->gameSpeed();
|
||||
m_gameWorldView->setGameSpeed(0.0);
|
||||
@@ -235,12 +189,12 @@ void MainWindow::onEscapeMenuRequested()
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onLayoutDialogRequested(BuildingId shipyardId)
|
||||
void MainWindow::handleEvent(std::shared_ptr<const LayoutDialogRequestedEvent> event)
|
||||
{
|
||||
const double prevSpeed = m_gameWorldView->gameSpeed();
|
||||
m_gameWorldView->setGameSpeed(0.0);
|
||||
|
||||
const Building* b = m_sim->buildings().findBuilding(shipyardId);
|
||||
const Building* b = m_sim->buildings().findBuilding(event->shipyardId);
|
||||
if (!b)
|
||||
{
|
||||
m_gameWorldView->setGameSpeed(prevSpeed);
|
||||
@@ -272,14 +226,14 @@ void MainWindow::onLayoutDialogRequested(BuildingId shipyardId)
|
||||
this);
|
||||
if (dialog.exec() == QDialog::Accepted && dialog.result().has_value())
|
||||
{
|
||||
m_sim->buildings().setShipLayout(shipyardId, *dialog.result());
|
||||
m_sim->buildings().setShipLayout(event->shipyardId, *dialog.result());
|
||||
}
|
||||
|
||||
m_gameWorldView->setGameSpeed(prevSpeed);
|
||||
m_gameWorldView->resetFrameTimer();
|
||||
}
|
||||
|
||||
void MainWindow::onGameOver()
|
||||
void MainWindow::handleEvent(std::shared_ptr<const GameOverEvent> /*event*/)
|
||||
{
|
||||
const Tick tick = m_sim->currentTick();
|
||||
const int totalSeconds = static_cast<int>(ticksToSeconds(tick));
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
|
||||
#include "BuildingBlocksChangedEvent.h"
|
||||
#include "BuildingId.h"
|
||||
#include "EscapeMenuRequestedEvent.h"
|
||||
#include "EventHandler.h"
|
||||
#include "GameOverEvent.h"
|
||||
#include "LayoutDialogRequestedEvent.h"
|
||||
#include "SchematicChoicesAvailableEvent.h"
|
||||
#include "ShipLayoutBlueprint.h"
|
||||
#include "Tick.h"
|
||||
@@ -24,7 +27,10 @@ class QResizeEvent;
|
||||
|
||||
class MainWindow : public QWidget,
|
||||
public CombinedEventHandler<BuildingBlocksChangedEvent,
|
||||
SchematicChoicesAvailableEvent>
|
||||
SchematicChoicesAvailableEvent,
|
||||
GameOverEvent,
|
||||
EscapeMenuRequestedEvent,
|
||||
LayoutDialogRequestedEvent>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -39,13 +45,11 @@ protected:
|
||||
private:
|
||||
void handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event) override;
|
||||
void handleEvent(std::shared_ptr<const SchematicChoicesAvailableEvent> event) override;
|
||||
void handleEvent(std::shared_ptr<const GameOverEvent> event) override;
|
||||
void handleEvent(std::shared_ptr<const EscapeMenuRequestedEvent> event) override;
|
||||
void handleEvent(std::shared_ptr<const LayoutDialogRequestedEvent> event) override;
|
||||
void layoutPanels();
|
||||
|
||||
private slots:
|
||||
void onGameOver();
|
||||
void onEscapeMenuRequested();
|
||||
void onLayoutDialogRequested(BuildingId shipyardId);
|
||||
|
||||
private:
|
||||
std::string m_configDir;
|
||||
VisualsConfig m_visuals;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "DynamicBodyComponent.h"
|
||||
#include "EntityAdmin.h"
|
||||
#include "EntitySelectedEvent.h"
|
||||
#include "EventManager.h"
|
||||
#include "FactionComponent.h"
|
||||
#include "HealthComponent.h"
|
||||
#include "ModuleOwnerComponent.h"
|
||||
@@ -28,6 +29,7 @@
|
||||
#include "BuildingSystem.h"
|
||||
#include "BuildingType.h"
|
||||
#include "ItemType.h"
|
||||
#include "LayoutDialogRequestedEvent.h"
|
||||
#include "ModulesConfig.h"
|
||||
#include "Rotation.h"
|
||||
#include "ShipLayoutPreview.h"
|
||||
@@ -139,7 +141,8 @@ SelectedBuildingPanel::SelectedBuildingPanel(Simulation* sim,
|
||||
connect(m_configureLayoutBtn, &QPushButton::clicked, this, [this]() {
|
||||
if (m_singleBuildingId != kInvalidBuildingId)
|
||||
{
|
||||
emit layoutDialogRequested(m_singleBuildingId);
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<LayoutDialogRequestedEvent>(m_singleBuildingId));
|
||||
}
|
||||
});
|
||||
connect(m_filterAList, &QListWidget::itemChanged,
|
||||
@@ -861,3 +864,8 @@ void SelectedBuildingPanel::clearEntityDisplay()
|
||||
m_entityStatsPanel->hide();
|
||||
m_stationStatsLabel->hide();
|
||||
}
|
||||
|
||||
void SelectedBuildingPanel::handleEvent(std::shared_ptr<const SelectionChangedEvent> event)
|
||||
{
|
||||
onSelectionChanged(event->ids);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "EventHandler.h"
|
||||
#include "GameConfig.h"
|
||||
#include "RecipesConfig.h"
|
||||
#include "SelectionChangedEvent.h"
|
||||
#include "ShipLayout.h"
|
||||
#include "ShipsConfig.h"
|
||||
#include "Tick.h"
|
||||
@@ -30,7 +31,9 @@ class QPushButton;
|
||||
class QVBoxLayout;
|
||||
|
||||
class SelectedBuildingPanel : public QWidget,
|
||||
public CombinedEventHandler<TickAdvancedEvent, EntitySelectedEvent>
|
||||
public CombinedEventHandler<TickAdvancedEvent,
|
||||
EntitySelectedEvent,
|
||||
SelectionChangedEvent>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -39,15 +42,10 @@ public:
|
||||
QWidget* parent = nullptr);
|
||||
~SelectedBuildingPanel() override;
|
||||
|
||||
signals:
|
||||
void layoutDialogRequested(BuildingId shipyardId);
|
||||
|
||||
public slots:
|
||||
void onSelectionChanged(const std::vector<BuildingId>& ids);
|
||||
|
||||
private:
|
||||
void handleEvent(std::shared_ptr<const TickAdvancedEvent> event) override;
|
||||
void handleEvent(std::shared_ptr<const EntitySelectedEvent> event) override;
|
||||
void handleEvent(std::shared_ptr<const SelectionChangedEvent> event) override;
|
||||
|
||||
private slots:
|
||||
void onRecipeChanged(int comboIndex);
|
||||
@@ -55,6 +53,7 @@ private slots:
|
||||
void onSplitterFilterChanged();
|
||||
|
||||
private:
|
||||
void onSelectionChanged(const std::vector<BuildingId>& ids);
|
||||
void rebuild();
|
||||
void clearContent();
|
||||
void buildEmpty();
|
||||
|
||||
Reference in New Issue
Block a user