#ifndef CITY_H #define CITY_H #include #include #include #include #include #include #include "terrain.h" struct CityYieldSummary { int food = 0; int labor = 0; int science = 0; int culture = 0; int faith = 0; int gold = 0; }; enum class CityProjectType { None, Unit, Building }; struct CityProject { CityProjectType type = CityProjectType::None; QString id = ""; QString name = ""; int laborCost = 0; int currentLabor = 0; QString district = "center"; bool isValid() const { return type != CityProjectType::None && !id.isEmpty(); } float getProgress() const { return laborCost > 0 ? std::max(0.0f, std::min(1.0f, (float)currentLabor / (float)laborCost)) : 0.0f; } int getRemainingLabor() const { return std::max(0, laborCost - currentLabor); } }; class City { public: int id; int playerId; QString name; int tileX; int tileY; QVector3D worldPos; int inhabitants; int inhabitantsPerPop; int accumulatedLabor = 0; // Local resource (Arbeid) CityProject currentProject; std::vector completedBuildings; // IDs of completed buildings in the city std::vector> territory; // Owned hex coordinates std::map, QString> workedTiles; // (x, y) -> resource name std::map, QString> tilePreferredResources; // (x, y) -> user chosen resource City(int cId, int pId, const QString &cName, int tx, int ty, const QVector3D &pos, int initInhabitants = 1000, int initInhabitantsPerPop = 100000, int initRadius = 1); bool hasBuilding(const QString &buildingId) const { for (const auto &b : completedBuildings) { if (b == buildingId) return true; } return false; } bool addBuilding(const QString &buildingId) { if (hasBuilding(buildingId)) return false; completedBuildings.push_back(buildingId); return true; } bool hasActiveProject() const { return currentProject.isValid(); } void startProject(CityProjectType type, const QString &projId, const QString &projName, int cost, const QString &district = "center") { currentProject.type = type; currentProject.id = projId; currentProject.name = projName; currentProject.laborCost = std::max(1, cost); currentProject.currentLabor = 0; currentProject.district = district.isEmpty() ? "center" : district; } void cancelProject() { currentProject = CityProject(); } bool addTerritory(int tx, int ty) { if (ownsTile(tx, ty)) return false; territory.emplace_back(tx, ty); return true; } int getTotalPop() const { return (int)std::ceil((float)inhabitants / (float)std::max(1, inhabitantsPerPop)); } int getAssignedPop() const { return (int)workedTiles.size(); } int getAvailablePop() const { return std::max(0, getTotalPop() - getAssignedPop()); } bool ownsTile(int tx, int ty) const { for (const auto &p : territory) { if (p.first == tx && p.second == ty) return true; } return false; } bool isTileWorked(int tx, int ty) const { return workedTiles.find({tx, ty}) != workedTiles.end(); } QString getWorkedResource(int tx, int ty) const { auto it = workedTiles.find({tx, ty}); return it != workedTiles.end() ? it->second : ""; } QString getEffectiveResource(int tx, int ty, const QString &defaultBestRes) const { auto itW = workedTiles.find({tx, ty}); if (itW != workedTiles.end()) return itW->second; auto itP = tilePreferredResources.find({tx, ty}); if (itP != tilePreferredResources.end()) return itP->second; return defaultBestRes; } void setTilePreferredResource(int tx, int ty, const QString &resource) { tilePreferredResources[{tx, ty}] = resource; if (isTileWorked(tx, ty)) { workedTiles[{tx, ty}] = resource; } } bool assignWorker(int tx, int ty, const QString &resource) { if (!ownsTile(tx, ty)) return false; tilePreferredResources[{tx, ty}] = resource; if (isTileWorked(tx, ty)) { workedTiles[{tx, ty}] = resource; return true; } if (getAvailablePop() <= 0) return false; workedTiles[{tx, ty}] = resource; return true; } bool unassignWorker(int tx, int ty) { auto it = workedTiles.find({tx, ty}); if (it != workedTiles.end()) { workedTiles.erase(it); return true; } return false; } void toggleWorker(int tx, int ty, const QString &defaultRes) { if (isTileWorked(tx, ty)) { unassignWorker(tx, ty); } else { assignWorker(tx, ty, defaultRes); } } }; #endif // CITY_H