• Skip to content
  • Skip to link menu
KDE 4.0 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kgoldrunner

kgrgameio.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *  Copyright (C) 2006 by Ian Wadham
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU Lesser General Public
00015  *  License along with this library; if not, write to the 
00016  *  Free Software Foundation, Inc., 
00017  *  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00018  ***************************************************************************/
00019 
00020 
00021 #include "kgrgameio.h"
00022 #include <KDebug>
00023 #include <QDir>
00024 
00025 KGrGameIO::KGrGameIO ()
00026 {
00027 }
00028 
00029 IOStatus KGrGameIO::fetchGameListData
00030     (const QString & dir, QList<GameData *> & gameList)
00031 {
00032     QDir directory (dir);
00033     QStringList pattern;
00034     pattern << "game_*";
00035     QStringList files = directory.entryList (pattern, QDir::Files, QDir::Name);
00036 
00037     // KGr 3 has a game's data and all its levels in one file.
00038     // KGr 2 has all game-data in "games.dat" and each level in a separate file.
00039     bool kgr3Format = (files.count() > 0);
00040     if (! kgr3Format) {
00041     files << "games.dat";
00042     }
00043 
00044     // Loop to read each file containing game-data.
00045     foreach (const QString filename, files) {
00046     if (filename == "game_ende.txt") {
00047         continue;           // Skip the "ENDE" file.
00048     }
00049 
00050     GameData * g = initGameData (dir + filename);
00051     gameList.append (g);
00052     // kDebug()<< "GAME PATH:" << g->filePath;
00053 
00054     openFile.setFileName (g->filePath);
00055 
00056     // Check that the game-file exists.
00057     if (! openFile.exists()) {
00058         return (NotFound);
00059     }
00060 
00061     // Open the file for read-only.
00062     if (! openFile.open (QIODevice::ReadOnly)) {
00063         return (NoRead);
00064     }
00065 
00066     char c;
00067     QByteArray textLine;
00068 
00069     // Find the first line of game-data.
00070     c = getALine (kgr3Format, textLine);
00071     if (kgr3Format) {
00072         while ((c != 'G') && (c != '\0')) {
00073         c = getALine (kgr3Format, textLine);
00074         }
00075     }
00076     if (c == '\0') {
00077         openFile.close();
00078         return (UnexpectedEOF); // We reached end-of-file unexpectedly.
00079     }
00080 
00081     // Loop to extract the game-data for each game on the file.
00082     while (c != '\0') {
00083         if (kgr3Format && (c == 'L')) {
00084         break;          // End of KGr 3 game-file header.
00085         }
00086         // Decode line 1 of the game-data.
00087         QList<QByteArray> fields = textLine.split (' ');
00088         g->nLevels = fields.at(0).toInt();
00089         g->rules   = fields.at(1).at(0);
00090         g->prefix  = fields.at(2);
00091         // kDebug() << "Levels:" << g->nLevels << "Rules:" << g->rules <<
00092         // "Prefix:" << g->prefix;
00093 
00094         if (kgr3Format) {
00095         // KGr 3 Format: get skill, get game-name from next line.
00096         g->skill = fields.at(3).at(0);
00097         c = getALine (kgr3Format, textLine);
00098         if (c == ' ') {
00099             g->name = removeNewline (textLine);
00100         }
00101         }
00102         else {
00103         // KGr 2 Format: get game-name from end of line 1.
00104         int n = 0;
00105         // Skip the first 3 fields and extract the rest of the line.
00106         n = textLine.indexOf(' ', n) + 1;
00107         n = textLine.indexOf(' ', n) + 1;
00108         n = textLine.indexOf(' ', n) + 1;
00109         g->name = removeNewline (textLine.right (textLine.size() - n));
00110         }
00111         // kDebug() << "Skill:" << g->skill << "Name:" << g->name;
00112 
00113         // Loop to accumulate lines of about-data.  If kgr3Format, exit on
00114         // EOF or 'L' line.  If not kgr3Format, exit on EOF or numeric line.
00115         while (c != '\0') {
00116         c = getALine (kgr3Format, textLine);
00117         if ((c == '\0') ||
00118             (kgr3Format && (c == 'L')) ||
00119             ((! kgr3Format) &&
00120             (textLine.at(0) >= '0') && (textLine.at(0) <= '9'))) {
00121             break;
00122         }
00123         g->about.append (textLine);
00124         }
00125         g->about = removeNewline (g->about);    // Remove final '\n'.
00126         // kDebug() << "Info about: [" + g->about + "]";
00127 
00128         if ((! kgr3Format) && (c != '\0')) {
00129         g = initGameData (dir + filename);
00130         gameList.append (g);
00131         }
00132     } // END: game-data loop
00133 
00134     openFile.close();
00135 
00136     } // END: filename loop
00137 
00138     return (OK);
00139 }
00140 
00141 IOStatus KGrGameIO::fetchLevelData
00142     (const QString & dir, const QString & prefix,
00143         const int level, LevelData & d)
00144 {
00145     d.filePath = getFilePath (dir, prefix, level);
00146     d.level  = level;       // Level number.
00147     d.layout = "";      // Codes for the level layout (mandatory).
00148     d.name   = "";      // Level name (optional).
00149     d.hint   = "";      // Level hint (optional).
00150 
00151     // kDebug()<< "LEVEL PATH:" << d.filePath;
00152     openFile.setFileName (d.filePath);
00153 
00154     // Check that the level-file exists.
00155     if (! openFile.exists()) {
00156     return (NotFound);
00157     }
00158 
00159     // Open the file for read-only.
00160     if (! openFile.open (QIODevice::ReadOnly)) {
00161     return (NoRead);
00162     }
00163 
00164     char c;
00165     QByteArray textLine;
00166     IOStatus result = UnexpectedEOF;
00167 
00168     // Determine whether the file is in KGoldrunner v3 or v2 format.
00169     bool kgr3Format = (d.filePath.endsWith (".txt"));
00170 
00171     if (kgr3Format) {
00172     // In KGr 3 format, if a line starts with 'L', check the number.
00173     while ((c = getALine (kgr3Format, textLine)) != '\0') {
00174         if ((c == 'L') && (textLine.left(3).toInt() == level)) {
00175         break;          // We have found the required level.
00176         } 
00177     }
00178     if (c == '\0') {
00179         openFile.close();       // We reached end-of-file.
00180         return (UnexpectedEOF);
00181     }
00182     }  
00183 
00184     // Read in the character-codes for the level layout.
00185     if ((c = getALine (kgr3Format, textLine)) == ' ') {
00186     result = OK;
00187     d.layout = removeNewline (textLine);        // Remove '\n'.
00188 
00189     // Look for a line containing a level name (optional).
00190     if ((c = getALine (kgr3Format, textLine)) == ' ') {
00191         d.name = removeNewline (textLine);      // Remove '\n'.
00192 
00193         // Look for one or more lines containing a hint (optional).
00194         while ((c = getALine (kgr3Format, textLine)) == ' ') {
00195         d.hint.append (textLine);
00196         }
00197         d.hint = removeNewline (d.hint);        // Remove final '\n'.
00198     }
00199     }
00200 
00201     // kDebug() << "Level:" << level << "Layout length:" << d.layout.size();
00202     // kDebug() << "Name:" << "[" + d.name + "]";
00203     // kDebug() << "Hint:" << "[" + d.hint + "]";
00204 
00205     openFile.close();
00206     return (result);
00207 }
00208 
00209 QString KGrGameIO::getFilePath
00210     (const QString & dir, const QString & prefix, const int level)
00211 {
00212     QString filePath = ((level == 0) ? "ende" : prefix);
00213     filePath = dir + "game_" + filePath + ".txt";
00214     QFile test (filePath);
00215 
00216     // See if there is a game-file or "ENDE" screen in KGoldrunner 3 format.
00217     if (test.exists()) {
00218     return (filePath);
00219     }
00220 
00221     // If not, we are looking for a file in KGoldrunner 2 format.
00222     if (level == 0) {
00223     // End of game: show the "ENDE" screen.
00224     filePath = dir + "levels/level000.grl";
00225     }
00226     else {
00227     QString num;
00228     num.setNum (level);         // Convert INT -> QString.
00229     num = num.rightJustified (3,'0');   // Add 0-2 zeros at left.
00230     filePath = dir + "levels/" + prefix + num + ".grl";
00231     }
00232 
00233     return (filePath);
00234 }
00235 
00236 char KGrGameIO::getALine (const bool kgr3, QByteArray & line)
00237 {
00238     char c;
00239     line = "";
00240     while (openFile.getChar(&c)) {
00241     line = line.append (c);
00242     if (c == '\n') {
00243         break;
00244     }
00245     }
00246 
00247     // kDebug() << "Raw line:" << line;
00248     if (line.size() <= 0) {
00249     // Return a '\0' byte if end-of-file.
00250     return ('\0');
00251     }
00252     if (kgr3) {
00253     // In KGr 3 format, strip off leading and trailing syntax.
00254     if (line.startsWith ("// ")) {
00255         line = line.right (line.size() - 3);
00256         // kDebug() << "Stripped comment is:" << line;
00257     }
00258     else {
00259         if (line.startsWith (" i18n(\"")) {
00260         line = ' ' + line.right (line.size() - 7);
00261         }
00262         else if (line.startsWith (" NOTi18n(\"")) {
00263         line = ' ' + line.right (line.size() - 10);
00264         }
00265         else if (line.startsWith (" \"")) {
00266         line = ' ' + line.right (line.size() - 2);
00267         }
00268         if (line.endsWith ("\");\n")) {
00269         line = line.left (line.size() - 4) + '\n';
00270         }
00271         else if (line.endsWith ("\\n\"\n")) {
00272         line = line.left (line.size() - 4) + '\n';
00273         }
00274         else if (line.endsWith ("\"\n")) {
00275         line = line.left (line.size() - 2);
00276         }
00277         // kDebug() << "Stripped syntax is:" << line;
00278     }
00279     // In Kgr 3 format, return the first byte if not end-of-file.
00280     c = line.at (0);
00281     line = line.right (line.size() - 1);
00282     return (c);
00283     }
00284     else {
00285     // In KGr 2 format, return a space if not end-of-file.
00286     return (' ');
00287     }
00288 }
00289 
00290 QByteArray KGrGameIO::removeNewline (const QByteArray & line)
00291 {
00292     int len = line.size ();
00293     if ((len > 0) && (line.endsWith ('\n'))) {
00294     return (line.left (len -1));
00295     }
00296     else {
00297     return (line);
00298     }
00299 }
00300 
00301 GameData * KGrGameIO::initGameData (const QString & filePath)
00302 {
00303     GameData * g = new GameData;
00304     g->filePath = filePath;
00305     g->owner    = USER; // Owner of the game: "System" or "User".
00306     g->nLevels  = 0;    // Number of levels in the game.
00307     g->rules    = 'T';  // Game's rules: KGoldrunner or Traditional.
00308     g->prefix   = "";   // Game's filename prefix.
00309     g->skill    = 'N';  // Game's skill: Tutorial, Normal or Champion.
00310     g->name     = "";   // Name of the game.
00311     g->about    = "";   // Optional text about the game.
00312     return (g);
00313 }
00314 
00315 #include "kgrgameio.moc"

kgoldrunner

Skip menu "kgoldrunner"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members

API Reference

Skip menu "API Reference"
  • kblackbox
  • kgoldrunner
  • kmahjongg
  • ksquares
  • libkdegames
  •   highscore
  •   kgame
  •   kggzgames
  •   kggzmod
  •   kggznet
  • libkmahjongg
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal