瀏覽代碼

Add configurable max population for barracks per map

Co-authored-by: djeada <[email protected]>
copilot-swe-agent[bot] 2 月之前
父節點
當前提交
dc3fe57e40

+ 23 - 30
app/core/game_engine.cpp

@@ -21,12 +21,12 @@
 #include "game/core/event_manager.h"
 #include "game/core/world.h"
 #include "game/game_config.h"
+#include "game/map/environment.h"
 #include "game/map/level_loader.h"
 #include "game/map/map_catalog.h"
 #include "game/map/map_loader.h"
 #include "game/map/map_transformer.h"
 #include "game/map/skirmish_loader.h"
-#include "game/map/environment.h"
 #include "game/map/terrain_service.h"
 #include "game/map/visibility_service.h"
 #include "game/map/world_bootstrap.h"
@@ -83,8 +83,7 @@ QJsonArray vec3ToJsonArray(const QVector3D &vec) {
   return arr;
 }
 
-QVector3D jsonArrayToVec3(const QJsonValue &value,
-                          const QVector3D &fallback) {
+QVector3D jsonArrayToVec3(const QJsonValue &value, const QVector3D &fallback) {
   if (!value.isArray()) {
     return fallback;
   }
@@ -1055,9 +1054,7 @@ QVariantList GameEngine::getSaveSlots() const {
   return m_saveLoadService->getSaveSlots();
 }
 
-void GameEngine::refreshSaveSlots() {
-  emit saveSlotsChanged();
-}
+void GameEngine::refreshSaveSlots() { emit saveSlotsChanged(); }
 
 bool GameEngine::deleteSaveSlot(const QString &slotName) {
   if (!m_saveLoadService) {
@@ -1066,7 +1063,7 @@ bool GameEngine::deleteSaveSlot(const QString &slotName) {
   }
 
   bool success = m_saveLoadService->deleteSaveSlot(slotName);
-  
+
   if (!success) {
     QString error = m_saveLoadService->getLastError();
     qWarning() << "Failed to delete save slot:" << error;
@@ -1074,7 +1071,7 @@ bool GameEngine::deleteSaveSlot(const QString &slotName) {
   } else {
     emit saveSlotsChanged();
   }
-  
+
   return success;
 }
 
@@ -1324,8 +1321,8 @@ void GameEngine::applyEnvironmentFromMetadata(const QJsonObject &metadata) {
     return;
 
   if (metadata.contains("localOwnerId")) {
-    m_runtime.localOwnerId = metadata.value("localOwnerId")
-                                 .toInt(m_runtime.localOwnerId);
+    m_runtime.localOwnerId =
+        metadata.value("localOwnerId").toInt(m_runtime.localOwnerId);
   }
 
   const QString mapPath = metadata.value("mapPath").toString();
@@ -1342,8 +1339,8 @@ void GameEngine::applyEnvironmentFromMetadata(const QJsonObject &metadata) {
         metadata.value("playerUnitId").toVariant().toULongLong());
   }
 
-  int maxTroops = metadata.value("maxTroopsPerPlayer")
-                      .toInt(m_level.maxTroopsPerPlayer);
+  int maxTroops =
+      metadata.value("maxTroopsPerPlayer").toInt(m_level.maxTroopsPerPlayer);
   if (maxTroops <= 0) {
     maxTroops = Game::GameConfig::instance().getMaxTroopsPerPlayer();
   }
@@ -1404,8 +1401,7 @@ void GameEngine::applyEnvironmentFromMetadata(const QJsonObject &metadata) {
       }
     }
 
-    Game::Systems::CommandService::initialize(def.grid.width,
-                                              def.grid.height);
+    Game::Systems::CommandService::initialize(def.grid.width, def.grid.height);
 
     auto &visibilityService = Game::Map::VisibilityService::instance();
     visibilityService.initialize(def.grid.width, def.grid.height,
@@ -1413,10 +1409,9 @@ void GameEngine::applyEnvironmentFromMetadata(const QJsonObject &metadata) {
     visibilityService.computeImmediate(*m_world, m_runtime.localOwnerId);
 
     if (m_fog && visibilityService.isInitialized()) {
-      m_fog->updateMask(visibilityService.getWidth(),
-                        visibilityService.getHeight(),
-                        visibilityService.getTileSize(),
-                        visibilityService.snapshotCells());
+      m_fog->updateMask(
+          visibilityService.getWidth(), visibilityService.getHeight(),
+          visibilityService.getTileSize(), visibilityService.snapshotCells());
     }
 
     m_runtime.visibilityVersion = visibilityService.version();
@@ -1446,10 +1441,9 @@ void GameEngine::applyEnvironmentFromMetadata(const QJsonObject &metadata) {
                                  fallbackTileSize);
     visibilityService.computeImmediate(*m_world, m_runtime.localOwnerId);
     if (m_fog && visibilityService.isInitialized()) {
-      m_fog->updateMask(visibilityService.getWidth(),
-                        visibilityService.getHeight(),
-                        visibilityService.getTileSize(),
-                        visibilityService.snapshotCells());
+      m_fog->updateMask(
+          visibilityService.getWidth(), visibilityService.getHeight(),
+          visibilityService.getTileSize(), visibilityService.snapshotCells());
     }
     m_runtime.visibilityVersion = visibilityService.version();
     m_runtime.visibilityUpdateAccumulator = 0.0f;
@@ -1465,15 +1459,14 @@ void GameEngine::applyEnvironmentFromMetadata(const QJsonObject &metadata) {
 
     const float nearPlane = static_cast<float>(
         cameraObj.value("near").toDouble(m_camera->getNear()));
-    const float farPlane = static_cast<float>(
-        cameraObj.value("far").toDouble(m_camera->getFar()));
-    const float fov = static_cast<float>(
-        cameraObj.value("fov").toDouble(m_camera->getFOV()));
+    const float farPlane =
+        static_cast<float>(cameraObj.value("far").toDouble(m_camera->getFar()));
+    const float fov =
+        static_cast<float>(cameraObj.value("fov").toDouble(m_camera->getFOV()));
 
     float aspect = m_camera->getAspect();
     if (m_viewport.height > 0) {
-      aspect = float(m_viewport.width) /
-               float(std::max(1, m_viewport.height));
+      aspect = float(m_viewport.width) / float(std::max(1, m_viewport.height));
     }
     m_camera->setPerspective(fov, aspect, nearPlane, farPlane);
   }
@@ -1533,8 +1526,8 @@ QByteArray GameEngine::captureSaveScreenshot() const {
   }
 
   const QSize targetSize(320, 180);
-  QImage scaled = image.scaled(targetSize, Qt::KeepAspectRatio,
-                               Qt::SmoothTransformation);
+  QImage scaled =
+      image.scaled(targetSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
 
   QByteArray buffer;
   QBuffer qBuffer(&buffer);

+ 3 - 3
assets/maps/test_map.json

@@ -33,7 +33,7 @@
     "far": 400.0
   },
   "spawns": [
-    { "type": "barracks", "x": 150, "z": 120, "playerId": 1 },
+    { "type": "barracks", "x": 150, "z": 120, "playerId": 1, "maxPopulation": 150 },
     { "type": "archer", "x": 148, "z": 122, "playerId": 1 },
     { "type": "archer", "x": 152, "z": 118, "playerId": 1 },
     { "type": "archer", "x": 152, "z": 122, "playerId": 1 },
@@ -43,14 +43,14 @@
     { "type": "archer", "x": 146, "z": 120, "playerId": 1 },
     { "type": "archer", "x": 154, "z": 120, "playerId": 1 },
 
-    { "type": "barracks", "x": 125, "z": 175, "playerId": 2 },
+    { "type": "barracks", "x": 125, "z": 175, "playerId": 2, "maxPopulation": 75 },
     { "type": "archer", "x": 123, "z": 177, "playerId": 2 },
     { "type": "archer", "x": 127, "z": 173, "playerId": 2 },
     { "type": "archer", "x": 127, "z": 177, "playerId": 2 },
     { "type": "archer", "x": 123, "z": 173, "playerId": 2 },
     { "type": "archer", "x": 129, "z": 175, "playerId": 2 },
 
-    { "type": "barracks", "x": 175, "z": 175, "playerId": 3 },
+    { "type": "barracks", "x": 175, "z": 175, "playerId": 3, "maxPopulation": 200 },
     { "type": "archer", "x": 173, "z": 177, "playerId": 3 },
     { "type": "archer", "x": 177, "z": 173, "playerId": 3 },
     { "type": "archer", "x": 175, "z": 171, "playerId": 3 },

+ 34 - 25
game/core/serialization.cpp

@@ -145,10 +145,10 @@ QJsonObject Serialization::serializeEntity(const Entity *entity) {
     entityObj["attack"] = attackObj;
   }
 
-  if (const auto *attackTarget = entity->getComponent<AttackTargetComponent>()) {
+  if (const auto *attackTarget =
+          entity->getComponent<AttackTargetComponent>()) {
     QJsonObject attackTargetObj;
-    attackTargetObj["targetId"] =
-        static_cast<qint64>(attackTarget->targetId);
+    attackTargetObj["targetId"] = static_cast<qint64>(attackTarget->targetId);
     attackTargetObj["shouldChase"] = attackTarget->shouldChase;
     entityObj["attackTarget"] = attackTargetObj;
   }
@@ -216,7 +216,8 @@ void Serialization::deserializeEntity(Entity *entity, const QJsonObject &json) {
     transform->scale.y = static_cast<float>(transformObj["scaleY"].toDouble());
     transform->scale.z = static_cast<float>(transformObj["scaleZ"].toDouble());
     transform->hasDesiredYaw = transformObj["hasDesiredYaw"].toBool(false);
-    transform->desiredYaw = static_cast<float>(transformObj["desiredYaw"].toDouble());
+    transform->desiredYaw =
+        static_cast<float>(transformObj["desiredYaw"].toDouble());
   }
 
   if (json.contains("renderable")) {
@@ -226,8 +227,9 @@ void Serialization::deserializeEntity(Entity *entity, const QJsonObject &json) {
     renderable->texturePath =
         renderableObj["texturePath"].toString().toStdString();
     renderable->visible = renderableObj["visible"].toBool(true);
-    renderable->mesh = static_cast<RenderableComponent::MeshKind>(
-        renderableObj["mesh"].toInt(static_cast<int>(RenderableComponent::MeshKind::Cube)));
+    renderable->mesh =
+        static_cast<RenderableComponent::MeshKind>(renderableObj["mesh"].toInt(
+            static_cast<int>(RenderableComponent::MeshKind::Cube)));
     if (renderableObj.contains("color")) {
       deserializeColor(renderableObj["color"].toArray(), renderable->color);
     }
@@ -239,7 +241,8 @@ void Serialization::deserializeEntity(Entity *entity, const QJsonObject &json) {
     unit->health = unitObj["health"].toInt(100);
     unit->maxHealth = unitObj["maxHealth"].toInt(100);
     unit->speed = static_cast<float>(unitObj["speed"].toDouble());
-    unit->visionRange = static_cast<float>(unitObj["visionRange"].toDouble(12.0));
+    unit->visionRange =
+        static_cast<float>(unitObj["visionRange"].toDouble(12.0));
     unit->unitType = unitObj["unitType"].toString().toStdString();
     unit->ownerId = unitObj["ownerId"].toInt(0);
   }
@@ -257,11 +260,14 @@ void Serialization::deserializeEntity(Entity *entity, const QJsonObject &json) {
     movement->pathPending = movementObj["pathPending"].toBool(false);
     movement->pendingRequestId = static_cast<std::uint64_t>(
         movementObj["pendingRequestId"].toVariant().toULongLong());
-    movement->repathCooldown = static_cast<float>(movementObj["repathCooldown"].toDouble());
-    movement->lastGoalX = static_cast<float>(movementObj["lastGoalX"].toDouble());
-    movement->lastGoalY = static_cast<float>(movementObj["lastGoalY"].toDouble());
-    movement->timeSinceLastPathRequest = static_cast<float>(
-        movementObj["timeSinceLastPathRequest"].toDouble());
+    movement->repathCooldown =
+        static_cast<float>(movementObj["repathCooldown"].toDouble());
+    movement->lastGoalX =
+        static_cast<float>(movementObj["lastGoalX"].toDouble());
+    movement->lastGoalY =
+        static_cast<float>(movementObj["lastGoalY"].toDouble());
+    movement->timeSinceLastPathRequest =
+        static_cast<float>(movementObj["timeSinceLastPathRequest"].toDouble());
 
     movement->path.clear();
     const auto pathArray = movementObj["path"].toArray();
@@ -280,10 +286,13 @@ void Serialization::deserializeEntity(Entity *entity, const QJsonObject &json) {
     attack->range = static_cast<float>(attackObj["range"].toDouble());
     attack->damage = attackObj["damage"].toInt(0);
     attack->cooldown = static_cast<float>(attackObj["cooldown"].toDouble());
-    attack->timeSinceLast = static_cast<float>(attackObj["timeSinceLast"].toDouble());
-    attack->meleeRange = static_cast<float>(attackObj["meleeRange"].toDouble(1.5));
+    attack->timeSinceLast =
+        static_cast<float>(attackObj["timeSinceLast"].toDouble());
+    attack->meleeRange =
+        static_cast<float>(attackObj["meleeRange"].toDouble(1.5));
     attack->meleeDamage = attackObj["meleeDamage"].toInt(0);
-    attack->meleeCooldown = static_cast<float>(attackObj["meleeCooldown"].toDouble());
+    attack->meleeCooldown =
+        static_cast<float>(attackObj["meleeCooldown"].toDouble());
     attack->preferredMode =
         combatModeFromString(attackObj["preferredMode"].toString());
     attack->currentMode =
@@ -308,8 +317,8 @@ void Serialization::deserializeEntity(Entity *entity, const QJsonObject &json) {
   if (json.contains("patrol")) {
     const auto patrolObj = json["patrol"].toObject();
     auto patrol = entity->addComponent<PatrolComponent>();
-    patrol->currentWaypoint = static_cast<size_t>(
-        std::max(0, patrolObj["currentWaypoint"].toInt()));
+    patrol->currentWaypoint =
+        static_cast<size_t>(std::max(0, patrolObj["currentWaypoint"].toInt()));
     patrol->patrolling = patrolObj["patrolling"].toBool(false);
 
     patrol->waypoints.clear();
@@ -331,8 +340,10 @@ void Serialization::deserializeEntity(Entity *entity, const QJsonObject &json) {
     const auto productionObj = json["production"].toObject();
     auto production = entity->addComponent<ProductionComponent>();
     production->inProgress = productionObj["inProgress"].toBool(false);
-    production->buildTime = static_cast<float>(productionObj["buildTime"].toDouble());
-    production->timeRemaining = static_cast<float>(productionObj["timeRemaining"].toDouble());
+    production->buildTime =
+        static_cast<float>(productionObj["buildTime"].toDouble());
+    production->timeRemaining =
+        static_cast<float>(productionObj["timeRemaining"].toDouble());
     production->producedCount = productionObj["producedCount"].toInt(0);
     production->maxUnits = productionObj["maxUnits"].toInt(0);
     production->productType =
@@ -366,11 +377,9 @@ QJsonDocument Serialization::serializeWorld(const World *world) {
   }
 
   worldObj["entities"] = entitiesArray;
-  worldObj["nextEntityId"] =
-      static_cast<qint64>(world->getNextEntityId());
+  worldObj["nextEntityId"] = static_cast<qint64>(world->getNextEntityId());
   worldObj["schemaVersion"] = 1;
-  worldObj["ownerRegistry"] =
-      Game::Systems::OwnerRegistry::instance().toJson();
+  worldObj["ownerRegistry"] = Game::Systems::OwnerRegistry::instance().toJson();
 
   return QJsonDocument(worldObj);
 }
@@ -380,8 +389,8 @@ void Serialization::deserializeWorld(World *world, const QJsonDocument &doc) {
   auto entitiesArray = worldObj["entities"].toArray();
   for (const auto &value : entitiesArray) {
     auto entityObj = value.toObject();
-    const auto entityId = static_cast<EntityID>(
-        entityObj["id"].toVariant().toULongLong());
+    const auto entityId =
+        static_cast<EntityID>(entityObj["id"].toVariant().toULongLong());
     auto entity = entityId == NULL_ENTITY ? world->createEntity()
                                           : world->createEntityWithId(entityId);
     if (entity) {

+ 2 - 2
game/core/world.h

@@ -49,8 +49,8 @@ public:
   std::vector<Entity *> getEnemyUnits(int ownerId) const;
   int countTroopsForPlayer(int ownerId) const;
 
-  // For serialization purposes
-  const std::unordered_map<EntityID, std::unique_ptr<Entity>> &getEntities() const {
+  const std::unordered_map<EntityID, std::unique_ptr<Entity>> &
+  getEntities() const {
     return m_entities;
   }
 

+ 1 - 0
game/map/map_definition.h

@@ -31,6 +31,7 @@ struct UnitSpawn {
   float z = 0.0f;
   int playerId = 0;
   int teamId = 0;
+  int maxPopulation = 100;
 };
 
 enum class CoordSystem { Grid, World };

+ 1 - 0
game/map/map_loader.cpp

@@ -189,6 +189,7 @@ static void readSpawns(const QJsonArray &arr, std::vector<UnitSpawn> &out) {
     s.z = float(o.value("z").toDouble(0.0));
     s.playerId = o.value("playerId").toInt(0);
     s.teamId = o.value("teamId").toInt(0);
+    s.maxPopulation = o.value("maxPopulation").toInt(100);
     out.push_back(s);
   }
 }

+ 1 - 0
game/map/map_transformer.cpp

@@ -142,6 +142,7 @@ MapTransformer::applyToWorld(const MapDefinition &def,
       sp.unitType = s.type.toStdString();
       sp.aiControlled =
           !Game::Systems::OwnerRegistry::instance().isPlayer(s.playerId);
+      sp.maxPopulation = s.maxPopulation;
       auto obj = s_registry->create(s.type.toStdString(), world, sp);
       if (obj) {
         e = world.getEntity(obj->id());

+ 8 - 15
game/systems/save_load_service.cpp

@@ -30,8 +30,8 @@ SaveLoadService::SaveLoadService() {
 SaveLoadService::~SaveLoadService() = default;
 
 QString SaveLoadService::getSavesDirectory() const {
-  QString savesPath = QStandardPaths::writableLocation(
-      QStandardPaths::AppDataLocation);
+  QString savesPath =
+      QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
   return savesPath + "/saves";
 }
 
@@ -64,14 +64,13 @@ bool SaveLoadService::saveGameToSlot(Engine::Core::World &world,
 
     QJsonDocument worldDoc =
         Engine::Core::Serialization::serializeWorld(&world);
-    const QByteArray worldBytes =
-        worldDoc.toJson(QJsonDocument::Compact);
+    const QByteArray worldBytes = worldDoc.toJson(QJsonDocument::Compact);
 
     QJsonObject combinedMetadata = metadata;
     combinedMetadata["slotName"] = slotName;
     combinedMetadata["title"] = title;
-    combinedMetadata["timestamp"] = QDateTime::currentDateTimeUtc().toString(
-        Qt::ISODateWithMs);
+    combinedMetadata["timestamp"] =
+        QDateTime::currentDateTimeUtc().toString(Qt::ISODateWithMs);
     if (!combinedMetadata.contains("mapName")) {
       combinedMetadata["mapName"] =
           mapName.isEmpty() ? QStringLiteral("Unknown Map") : mapName;
@@ -124,8 +123,7 @@ bool SaveLoadService::loadGameFromSlot(Engine::Core::World &world,
     }
 
     QJsonParseError parseError{};
-    QJsonDocument doc =
-        QJsonDocument::fromJson(worldBytes, &parseError);
+    QJsonDocument doc = QJsonDocument::fromJson(worldBytes, &parseError);
     if (parseError.error != QJsonParseError::NoError || doc.isNull()) {
       m_lastError = QStringLiteral("Corrupted save data for slot '%1': %2")
                         .arg(slotName, parseError.errorString());
@@ -185,16 +183,11 @@ bool SaveLoadService::deleteSaveSlot(const QString &slotName) {
   return true;
 }
 
-void SaveLoadService::openSettings() {
-  qInfo() << "Open settings requested";
-  // TODO: Implement settings dialog/menu integration
-  // This could trigger a signal or callback to open the settings UI
-}
+void SaveLoadService::openSettings() { qInfo() << "Open settings requested"; }
 
 void SaveLoadService::exitGame() {
   qInfo() << "Exit game requested";
-  // Perform any cleanup before exit if needed
-  // Then quit the application
+
   QCoreApplication::quit();
 }
 

+ 1 - 9
game/systems/save_load_service.h

@@ -2,8 +2,8 @@
 
 #include <QByteArray>
 #include <QJsonObject>
-#include <QVariantList>
 #include <QString>
+#include <QVariantList>
 
 #include <memory>
 
@@ -23,35 +23,27 @@ public:
   SaveLoadService();
   ~SaveLoadService();
 
-  // Save game to named slot with metadata
   bool saveGameToSlot(Engine::Core::World &world, const QString &slotName,
                       const QString &title, const QString &mapName,
                       const QJsonObject &metadata = {},
                       const QByteArray &screenshot = QByteArray());
 
-  // Load game from named slot
   bool loadGameFromSlot(Engine::Core::World &world, const QString &slotName);
 
-  // Get list of all save slots with metadata
   QVariantList getSaveSlots() const;
 
-  // Delete a save slot
   bool deleteSaveSlot(const QString &slotName);
 
-  // Get the last error message
   QString getLastError() const { return m_lastError; }
 
-  // Clear the last error
   void clearError() { m_lastError.clear(); }
 
   QJsonObject getLastMetadata() const { return m_lastMetadata; }
   QString getLastTitle() const { return m_lastTitle; }
   QByteArray getLastScreenshot() const { return m_lastScreenshot; }
 
-  // Settings-related functionality
   void openSettings();
 
-  // Exit game functionality
   void exitGame();
 
 private:

+ 46 - 48
game/systems/save_storage.cpp

@@ -17,8 +17,8 @@ constexpr const char *kDriverName = "QSQLITE";
 constexpr int kCurrentSchemaVersion = 1;
 
 QString buildConnectionName(const SaveStorage *instance) {
-  return QStringLiteral("SaveStorage_%1").arg(
-      reinterpret_cast<quintptr>(instance), /*fieldWidth=*/0, /*base=*/16);
+  return QStringLiteral("SaveStorage_%1")
+      .arg(reinterpret_cast<quintptr>(instance), 0, 16);
 }
 
 QString lastErrorString(const QSqlError &error) {
@@ -109,8 +109,7 @@ bool SaveStorage::initialize(QString *outError) {
 bool SaveStorage::saveSlot(const QString &slotName, const QString &title,
                            const QJsonObject &metadata,
                            const QByteArray &worldState,
-                           const QByteArray &screenshot,
-                           QString *outError) {
+                           const QByteArray &screenshot, QString *outError) {
   if (!initialize(outError)) {
     return false;
   }
@@ -121,25 +120,24 @@ bool SaveStorage::saveSlot(const QString &slotName, const QString &title,
   }
 
   QSqlQuery query(m_database);
-  const QString insertSql =
-      QStringLiteral(
-          "INSERT INTO saves (slot_name, title, map_name, timestamp, "
-          "metadata, world_state, screenshot, created_at, updated_at) "
-          "VALUES (:slot_name, :title, :map_name, :timestamp, :metadata, "
-          ":world_state, :screenshot, :created_at, :updated_at) "
-          "ON CONFLICT(slot_name) DO UPDATE SET "
-          "title = excluded.title, "
-          "map_name = excluded.map_name, "
-          "timestamp = excluded.timestamp, "
-          "metadata = excluded.metadata, "
-          "world_state = excluded.world_state, "
-          "screenshot = excluded.screenshot, "
-          "updated_at = excluded.updated_at");
+  const QString insertSql = QStringLiteral(
+      "INSERT INTO saves (slot_name, title, map_name, timestamp, "
+      "metadata, world_state, screenshot, created_at, updated_at) "
+      "VALUES (:slot_name, :title, :map_name, :timestamp, :metadata, "
+      ":world_state, :screenshot, :created_at, :updated_at) "
+      "ON CONFLICT(slot_name) DO UPDATE SET "
+      "title = excluded.title, "
+      "map_name = excluded.map_name, "
+      "timestamp = excluded.timestamp, "
+      "metadata = excluded.metadata, "
+      "world_state = excluded.world_state, "
+      "screenshot = excluded.screenshot, "
+      "updated_at = excluded.updated_at");
 
   if (!query.prepare(insertSql)) {
     if (outError) {
       *outError = QStringLiteral("Failed to prepare save query: %1")
-                       .arg(lastErrorString(query.lastError()));
+                      .arg(lastErrorString(query.lastError()));
     }
     return false;
   }
@@ -171,7 +169,7 @@ bool SaveStorage::saveSlot(const QString &slotName, const QString &title,
   if (!query.exec()) {
     if (outError) {
       *outError = QStringLiteral("Failed to persist save slot: %1")
-                       .arg(lastErrorString(query.lastError()));
+                      .arg(lastErrorString(query.lastError()));
     }
     transaction.rollback();
     return false;
@@ -200,7 +198,7 @@ bool SaveStorage::loadSlot(const QString &slotName, QByteArray &worldState,
   if (!query.exec()) {
     if (outError) {
       *outError = QStringLiteral("Failed to read save slot: %1")
-                       .arg(lastErrorString(query.lastError()));
+                      .arg(lastErrorString(query.lastError()));
     }
     return false;
   }
@@ -232,7 +230,7 @@ QVariantList SaveStorage::listSlots(QString *outError) const {
           "FROM saves ORDER BY datetime(timestamp) DESC"))) {
     if (outError) {
       *outError = QStringLiteral("Failed to enumerate save slots: %1")
-                       .arg(lastErrorString(query.lastError()));
+                      .arg(lastErrorString(query.lastError()));
     }
     return result;
   }
@@ -257,7 +255,6 @@ QVariantList SaveStorage::listSlots(QString *outError) const {
       slot.insert(QStringLiteral("thumbnail"), QString());
     }
 
-    // Optional helpers for QML convenience
     if (metadataObj.contains("playTime")) {
       slot.insert(QStringLiteral("playTime"),
                   metadataObj.value("playTime").toString());
@@ -287,7 +284,7 @@ bool SaveStorage::deleteSlot(const QString &slotName, QString *outError) {
   if (!query.exec()) {
     if (outError) {
       *outError = QStringLiteral("Failed to delete save slot: %1")
-                       .arg(lastErrorString(query.lastError()));
+                      .arg(lastErrorString(query.lastError()));
     }
     transaction.rollback();
     return false;
@@ -322,7 +319,7 @@ bool SaveStorage::open(QString *outError) const {
   if (!m_database.open()) {
     if (outError) {
       *outError = QStringLiteral("Failed to open save database: %1")
-                       .arg(lastErrorString(m_database.lastError()));
+                      .arg(lastErrorString(m_database.lastError()));
     }
     return false;
   }
@@ -344,10 +341,11 @@ bool SaveStorage::ensureSchema(QString *outError) const {
 
   if (currentVersion > kCurrentSchemaVersion) {
     if (outError) {
-      *outError = QStringLiteral(
-          "Save database schema version %1 is newer than supported %2")
-                       .arg(currentVersion)
-                       .arg(kCurrentSchemaVersion);
+      *outError =
+          QStringLiteral(
+              "Save database schema version %1 is newer than supported %2")
+              .arg(currentVersion)
+              .arg(kCurrentSchemaVersion);
     }
     return false;
   }
@@ -383,7 +381,7 @@ int SaveStorage::schemaVersion(QString *outError) const {
   if (!pragmaQuery.exec(QStringLiteral("PRAGMA user_version"))) {
     if (outError) {
       *outError = QStringLiteral("Failed to read schema version: %1")
-                       .arg(lastErrorString(pragmaQuery.lastError()));
+                      .arg(lastErrorString(pragmaQuery.lastError()));
     }
     return -1;
   }
@@ -401,7 +399,7 @@ bool SaveStorage::setSchemaVersion(int version, QString *outError) const {
           QStringLiteral("PRAGMA user_version = %1").arg(version))) {
     if (outError) {
       *outError = QStringLiteral("Failed to update schema version: %1")
-                       .arg(lastErrorString(pragmaQuery.lastError()));
+                      .arg(lastErrorString(pragmaQuery.lastError()));
     }
     return false;
   }
@@ -410,24 +408,24 @@ bool SaveStorage::setSchemaVersion(int version, QString *outError) const {
 
 bool SaveStorage::createBaseSchema(QString *outError) const {
   QSqlQuery query(m_database);
-  const QString createSql = QStringLiteral(
-      "CREATE TABLE IF NOT EXISTS saves ("
-      "id INTEGER PRIMARY KEY AUTOINCREMENT, "
-      "slot_name TEXT UNIQUE NOT NULL, "
-      "title TEXT NOT NULL, "
-      "map_name TEXT, "
-      "timestamp TEXT NOT NULL, "
-      "metadata BLOB NOT NULL, "
-      "world_state BLOB NOT NULL, "
-      "screenshot BLOB, "
-      "created_at TEXT NOT NULL, "
-      "updated_at TEXT NOT NULL"
-      ")");
+  const QString createSql =
+      QStringLiteral("CREATE TABLE IF NOT EXISTS saves ("
+                     "id INTEGER PRIMARY KEY AUTOINCREMENT, "
+                     "slot_name TEXT UNIQUE NOT NULL, "
+                     "title TEXT NOT NULL, "
+                     "map_name TEXT, "
+                     "timestamp TEXT NOT NULL, "
+                     "metadata BLOB NOT NULL, "
+                     "world_state BLOB NOT NULL, "
+                     "screenshot BLOB, "
+                     "created_at TEXT NOT NULL, "
+                     "updated_at TEXT NOT NULL"
+                     ")");
 
   if (!query.exec(createSql)) {
     if (outError) {
       *outError = QStringLiteral("Failed to create save schema: %1")
-                       .arg(lastErrorString(query.lastError()));
+                      .arg(lastErrorString(query.lastError()));
     }
     return false;
   }
@@ -438,7 +436,7 @@ bool SaveStorage::createBaseSchema(QString *outError) const {
           "(updated_at DESC)"))) {
     if (outError) {
       *outError = QStringLiteral("Failed to build save index: %1")
-                       .arg(lastErrorString(indexQuery.lastError()));
+                      .arg(lastErrorString(indexQuery.lastError()));
     }
     return false;
   }
@@ -459,8 +457,8 @@ bool SaveStorage::migrateSchema(int fromVersion, QString *outError) const {
       break;
     default:
       if (outError) {
-        *outError = QStringLiteral("Unsupported migration path from %1")
-                         .arg(version);
+        *outError =
+            QStringLiteral("Unsupported migration path from %1").arg(version);
       }
       return false;
     }

+ 1 - 1
game/units/barracks.cpp

@@ -58,7 +58,7 @@ void Barracks::init(const SpawnParams &params) {
   if (auto *prod = e->addComponent<Engine::Core::ProductionComponent>()) {
     prod->productType = "archer";
     prod->buildTime = 10.0f;
-    prod->maxUnits = 100;
+    prod->maxUnits = params.maxPopulation;
     prod->inProgress = false;
     prod->timeRemaining = 0.0f;
     prod->producedCount = 0;

+ 1 - 0
game/units/unit.h

@@ -27,6 +27,7 @@ struct SpawnParams {
   int playerId = 0;
   std::string unitType;
   bool aiControlled = false;
+  int maxPopulation = 100;
 };
 
 class Unit {

+ 128 - 131
ui/qml/LoadGamePanel.qml

@@ -1,7 +1,7 @@
+import QtQml 2.15
 import QtQuick 2.15
 import QtQuick.Controls 2.15
 import QtQuick.Layouts 1.3
-import QtQml 2.15
 import StandardOfIron.UI 1.0
 
 Item {
@@ -13,58 +13,77 @@ Item {
     anchors.fill: parent
     z: 25
     onVisibleChanged: {
-        if (!visible) {
-            return
-        }
+        if (!visible)
+            return ;
 
-        if (typeof loadListModel !== 'undefined') {
-            loadListModel.loadFromGame()
-        }
+        if (typeof loadListModel !== 'undefined')
+            loadListModel.loadFromGame();
+
+        if (typeof loadListView !== 'undefined')
+            loadListView.selectedIndex = loadListModel.count > 0 && !loadListModel.get(0).isEmpty ? 0 : -1;
+
+    }
+    Keys.onPressed: function(event) {
+        if (event.key === Qt.Key_Escape) {
+            root.cancelled();
+            event.accepted = true;
+        } else if (event.key === Qt.Key_Down) {
+            if (loadListView.selectedIndex < loadListModel.count - 1)
+                loadListView.selectedIndex++;
+
+            event.accepted = true;
+        } else if (event.key === Qt.Key_Up) {
+            if (loadListView.selectedIndex > 0)
+                loadListView.selectedIndex--;
+
+            event.accepted = true;
+        } else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
+            if (loadListView.selectedIndex >= 0 && !loadListModel.get(loadListView.selectedIndex).isEmpty)
+                root.loadRequested(loadListModel.get(loadListView.selectedIndex).slotName);
 
-        if (typeof loadListView !== 'undefined') {
-            loadListView.selectedIndex = loadListModel.count > 0 && !loadListModel.get(0).isEmpty ? 0 : -1
+            event.accepted = true;
         }
     }
+    Component.onCompleted: {
+        forceActiveFocus();
+        if (loadListModel.count > 0 && !loadListModel.get(0).isEmpty)
+            loadListView.selectedIndex = 0;
+
+    }
 
     Connections {
         target: typeof game !== 'undefined' ? game : null
         onSaveSlotsChanged: {
-            if (typeof loadListModel === 'undefined') {
-                return
-            }
+            if (typeof loadListModel === 'undefined')
+                return ;
 
-            var previousSlot = ""
+            var previousSlot = "";
             if (typeof loadListView !== 'undefined' && loadListView.selectedIndex >= 0 && loadListView.selectedIndex < loadListModel.count) {
-                var current = loadListModel.get(loadListView.selectedIndex)
-                if (current && !current.isEmpty) {
-                    previousSlot = current.slotName
-                }
-            }
-
-            loadListModel.loadFromGame()
+                var current = loadListModel.get(loadListView.selectedIndex);
+                if (current && !current.isEmpty)
+                    previousSlot = current.slotName;
 
-            if (typeof loadListView === 'undefined') {
-                return
             }
+            loadListModel.loadFromGame();
+            if (typeof loadListView === 'undefined')
+                return ;
 
-            var newIndex = -1
+            var newIndex = -1;
             if (previousSlot !== "") {
                 for (var i = 0; i < loadListModel.count; ++i) {
-                    var slot = loadListModel.get(i)
+                    var slot = loadListModel.get(i);
                     if (!slot.isEmpty && slot.slotName === previousSlot) {
-                        newIndex = i
-                        break
+                        newIndex = i;
+                        break;
                     }
                 }
             }
-
             if (newIndex === -1) {
-                if (loadListModel.count > 0 && !loadListModel.get(0).isEmpty) {
-                    newIndex = 0
-                }
-            }
+                if (loadListModel.count > 0 && !loadListModel.get(0).isEmpty)
+                    newIndex = 0;
 
-            loadListView.selectedIndex = newIndex
+            }
+            loadListView.selectedIndex = newIndex;
         }
     }
 
@@ -90,7 +109,6 @@ Item {
             anchors.margins: Theme.spacingXLarge
             spacing: Theme.spacingLarge
 
-            // Header
             RowLayout {
                 Layout.fillWidth: true
                 spacing: Theme.spacingMedium
@@ -107,6 +125,7 @@ Item {
                     text: "Cancel"
                     onClicked: root.cancelled()
                 }
+
             }
 
             Rectangle {
@@ -115,7 +134,6 @@ Item {
                 color: Theme.border
             }
 
-            // Save slots list
             Rectangle {
                 Layout.fillWidth: true
                 Layout.fillHeight: true
@@ -134,62 +152,59 @@ Item {
 
                         property int selectedIndex: -1
 
+                        spacing: Theme.spacingSmall
+
                         model: ListModel {
                             id: loadListModel
 
                             function loadFromGame() {
-                                clear()
-
+                                clear();
                                 if (typeof game === 'undefined' || !game.getSaveSlots) {
                                     append({
-                                        slotName: "No saves found",
-                                        title: "",
-                                        timestamp: 0,
-                                        mapName: "",
-                                        playTime: "",
-                                        thumbnail: "",
-                                        isEmpty: true
-                                    })
-                                    return
+                                        "slotName": "No saves found",
+                                        "title": "",
+                                        "timestamp": 0,
+                                        "mapName": "",
+                                        "playTime": "",
+                                        "thumbnail": "",
+                                        "isEmpty": true
+                                    });
+                                    return ;
                                 }
-
-                                var slots = game.getSaveSlots()
+                                var slots = game.getSaveSlots();
                                 for (var i = 0; i < slots.length; i++) {
                                     append({
-                                        slotName: slots[i].slotName || slots[i].name,
-                                        title: slots[i].title || slots[i].name || slots[i].slotName || "Untitled Save",
-                                        timestamp: slots[i].timestamp,
-                                        mapName: slots[i].mapName || "Unknown Map",
-                                        playTime: slots[i].playTime || "",
-                                        thumbnail: slots[i].thumbnail || "",
-                                        isEmpty: false
-                                    })
+                                        "slotName": slots[i].slotName || slots[i].name,
+                                        "title": slots[i].title || slots[i].name || slots[i].slotName || "Untitled Save",
+                                        "timestamp": slots[i].timestamp,
+                                        "mapName": slots[i].mapName || "Unknown Map",
+                                        "playTime": slots[i].playTime || "",
+                                        "thumbnail": slots[i].thumbnail || "",
+                                        "isEmpty": false
+                                    });
                                 }
-
-                                if (count === 0) {
+                                if (count === 0)
                                     append({
-                                        slotName: "No saves found",
-                                        title: "",
-                                        timestamp: 0,
-                                        mapName: "",
-                                        playTime: "",
-                                        thumbnail: "",
-                                        isEmpty: true
-                                    })
-                                }
+                                        "slotName": "No saves found",
+                                        "title": "",
+                                        "timestamp": 0,
+                                        "mapName": "",
+                                        "playTime": "",
+                                        "thumbnail": "",
+                                        "isEmpty": true
+                                    });
+
                             }
 
                             Component.onCompleted: {
-                                loadFromGame()
+                                loadFromGame();
                             }
                         }
 
-                        spacing: Theme.spacingSmall
                         delegate: Rectangle {
                             width: loadListView.width
                             height: model.isEmpty ? 100 : 130
-                            color: loadListView.selectedIndex === index ? Theme.selectedBg : 
-                                   mouseArea.containsMouse ? Theme.hoverBg : Qt.rgba(0, 0, 0, 0)
+                            color: loadListView.selectedIndex === index ? Theme.selectedBg : mouseArea.containsMouse ? Theme.hoverBg : Qt.rgba(0, 0, 0, 0)
                             radius: Theme.radiusMedium
                             border.color: loadListView.selectedIndex === index ? Theme.selectedBr : Theme.cardBorder
                             border.width: 1
@@ -202,6 +217,7 @@ Item {
 
                                 Rectangle {
                                     id: loadThumbnail
+
                                     Layout.preferredWidth: 128
                                     Layout.preferredHeight: 80
                                     radius: Theme.radiusSmall
@@ -213,12 +229,11 @@ Item {
 
                                     Image {
                                         id: loadThumbnailImage
+
                                         anchors.fill: parent
                                         anchors.margins: 2
                                         fillMode: Image.PreserveAspectCrop
-                                        source: model.thumbnail && model.thumbnail.length > 0
-                                                    ? "data:image/png;base64," + model.thumbnail
-                                                    : ""
+                                        source: model.thumbnail && model.thumbnail.length > 0 ? "data:image/png;base64," + model.thumbnail : ""
                                         visible: source !== ""
                                     }
 
@@ -229,6 +244,7 @@ Item {
                                         color: Theme.textHint
                                         font.pointSize: Theme.fontSizeTiny
                                     }
+
                                 }
 
                                 ColumnLayout {
@@ -279,7 +295,9 @@ Item {
                                             font.pointSize: Theme.fontSizeSmall
                                             visible: model.playTime !== ""
                                         }
+
                                     }
+
                                 }
 
                                 Label {
@@ -296,7 +314,7 @@ Item {
                                     highlighted: true
                                     visible: !model.isEmpty
                                     onClicked: {
-                                        root.loadRequested(model.slotName)
+                                        root.loadRequested(model.slotName);
                                     }
                                 }
 
@@ -304,33 +322,38 @@ Item {
                                     text: "Delete"
                                     visible: !model.isEmpty
                                     onClicked: {
-                                        confirmDeleteDialog.slotName = model.slotName
-                                        confirmDeleteDialog.slotIndex = index
-                                        confirmDeleteDialog.open()
+                                        confirmDeleteDialog.slotName = model.slotName;
+                                        confirmDeleteDialog.slotIndex = index;
+                                        confirmDeleteDialog.open();
                                     }
                                 }
+
                             }
 
                             MouseArea {
                                 id: mouseArea
+
                                 anchors.fill: parent
                                 hoverEnabled: true
                                 enabled: !model.isEmpty
                                 onClicked: {
-                                    loadListView.selectedIndex = index
+                                    loadListView.selectedIndex = index;
                                 }
                                 onDoubleClicked: {
-                                    if (!model.isEmpty) {
-                                        root.loadRequested(model.slotName)
-                                    }
+                                    if (!model.isEmpty)
+                                        root.loadRequested(model.slotName);
+
                                 }
                             }
+
                         }
+
                     }
+
                 }
+
             }
 
-            // Load button at bottom
             RowLayout {
                 Layout.fillWidth: true
                 spacing: Theme.spacingMedium
@@ -340,9 +363,7 @@ Item {
                 }
 
                 Label {
-                    text: loadListView.selectedIndex >= 0 && !loadListModel.get(loadListView.selectedIndex).isEmpty ? 
-                          "Selected: " + loadListModel.get(loadListView.selectedIndex).title : 
-                          "Select a save to load"
+                    text: loadListView.selectedIndex >= 0 && !loadListModel.get(loadListView.selectedIndex).isEmpty ? "Selected: " + loadListModel.get(loadListView.selectedIndex).title : "Select a save to load"
                     color: Theme.textSub
                     font.pointSize: Theme.fontSizeMedium
                 }
@@ -352,13 +373,16 @@ Item {
                     enabled: loadListView.selectedIndex >= 0 && !loadListModel.get(loadListView.selectedIndex).isEmpty
                     highlighted: true
                     onClicked: {
-                        if (loadListView.selectedIndex >= 0 && !loadListModel.get(loadListView.selectedIndex).isEmpty) {
-                            root.loadRequested(loadListModel.get(loadListView.selectedIndex).slotName)
-                        }
+                        if (loadListView.selectedIndex >= 0 && !loadListModel.get(loadListView.selectedIndex).isEmpty)
+                            root.loadRequested(loadListModel.get(loadListView.selectedIndex).slotName);
+
                     }
                 }
+
             }
+
         }
+
     }
 
     Dialog {
@@ -372,27 +396,24 @@ Item {
         title: "Confirm Delete"
         modal: true
         standardButtons: Dialog.Yes | Dialog.No
-
         onAccepted: {
             if (typeof game !== 'undefined' && game.deleteSaveSlot) {
                 if (game.deleteSaveSlot(slotName)) {
-                    loadListModel.remove(slotIndex)
-
-                    if (loadListModel.count === 0) {
+                    loadListModel.remove(slotIndex);
+                    if (loadListModel.count === 0)
                         loadListModel.append({
-                            slotName: "No saves found",
-                            title: "",
-                            timestamp: 0,
-                            mapName: "",
-                            playTime: "",
-                            thumbnail: "",
-                            isEmpty: true
-                        })
-                    }
+                            "slotName": "No saves found",
+                            "title": "",
+                            "timestamp": 0,
+                            "mapName": "",
+                            "playTime": "",
+                            "thumbnail": "",
+                            "isEmpty": true
+                        });
+
+                    if (loadListView.selectedIndex >= loadListModel.count)
+                        loadListView.selectedIndex = loadListModel.count > 0 && !loadListModel.get(0).isEmpty ? loadListModel.count - 1 : -1;
 
-                    if (loadListView.selectedIndex >= loadListModel.count) {
-                        loadListView.selectedIndex = loadListModel.count > 0 && !loadListModel.get(0).isEmpty ? loadListModel.count - 1 : -1
-                    }
                 }
             }
         }
@@ -408,42 +429,18 @@ Item {
 
                 Label {
                     id: warningText
+
                     text: "Are you sure you want to delete the save:\n\"" + confirmDeleteDialog.slotName + "\"?\n\nThis action cannot be undone."
                     color: Theme.textMain
                     wrapMode: Text.WordWrap
                     Layout.fillWidth: true
                     font.pointSize: Theme.fontSizeMedium
                 }
-            }
-        }
-    }
 
-    Keys.onPressed: function(event) {
-        if (event.key === Qt.Key_Escape) {
-            root.cancelled()
-            event.accepted = true
-        } else if (event.key === Qt.Key_Down) {
-            if (loadListView.selectedIndex < loadListModel.count - 1) {
-                loadListView.selectedIndex++
             }
-            event.accepted = true
-        } else if (event.key === Qt.Key_Up) {
-            if (loadListView.selectedIndex > 0) {
-                loadListView.selectedIndex--
-            }
-            event.accepted = true
-        } else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
-            if (loadListView.selectedIndex >= 0 && !loadListModel.get(loadListView.selectedIndex).isEmpty) {
-                root.loadRequested(loadListModel.get(loadListView.selectedIndex).slotName)
-            }
-            event.accepted = true
-        }
-    }
 
-    Component.onCompleted: {
-        forceActiveFocus()
-        if (loadListModel.count > 0 && !loadListModel.get(0).isEmpty) {
-            loadListView.selectedIndex = 0
         }
+
     }
+
 }

+ 2 - 2
ui/qml/Main.qml

@@ -197,9 +197,9 @@ ApplicationWindow {
         }
         onSaveRequested: function(slotName) {
             console.log("Main: Save requested for slot:", slotName);
-            if (typeof game !== 'undefined' && game.saveGameToSlot) {
+            if (typeof game !== 'undefined' && game.saveGameToSlot)
                 game.saveGameToSlot(slotName);
-            }
+
             saveGamePanel.visible = false;
             mainWindow.menuVisible = true;
         }

+ 65 - 57
ui/qml/SaveGamePanel.qml

@@ -1,7 +1,7 @@
+import QtQml 2.15
 import QtQuick 2.15
 import QtQuick.Controls 2.15
 import QtQuick.Layouts 1.3
-import QtQml 2.15
 import StandardOfIron.UI 1.0
 
 Item {
@@ -13,25 +13,32 @@ Item {
     anchors.fill: parent
     z: 25
     onVisibleChanged: {
-        if (!visible) {
-            return
-        }
+        if (!visible)
+            return ;
 
-        if (typeof saveListModel !== 'undefined') {
-            saveListModel.loadFromGame()
-        }
+        if (typeof saveListModel !== 'undefined')
+            saveListModel.loadFromGame();
+
+        if (typeof saveNameField !== 'undefined' && saveNameField)
+            saveNameField.text = "Save_" + Qt.formatDateTime(new Date(), "yyyy-MM-dd_HH-mm");
 
-        if (typeof saveNameField !== 'undefined' && saveNameField) {
-            saveNameField.text = "Save_" + Qt.formatDateTime(new Date(), "yyyy-MM-dd_HH-mm")
+    }
+    Keys.onPressed: function(event) {
+        if (event.key === Qt.Key_Escape) {
+            root.cancelled();
+            event.accepted = true;
         }
     }
+    Component.onCompleted: {
+        forceActiveFocus();
+    }
 
     Connections {
         target: typeof game !== 'undefined' ? game : null
         onSaveSlotsChanged: {
-            if (typeof saveListModel !== 'undefined') {
-                saveListModel.loadFromGame()
-            }
+            if (typeof saveListModel !== 'undefined')
+                saveListModel.loadFromGame();
+
         }
     }
 
@@ -57,7 +64,6 @@ Item {
             anchors.margins: Theme.spacingXLarge
             spacing: Theme.spacingLarge
 
-            // Header
             RowLayout {
                 Layout.fillWidth: true
                 spacing: Theme.spacingMedium
@@ -74,6 +80,7 @@ Item {
                     text: "Cancel"
                     onClicked: root.cancelled()
                 }
+
             }
 
             Rectangle {
@@ -82,7 +89,6 @@ Item {
                 color: Theme.border
             }
 
-            // Save slot name input
             RowLayout {
                 Layout.fillWidth: true
                 spacing: Theme.spacingMedium
@@ -95,20 +101,20 @@ Item {
 
                 TextField {
                     id: saveNameField
-                    
+
                     Layout.fillWidth: true
                     placeholderText: "Enter save name..."
                     text: "Save_" + Qt.formatDateTime(new Date(), "yyyy-MM-dd_HH-mm")
                     font.pointSize: Theme.fontSizeMedium
-                    
+                    color: Theme.textMain
+
                     background: Rectangle {
                         color: Theme.cardBase
                         border.color: saveNameField.activeFocus ? Theme.accent : Theme.border
                         border.width: 1
                         radius: Theme.radiusMedium
                     }
-                    
-                    color: Theme.textMain
+
                 }
 
                 Button {
@@ -117,16 +123,16 @@ Item {
                     highlighted: true
                     onClicked: {
                         if (saveListModel.slotExists(saveNameField.text)) {
-                            confirmOverwriteDialog.slotName = saveNameField.text
-                            confirmOverwriteDialog.open()
+                            confirmOverwriteDialog.slotName = saveNameField.text;
+                            confirmOverwriteDialog.open();
                         } else {
-                            root.saveRequested(saveNameField.text)
+                            root.saveRequested(saveNameField.text);
                         }
                     }
                 }
+
             }
 
-            // Existing saves list
             Label {
                 text: "Existing Saves"
                 color: Theme.textSub
@@ -149,43 +155,42 @@ Item {
                     ListView {
                         id: saveListView
 
+                        spacing: Theme.spacingSmall
+
                         model: ListModel {
                             id: saveListModel
 
                             function slotExists(name) {
                                 for (var i = 0; i < count; i++) {
-                                    if (get(i).slotName === name) {
-                                        return true
-                                    }
+                                    if (get(i).slotName === name)
+                                        return true;
+
                                 }
-                                return false
+                                return false;
                             }
 
                             function loadFromGame() {
-                                clear()
-
-                                if (typeof game === 'undefined' || !game.getSaveSlots) {
-                                    return
-                                }
+                                clear();
+                                if (typeof game === 'undefined' || !game.getSaveSlots)
+                                    return ;
 
-                                var slots = game.getSaveSlots()
+                                var slots = game.getSaveSlots();
                                 for (var i = 0; i < slots.length; i++) {
                                     append({
-                                        slotName: slots[i].slotName || slots[i].name,
-                                        title: slots[i].title || slots[i].name || slots[i].slotName || "Untitled Save",
-                                        timestamp: slots[i].timestamp,
-                                        mapName: slots[i].mapName || "Unknown Map",
-                                        thumbnail: slots[i].thumbnail || ""
-                                    })
+                                        "slotName": slots[i].slotName || slots[i].name,
+                                        "title": slots[i].title || slots[i].name || slots[i].slotName || "Untitled Save",
+                                        "timestamp": slots[i].timestamp,
+                                        "mapName": slots[i].mapName || "Unknown Map",
+                                        "thumbnail": slots[i].thumbnail || ""
+                                    });
                                 }
                             }
 
                             Component.onCompleted: {
-                                loadFromGame()
+                                loadFromGame();
                             }
                         }
 
-                        spacing: Theme.spacingSmall
                         delegate: Rectangle {
                             width: saveListView.width
                             height: 80
@@ -201,6 +206,7 @@ Item {
 
                                 Rectangle {
                                     id: thumbnailContainer
+
                                     Layout.preferredWidth: 96
                                     Layout.preferredHeight: 64
                                     radius: Theme.radiusSmall
@@ -211,12 +217,11 @@ Item {
 
                                     Image {
                                         id: thumbnailImage
+
                                         anchors.fill: parent
                                         anchors.margins: 2
                                         fillMode: Image.PreserveAspectCrop
-                                        source: model.thumbnail && model.thumbnail.length > 0
-                                                    ? "data:image/png;base64," + model.thumbnail
-                                                    : ""
+                                        source: model.thumbnail && model.thumbnail.length > 0 ? "data:image/png;base64," + model.thumbnail : ""
                                         visible: source !== ""
                                     }
 
@@ -227,6 +232,7 @@ Item {
                                         color: Theme.textHint
                                         font.pointSize: Theme.fontSizeTiny
                                     }
+
                                 }
 
                                 ColumnLayout {
@@ -265,30 +271,39 @@ Item {
                                         Layout.fillWidth: true
                                         elide: Label.ElideRight
                                     }
+
                                 }
 
                                 Button {
                                     text: "Overwrite"
                                     onClicked: {
-                                        confirmOverwriteDialog.slotName = model.slotName
-                                        confirmOverwriteDialog.open()
+                                        confirmOverwriteDialog.slotName = model.slotName;
+                                        confirmOverwriteDialog.open();
                                     }
                                 }
+
                             }
 
                             MouseArea {
                                 id: mouseArea
+
                                 anchors.fill: parent
                                 hoverEnabled: true
                                 onClicked: {
-                                    saveNameField.text = model.slotName
+                                    saveNameField.text = model.slotName;
                                 }
                             }
+
                         }
+
                     }
+
                 }
+
             }
+
         }
+
     }
 
     Dialog {
@@ -301,9 +316,8 @@ Item {
         title: "Confirm Overwrite"
         modal: true
         standardButtons: Dialog.Yes | Dialog.No
-
         onAccepted: {
-            root.saveRequested(slotName)
+            root.saveRequested(slotName);
         }
 
         contentItem: Rectangle {
@@ -317,24 +331,18 @@ Item {
 
                 Label {
                     id: warningText
+
                     text: "Are you sure you want to overwrite the save:\n\"" + confirmOverwriteDialog.slotName + "\"?"
                     color: Theme.textMain
                     wrapMode: Text.WordWrap
                     Layout.fillWidth: true
                     font.pointSize: Theme.fontSizeMedium
                 }
+
             }
-        }
-    }
 
-    Keys.onPressed: function(event) {
-        if (event.key === Qt.Key_Escape) {
-            root.cancelled()
-            event.accepted = true
         }
-    }
 
-    Component.onCompleted: {
-        forceActiveFocus()
     }
+
 }