Files
Ascent-of-Man/techconfig.cpp
T

132 lines
4.2 KiB
C++

#include "techconfig.h"
#include "yamlparser.h"
#include <QDebug>
#include <algorithm>
TechTreeManager::TechTreeManager()
: m_maxColumn(0), m_maxRow(0)
{
}
int TechTreeManager::computeTechDepth(const QString &techId, QMap<QString, int> &visited) const
{
if (visited.contains(techId)) {
return visited.value(techId);
}
visited[techId] = 0; // Guard against cycles
auto it = m_techs.find(techId);
if (it == m_techs.end()) {
return 0;
}
int maxPrereqDepth = -1;
for (const QString &pre : it.value().prerequisites) {
if (m_techs.contains(pre)) {
int d = computeTechDepth(pre, visited);
if (d > maxPrereqDepth) {
maxPrereqDepth = d;
}
}
}
int depth = maxPrereqDepth + 1;
visited[techId] = depth;
return depth;
}
bool TechTreeManager::loadConfigFile(const QString &filePath)
{
YamlNode root = YamlParser::parseFile(filePath);
if (root.children.isEmpty()) {
qWarning() << "Failed to parse technologies config YAML:" << filePath;
return false;
}
m_techs.clear();
m_orderedTechIds.clear();
m_maxColumn = 0;
m_maxRow = 0;
const YamlNode &techsNode = root.hasChild("technologies") ? root["technologies"] : root;
QMap<QString, bool> hasExplicitColumn;
QMap<QString, bool> hasExplicitRow;
for (auto it = techsNode.children.begin(); it != techsNode.children.end(); ++it) {
const YamlNode &node = it.value();
TechConfig cfg;
cfg.id = node.hasChild("id") ? node["id"].asString() : it.key();
cfg.name = node.hasChild("name") ? node["name"].asString() : cfg.id;
cfg.scienceCost = node.hasChild("science_cost") ? node["science_cost"].asInt(1000) : 1000;
if (node.hasChild("cost") && !node.hasChild("science_cost")) {
cfg.scienceCost = node["cost"].asInt(1000);
}
cfg.scienceCost = std::max(1, cfg.scienceCost);
if (node.hasChild("prerequisites")) {
cfg.prerequisites = node["prerequisites"].listValues;
}
if (node.hasChild("icon")) {
cfg.iconPath = node["icon"].asString("images/resources/kennis.png");
}
if (node.hasChild("description")) {
cfg.description = node["description"].asString("");
}
if (node.hasChild("column")) {
cfg.column = node["column"].asInt(0);
hasExplicitColumn[cfg.id] = true;
}
if (node.hasChild("row")) {
cfg.row = node["row"].asInt(0);
hasExplicitRow[cfg.id] = true;
}
m_techs[cfg.id] = cfg;
}
// Auto-calculate column and row for any tech without explicit coordinates
QMap<QString, int> depthCache;
QMap<int, int> nextRowInCol;
for (auto it = m_techs.begin(); it != m_techs.end(); ++it) {
if (!hasExplicitColumn.value(it.key(), false)) {
it.value().column = computeTechDepth(it.key(), depthCache);
}
if (hasExplicitRow.value(it.key(), false)) {
nextRowInCol[it.value().column] = std::max(nextRowInCol.value(it.value().column, 0), it.value().row + 1);
}
}
for (auto it = m_techs.begin(); it != m_techs.end(); ++it) {
if (!hasExplicitRow.value(it.key(), false)) {
int col = it.value().column;
it.value().row = nextRowInCol.value(col, 0);
nextRowInCol[col] = it.value().row + 1;
}
m_maxColumn = std::max(m_maxColumn, it.value().column);
m_maxRow = std::max(m_maxRow, it.value().row);
m_orderedTechIds.push_back(it.key());
}
std::sort(m_orderedTechIds.begin(), m_orderedTechIds.end(), [&](const QString &a, const QString &b) {
const TechConfig &ta = m_techs[a];
const TechConfig &tb = m_techs[b];
if (ta.column != tb.column) return ta.column < tb.column;
if (ta.row != tb.row) return ta.row < tb.row;
return ta.id < tb.id;
});
qDebug() << "TechTreeManager loaded" << m_techs.size() << "technologies from" << filePath;
return !m_techs.isEmpty();
}
const TechConfig* TechTreeManager::getTech(const QString &id) const
{
auto it = m_techs.find(id);
if (it != m_techs.end()) {
return &it.value();
}
return nullptr;
}