177 lines
4.9 KiB
C++
177 lines
4.9 KiB
C++
#ifndef CITY_H
|
|
#define CITY_H
|
|
|
|
#include <QString>
|
|
#include <QVector3D>
|
|
#include <vector>
|
|
#include <utility>
|
|
#include <map>
|
|
#include <cmath>
|
|
#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<QString> completedBuildings; // IDs of completed buildings in the city
|
|
|
|
std::vector<std::pair<int, int>> territory; // Owned hex coordinates
|
|
std::map<std::pair<int, int>, QString> workedTiles; // (x, y) -> resource name
|
|
std::map<std::pair<int, int>, 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
|