File indexing completed on 2025-02-09 04:33:44
0001 /* 0002 SPDX-FileCopyrightText: 2011 Julian Helfferich <julian.helfferich@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "levelloader.h" 0008 0009 // own 0010 #include "globals.h" 0011 #include "kbreakout_debug.h" 0012 // KF 0013 // These can be removed when KConfig style levelsets are no longer supported 0014 #include <KConfig> 0015 #include <KConfigGroup> 0016 // Qt 0017 #include <QDomDocument> 0018 #include <QFile> 0019 #include <QStandardPaths> 0020 0021 LevelLoader::LevelLoader(QObject *parent) 0022 : QObject(parent) 0023 { 0024 m_level = 0; 0025 m_levelset = nullptr; 0026 } 0027 0028 LevelLoader::~LevelLoader() 0029 { 0030 delete m_levelset; 0031 } 0032 0033 int LevelLoader::level() const 0034 { 0035 return m_level; 0036 } 0037 0038 void LevelLoader::setLevel(int level) 0039 { 0040 m_level = level; 0041 } 0042 0043 QString LevelLoader::levelset() const 0044 { 0045 return m_levelname; 0046 } 0047 0048 void LevelLoader::setLevelset(const QString &levelname) 0049 { 0050 if (levelname == m_levelname) { 0051 return; 0052 } 0053 m_levelname = levelname; 0054 0055 // Loading document model 0056 // Locating the path in the filesystem 0057 QString path = QStringLiteral("levelsets/%1.levelset").arg(m_levelname); 0058 path = QStandardPaths::locate(QStandardPaths::AppDataLocation, path); 0059 // -- 0060 0061 delete m_levelset; 0062 0063 m_levelset = new QDomDocument(m_levelname); 0064 QFile file(path); 0065 if (!file.open(QIODevice::ReadOnly)) { 0066 qCCritical(KBREAKOUT_General) << "Can't open file " << path; 0067 } 0068 0069 const QDomDocument::ParseResult parseResult = m_levelset->setContent(&file); 0070 if (!parseResult) { 0071 file.close(); 0072 // Testing whether levelset is of old KConfig style 0073 KConfig kconfigfile(path, KConfig::SimpleConfig); 0074 if (kconfigfile.hasGroup(QStringLiteral("level1"))) { 0075 // Levelset is in KConfig style 0076 m_oldstyle = true; 0077 qCCritical(KBREAKOUT_General) << "Warning: Using deprecated KConfig-levelset. Please change to XML-Style.\n"; 0078 } else { 0079 qCCritical(KBREAKOUT_General) << "Can't read levelset from " << path << "\nError: " << parseResult.errorMessage << 0080 " in Line " << parseResult.errorLine << ", Column " << parseResult.errorColumn; 0081 } 0082 } else { 0083 // Successfully loaded QDom-style levelset 0084 m_oldstyle = false; 0085 } 0086 file.close(); 0087 // -- 0088 } 0089 0090 void LevelLoader::loadLevel() 0091 { 0092 // Check if levelset is of KConfig-type 0093 if (m_oldstyle) { 0094 loadOldStyleLevel(); 0095 return; 0096 } 0097 // Selecting the correct level 0098 m_level++; 0099 0100 if (m_levelset == nullptr) { 0101 qCCritical(KBREAKOUT_General) << "Error: No levelset specified"; 0102 return; 0103 } 0104 0105 QDomElement levels = m_levelset->documentElement(); 0106 QDomNode node = levels.firstChild(); 0107 for (int i = 1; i < m_level; i++) { 0108 node = node.nextSibling(); 0109 } 0110 // -- 0111 0112 // Load level information 0113 if (node.isNull() || node.toElement().tagName() != QLatin1String("Level")) { 0114 // Level not found or no more levels 0115 return; 0116 } 0117 0118 QDomAttr attribute; 0119 QDomElement level = node.toElement(); 0120 if (level.isNull()) { 0121 qCCritical(KBREAKOUT_General) << "Invalid Levelset " << m_levelname << ": Can't read level information"; 0122 } 0123 attribute = level.attributeNode(QStringLiteral("Name")); 0124 QString levelName; 0125 if (!attribute.isNull()) { 0126 levelName = level.attributeNode(QStringLiteral("Name")).value(); 0127 } 0128 node = node.firstChild(); 0129 // -- 0130 0131 // Load bricks and gifts 0132 m_lineNumber = 0; 0133 while (!node.isNull()) { 0134 QDomElement info = node.toElement(); 0135 if (info.isNull()) { 0136 qCCritical(KBREAKOUT_General) << "Invalid levelset " << m_levelname << ": Can't read level information."; 0137 } 0138 0139 if (info.tagName() == QLatin1String("Line")) { 0140 // Load one line of bricks 0141 loadLine(info); 0142 } else if (info.tagName() == QLatin1String("Gift")) { 0143 // Load one gift type 0144 loadGift(info); 0145 } else { 0146 qCCritical(KBREAKOUT_General) << "Invalid tag name " << info.tagName() << " has occurred in level " 0147 << levelName << " in levelset " << m_levelname; 0148 } 0149 0150 node = node.nextSibling(); 0151 } 0152 } 0153 0154 void LevelLoader::loadLine(QDomElement lineNode) 0155 { 0156 // Reading the line number 0157 QDomAttr attribute = lineNode.attributeNode(QStringLiteral("Number")); 0158 QDomElement attributeNode = lineNode.firstChildElement(QStringLiteral("Number")); 0159 if (!attribute.isNull()) { 0160 m_lineNumber = attribute.value().toInt(); 0161 } else if (!attributeNode.isNull()) { 0162 m_lineNumber = attributeNode.text().toInt(); 0163 } else { 0164 // Standard line numbering: load next line 0165 m_lineNumber++; 0166 } 0167 0168 // Reading the brick information 0169 attribute = lineNode.attributeNode(QStringLiteral("Bricks")); 0170 attributeNode = lineNode.firstChildElement(QStringLiteral("Bricks")); 0171 QString line; 0172 if (!attribute.isNull()) { 0173 line = attribute.value(); 0174 } else if (!attributeNode.isNull()) { 0175 line = attributeNode.text(); 0176 } else { 0177 line = lineNode.text(); 0178 } 0179 0180 if (line.size() > WIDTH) { 0181 qCCritical(KBREAKOUT_General) << "Invalid levelset " << m_levelname << ": too many bricks in line " 0182 << m_lineNumber; 0183 } 0184 0185 Q_EMIT newLine(line, m_lineNumber); 0186 } 0187 0188 void LevelLoader::loadGift(QDomElement giftNode) 0189 { 0190 bool nodeTextRead = false; 0191 // Reading the brick type 0192 QDomAttr attribute = giftNode.attributeNode(QStringLiteral("Type")); 0193 QDomElement attributeNode = giftNode.firstChildElement(QStringLiteral("Type")); 0194 QString giftType; 0195 if (!attribute.isNull()) { 0196 giftType = attribute.value(); 0197 } else if (!attributeNode.isNull()) { 0198 giftType = attributeNode.text(); 0199 nodeTextRead = true; 0200 } else { 0201 giftType = giftNode.text(); 0202 nodeTextRead = true; 0203 } 0204 0205 // Reading number of gifts to be distributed. If not specified one gift is placed. 0206 attribute = giftNode.attributeNode(QStringLiteral("Count")); 0207 attributeNode = giftNode.firstChildElement(QStringLiteral("Count")); 0208 int times = 1; 0209 bool ok = true; 0210 if (!attribute.isNull()) { 0211 times = attribute.value().toInt(&ok); 0212 } else if (!attributeNode.isNull()) { 0213 times = attributeNode.text().toInt(&ok); 0214 nodeTextRead = true; 0215 } else if (!nodeTextRead) { 0216 times = giftNode.text().toInt(&ok); 0217 if (!ok) { 0218 times = 1; 0219 } 0220 } 0221 0222 // If only one brick to be placed: see if position is given 0223 QString position; 0224 if (times == 1) { 0225 attribute = giftNode.attributeNode(QStringLiteral("Position")); 0226 attributeNode = giftNode.firstChildElement(QStringLiteral("Position")); 0227 if (!attribute.isNull()) { 0228 position = attribute.value(); 0229 } else if (!attributeNode.isNull()) { 0230 position = attributeNode.text(); 0231 nodeTextRead = true; 0232 } else if (!nodeTextRead && giftNode.text().contains(QLatin1Char(','))) { 0233 position = giftNode.text(); 0234 nodeTextRead = true; 0235 } 0236 } 0237 0238 Q_EMIT newGift(giftType, times, position); 0239 } 0240 0241 void LevelLoader::loadOldStyleLevel() 0242 { 0243 // Selecting the correct level 0244 m_level++; 0245 0246 // Loading the levelset 0247 QString path = QStringLiteral("levelsets/%1.levelset").arg(m_levelname); 0248 path = QStandardPaths::locate(QStandardPaths::AppDataLocation, path); 0249 KConfig file(path, KConfig::SimpleConfig); 0250 0251 QString levelName(QLatin1String("level") + QString::number(m_level)); 0252 0253 if (!file.hasGroup(levelName)) { 0254 // No more levels or no levels found 0255 return; 0256 } 0257 0258 // Loading level information 0259 KConfigGroup lvl = file.group(levelName); 0260 0261 // add bricks 0262 0263 int y = 1; 0264 QString key(QLatin1String("line") + QString::number(y)); 0265 0266 while (lvl.hasKey(key)) { 0267 // one line of bricks to be converted 0268 QString line = lvl.readEntry(key, "error"); 0269 if (line == QLatin1String("error")) { 0270 qCCritical(KBREAKOUT_General) << "Something strange happened!!\n"; 0271 return; 0272 } 0273 0274 qCDebug(KBREAKOUT_General) << line; 0275 0276 if (line.size() > WIDTH) { 0277 qCCritical(KBREAKOUT_General) << "Invalid file: too many bricks\n"; 0278 } 0279 0280 Q_EMIT newLine(line, y); 0281 0282 ++y; 0283 key = QLatin1String("line") + QString::number(y); 0284 } 0285 0286 // add gifts 0287 0288 for (int i = 0; i < GIFT_TYPES_COUNT; ++i) { 0289 key = GIFT_TYPES[i]; 0290 if (!lvl.hasKey(key)) { 0291 continue; 0292 } 0293 0294 QString line = lvl.readEntry(key, "error"); 0295 if (line == QLatin1String("error")) { 0296 qCCritical(KBREAKOUT_General) << "Impossible reading " << m_level << ":" << key; 0297 return; 0298 } 0299 bool ok; 0300 int times = line.toInt(&ok); 0301 if (!ok) { 0302 qCCritical(KBREAKOUT_General) << m_levelname << ":" << key << " invalid number!!"; 0303 continue; 0304 } 0305 0306 Q_EMIT newGift(key, times, QString()); 0307 } 0308 } 0309 0310 #include "moc_levelloader.cpp"