File indexing completed on 2021-12-21 12:50:21
0001 #include <stdio.h> 0002 #include <assert.h> 0003 #include <unistd.h> 0004 #include <string.h> 0005 0006 #include <QFile> 0007 #include <KSharedConfig> 0008 #include <KConfigGroup> 0009 #include "LevelCollection.h" 0010 0011 #include "Map.h" 0012 #if 1 0013 #define GETUID() 501 0014 #else 0015 #ifndef WIN32 0016 #define GETUID() getuid() 0017 #else 0018 #define GETUID() 1000 0019 #endif 0020 #endif 0021 0022 0023 static inline unsigned long 0024 forward(unsigned long a, unsigned long b, unsigned long c, unsigned long d) 0025 { 0026 unsigned long x=(a^b)&0xfffffffful; 0027 return (((x<<c)|(x>>((32ul-c)&31ul)))*d)&0xfffffffful; 0028 } 0029 0030 static inline unsigned long 0031 backward(unsigned long a, unsigned long b, unsigned long c, unsigned long d) 0032 { 0033 unsigned long x=(a*b)&0xfffffffful; 0034 return (((x<<c)|(x>>((32ul-c)&31ul)))^d)&0xfffffffful; 0035 } 0036 0037 0038 void 0039 LevelCollection::indexTextCollection() { 0040 enum states { 0041 BEFORE_NONE, BEFORE_VALID, BEFORE_INVALID, 0042 DURING_NONE, DURING_VALID, DURING_INVALID 0043 } state = BEFORE_NONE; 0044 0045 int levelstart=0, levelend=0; 0046 for (int pos=0; pos<(data_.size()-1); pos++) { 0047 switch (state) { 0048 case BEFORE_NONE: 0049 switch (data_[pos]) { 0050 case '#': case '.': case '$': case '+': case '*': case '@': 0051 state = BEFORE_VALID; 0052 break; 0053 0054 case ' ': case '\t': case '\r': 0055 break; 0056 0057 case '\n': 0058 levelstart = pos + 1; 0059 break; 0060 0061 default: 0062 state = BEFORE_INVALID; 0063 break; 0064 } 0065 break; 0066 0067 case BEFORE_VALID: 0068 switch (data_[pos]) { 0069 case '#': case '.': case '$': case '+': case '*': case '@': 0070 case ' ': case '\t': case '\r': 0071 break; 0072 0073 case '\n': 0074 addLevel(data_.constData() + levelstart); 0075 levelend = levelstart; 0076 state = DURING_NONE; 0077 break; 0078 0079 default: 0080 state = BEFORE_INVALID; 0081 break; 0082 } 0083 break; 0084 0085 case BEFORE_INVALID: 0086 switch (data_[pos]) { 0087 case '\n': 0088 levelstart = pos + 1; 0089 state = BEFORE_NONE; 0090 break; 0091 } 0092 break; 0093 0094 case DURING_NONE: 0095 switch (data_[pos]) { 0096 case '#': case '.': case '$': case '+': case '*': case '@': 0097 state = DURING_VALID; 0098 break; 0099 0100 case ' ': case '\t': case '\r': 0101 break; 0102 0103 case '\n': 0104 data_[levelend] = '\0'; 0105 levelstart = pos + 1; 0106 state = BEFORE_NONE; 0107 break; 0108 0109 default: 0110 state = DURING_INVALID; 0111 break; 0112 } 0113 break; 0114 0115 case DURING_VALID: 0116 switch (data_[pos]) { 0117 case '#': case '.': case '$': case '+': case '*': case '@': 0118 case ' ': case '\t': case '\r': 0119 break; 0120 0121 case '\n': 0122 levelend = pos; 0123 state = DURING_NONE; 0124 break; 0125 0126 default: 0127 state = DURING_INVALID; 0128 break; 0129 } 0130 break; 0131 0132 case DURING_INVALID: 0133 switch (data_[pos]) { 0134 case '\n': 0135 data_[levelend] = '\0'; 0136 levelstart = pos + 1; 0137 state = BEFORE_NONE; 0138 break; 0139 } 0140 break; 0141 0142 default: 0143 assert(0); 0144 } 0145 } 0146 0147 if (state==DURING_NONE || state==DURING_INVALID) { 0148 data_[levelend] = '\0'; 0149 } 0150 } 0151 0152 void 0153 LevelCollection::loadPrefs() { 0154 if (id_ >= 0) { 0155 KSharedConfigPtr cfg=KSharedConfig::openConfig(); 0156 KConfigGroup settingsGroup(cfg, "settings"); 0157 0158 QString key = QString::asprintf("level%d", id_); 0159 level_ = settingsGroup.readEntry(key, QStringLiteral("0")).toInt(); 0160 0161 key = QString::asprintf("status%d", id_); 0162 unsigned long x = settingsGroup.readEntry(key, QStringLiteral("0")).toULong(); 0163 0164 x = backward(x, 0xc1136a15ul, 0x12ul, 0x80ff0b94ul); 0165 x = backward(x, 0xd38fd2ddul, 0x01ul, 0xd4d657b4ul); 0166 x = backward(x, 0x59004eeful, 0x1eul, 0xf6c75e2cul); 0167 x = backward(x, 0x366c3e25ul, 0x0aul, 0x61ebc208ul); 0168 x = backward(x, 0x20a784c9ul, 0x15ul, 0x207d488bul); 0169 x = backward(x, 0xc02864abul, 0x09ul, 0x709e62a3ul); 0170 x = backward(x, 0xe2a60f19ul, 0x0eul, 0x8bb02c07ul); 0171 x = backward(x, 0x3b0e11f3ul, 0x13ul, 0x608aef3ful); 0172 0173 completedLevels_ = x>>16 & 0x3ff; 0174 if (!settingsGroup.hasKey(key)) completedLevels_ = 0; 0175 if (((x>>26) & 0x3ful) != (unsigned long) id_) completedLevels_ = 0; 0176 if ((x & 0xfffful) != (unsigned long) GETUID()) completedLevels_ = 0; 0177 if (completedLevels_ > noOfLevels_) completedLevels_ = 0; 0178 0179 if (level_ > completedLevels_) level_ = completedLevels_; 0180 if (level_ >= noOfLevels_) level_ = noOfLevels_-1; 0181 if (level_ < 0) level_ = 0; 0182 } else { 0183 level_ = 0; 0184 completedLevels_ = noOfLevels_; 0185 } 0186 } 0187 0188 void 0189 LevelCollection::addLevel(const char* _level) { 0190 index_.append(_level); 0191 } 0192 0193 void 0194 LevelCollection::addData(const char* _data, unsigned _len) { 0195 unsigned pos = data_.size(); 0196 data_.resize(pos + _len); 0197 memcpy(data_.data() + pos, _data, _len); 0198 } 0199 0200 void 0201 LevelCollection::addSeparator() { 0202 unsigned pos = data_.size(); 0203 data_.resize(pos + 1); 0204 data_[pos] = '\0'; 0205 } 0206 0207 LevelCollection::LevelCollection(const char *_def, int _len, 0208 const QString &_name, int _id) : 0209 level_(0), completedLevels_(0), noOfLevels_(0), 0210 name_(_name), id_(_id) { 0211 0212 addData(_def, _len); 0213 addSeparator(); 0214 0215 indexTextCollection(); 0216 0217 noOfLevels_ = index_.size(); 0218 0219 loadPrefs(); 0220 } 0221 0222 LevelCollection::LevelCollection(const QString &_path, const QString &_name, 0223 int _id) : 0224 level_(0), completedLevels_(0), noOfLevels_(0), 0225 name_(_name), path_(_path), id_(_id) { 0226 0227 char buf[1024]; 0228 int len; 0229 0230 QFile file(path_); 0231 if (file.open(QIODevice::ReadOnly)) { 0232 while ((len = file.read(buf, 1024)) > 0) { 0233 addData((const char *) buf, len); 0234 } 0235 file.close(); 0236 addSeparator(); 0237 } 0238 0239 indexTextCollection(); 0240 0241 noOfLevels_ = index_.size(); 0242 0243 loadPrefs(); 0244 0245 } 0246 0247 LevelCollection::~LevelCollection() { 0248 if (id_ >= 0) { 0249 KSharedConfigPtr cfg=KSharedConfig::openConfig(); 0250 KConfigGroup settingsGroup(cfg,"settings"); 0251 0252 const QString key = QString::asprintf("level%d", id_); 0253 settingsGroup.writeEntry(key, QStringLiteral("%1").arg(level_)); 0254 } 0255 } 0256 0257 0258 void 0259 LevelCollection::levelCompleted() { 0260 if (completedLevels_ < (level_+1)) completedLevels_ = level_+1; 0261 0262 if (id_ >= 0) { 0263 unsigned long x=(((unsigned long) GETUID()) & 0xfffful); 0264 x |= ((unsigned long) id_)<<26; 0265 x |= ((unsigned long) completedLevels_)<<16; 0266 0267 x = forward(x, 0x608aef3ful, 0x0dul, 0xfb00ef3bul); 0268 x = forward(x, 0x8bb02c07ul, 0x12ul, 0x2a37dd29ul); 0269 x = forward(x, 0x709e62a3ul, 0x17ul, 0x23607603ul); 0270 x = forward(x, 0x207d488bul, 0x0bul, 0xc31fd579ul); 0271 x = forward(x, 0x61ebc208ul, 0x16ul, 0xbcffadadul); 0272 x = forward(x, 0xf6c75e2cul, 0x02ul, 0xa2baa00ful); 0273 x = forward(x, 0xd4d657b4ul, 0x1ful, 0x7e129575ul); 0274 x = forward(x, 0x80ff0b94ul, 0x0eul, 0x92fc153dul); 0275 0276 const QString key = QString::asprintf("status%d", id_); 0277 0278 KSharedConfigPtr cfg=KSharedConfig::openConfig(); 0279 KConfigGroup settingsGroup(cfg, "settings"); 0280 settingsGroup.writeEntry(key, QStringLiteral("%1").arg(x)); 0281 cfg->sync(); 0282 } 0283 } 0284 0285 0286 void 0287 LevelCollection::level(int _level) { 0288 assert(_level >= 0 && _level < noOfLevels_); 0289 0290 level_ = _level; 0291 if (level_ > completedLevels_) level_ = completedLevels_; 0292 if (level_ >= noOfLevels_) level_ = noOfLevels_ - 1; 0293 if (level_ < 0) level_ = 0; 0294 } 0295 0296 static int 0297 minX(const char *def) { 0298 int min_x = 10000; 0299 0300 int x=0; 0301 for (int pos=0; def[pos]; pos++) { 0302 switch(def[pos]) { 0303 case '\n': 0304 x = 0; 0305 break; 0306 0307 case ' ': 0308 x++; 0309 break; 0310 0311 case '\t': 0312 x = (x+8) & ~7; 0313 break; 0314 0315 case '\r': 0316 break; 0317 0318 default: 0319 if (x < min_x) min_x = x; 0320 break; 0321 } 0322 } 0323 0324 return min_x == 10000 ? -1 : min_x; 0325 } 0326 0327 0328 bool 0329 LevelCollection::loadLevel(Map *_map) { 0330 _map->clearMap(); 0331 0332 const char *def = index_[level_]; 0333 bool goodMap = true; 0334 int x=0, y=0, goalsLeft=0; 0335 0336 int min_x = minX(def); 0337 if (min_x < 0) { 0338 min_x = 0; 0339 goodMap = false; 0340 } 0341 0342 0343 _map->xpos_ = -1; 0344 _map->ypos_ = -1; 0345 0346 for (int pos=0; def[pos]; pos++) { 0347 switch(def[pos]) { 0348 case '\n': 0349 y++; 0350 x = 0; 0351 break; 0352 0353 case ' ': 0354 x++; 0355 break; 0356 0357 case '\t': 0358 x = (x+8) & ~7; 0359 break; 0360 0361 case '@': 0362 if (x-min_x > MAX_X || y > MAX_Y) goodMap = false; 0363 else { 0364 _map->xpos_ = x-min_x; 0365 _map->ypos_ = y; 0366 } 0367 x++; 0368 break; 0369 0370 case '$': 0371 if (x-min_x > MAX_X || y > MAX_Y) goodMap = false; 0372 else _map->map(x-min_x, y, OBJECT); 0373 x++; 0374 break; 0375 0376 case '.': 0377 if (x-min_x > MAX_X || y > MAX_Y) goodMap = false; 0378 else { 0379 _map->map(x-min_x, y, GOAL); 0380 goalsLeft++; 0381 } 0382 x++; 0383 break; 0384 0385 case '#': 0386 if (x-min_x > MAX_X || y > MAX_Y) goodMap = false; 0387 else _map->map(x-min_x, y, WALL); 0388 x++; 0389 break; 0390 0391 case '+': 0392 if (x-min_x > MAX_X || y > MAX_Y) goodMap = false; 0393 else { 0394 _map->xpos_ = x-min_x; 0395 _map->ypos_ = y; 0396 _map->map(x-min_x, y, GOAL); 0397 goalsLeft++; 0398 } 0399 x++; 0400 break; 0401 0402 case '*': 0403 if (x-min_x > MAX_X || y > MAX_Y) goodMap = false; 0404 else _map->map(x-min_x, y, OBJECT|GOAL); 0405 x++; 0406 break; 0407 0408 case '\r': 0409 break; 0410 0411 default: 0412 goodMap = false; 0413 break; 0414 } 0415 } 0416 0417 if (_map->objectsLeft() != goalsLeft) goodMap = false; 0418 if (_map->completed()) goodMap = false; 0419 0420 if (_map->badCoords(_map->xpos_, _map->ypos_)) goodMap = false; 0421 else { 0422 if (!_map->empty(_map->xpos_, _map->ypos_)) goodMap = false; 0423 else if (!_map->fillFloor(_map->xpos_, _map->ypos_)) goodMap = false; 0424 } 0425 0426 return goodMap; 0427 } 0428