Ui fix.
[evilplumber] / src / game.cpp
index 3a71e3f..d64f3aa 100644 (file)
 #include <QTableWidget>
 #include <QListWidget>
 #include <QLabel>
-#include <QFile>
 #include <QPushButton>
 #include <QApplication>
+#include <QFile>
+#include <QDir>
 #include <QDebug>
 
 const Piece* findPiece(PieceType type, int rotation)
@@ -48,8 +49,6 @@ QString pieceToIconId(const Piece* piece, bool flow1 = false, bool flow2 = false
         fileName += (QString("_flow_") + (flow1? "1" : "0") + (flow2? "1" : "0"));
     }
 
-
-    qDebug() << "need: " << fileName;
     return fileName + ".png";
 }
 
@@ -68,11 +67,6 @@ int flowCount(const Piece* piece)
 
 Direction flowsTo(const Piece* piece, Direction flowFrom)
 {
-    //qDebug() << piece->flows[0];
-    //qDebug() << piece->flows[1];
-    //qDebug() << piece->flows[2];
-    //qDebug() << piece->flows[3];
-    //qDebug() << "check" << flowFrom;
     if (piece->flows[0] == flowFrom)
         return piece->flows[1];
     if (piece->flows[1] == flowFrom)
@@ -136,8 +130,6 @@ int GameField::toIndex(int row, int col)
 
 bool GameField::setPiece(int row, int col, const Piece* piece, bool fixed)
 {
-    qDebug() << "set piece" << row << col;
-
     if (row < 0 || row >= rows || col < 0 || col >= cols) {
         qWarning() << "Invalid piece index";
         return false;
@@ -145,7 +137,6 @@ bool GameField::setPiece(int row, int col, const Piece* piece, bool fixed)
 
     int index = toIndex(row, col);
     if (field[index].piece->type == PieceNone) {
-        qDebug() << "really setting";
         field[index].piece = piece;
         field[index].fixed = fixed;
 
@@ -154,6 +145,10 @@ bool GameField::setPiece(int row, int col, const Piece* piece, bool fixed)
         QLabel* label = (QLabel*)fieldUi->indexWidget(index);
         label->setPixmap(QPixmap(iconId));
 
+        if (fixed) {
+            label->setStyleSheet("background-color: #263d49");
+        }
+
         return true;
     }
     return false;
@@ -186,10 +181,15 @@ void GameField::indicateFlow(int row, int col, Direction dir)
     // Indicate the flow: fill the piece in question with the
     // liquid. (The piece can also be an empty one, or an illegal
     // one.)
-    qDebug() << "ind flow" << row << col << dir;
+
     if (row < 0 || col < 0 || row >= rows || col >= cols) {
         return;
     }
+    if (dir == DirFailed || dir == DirPassed) {
+        // No need to indicate these pseudo-directions
+        return;
+    }
+
     int index = toIndex(row, col);
     if (dir != DirNone && (field[index].piece->flows[0] == dir || field[index].piece->flows[1] == dir)) {
         field[index].flow[0] = true;
@@ -203,7 +203,6 @@ void GameField::indicateFlow(int row, int col, Direction dir)
         field[index].piece = ppieces;
         field[index].flow[0] = true;
         field[index].flow[1] = false;
-        
     }
     else {
         qWarning() << "Indicate flow: illegal direction" << row << col << dir;
@@ -211,7 +210,6 @@ void GameField::indicateFlow(int row, int col, Direction dir)
     }
 
     QString iconId = pieceToIconId(field[index].piece, field[index].flow[0], field[index].flow[1]);
-    qDebug() << "icon id" << iconId;
     QModelIndex mIndex = fieldUi->model()->index(row, col);
     QLabel* label = (QLabel*)fieldUi->indexWidget(mIndex);
 
@@ -225,18 +223,15 @@ AvailablePieces::AvailablePieces(QTableWidget* ui)
 
     // Setup ui
 
-    qDebug() << pieceUi->rowCount() << pieceUi->columnCount();
-
     for (int i = 0; i < 2; ++i)
         pieceUi->setColumnWidth(i, 120);
 
-    for (int i = 0; i < 4; ++i)
+    for (int i = 0; i < 5; ++i)
         pieceUi->setRowHeight(i, 70);
 
     for (int i = 0; ppieces[i].type != PiecesEnd; ++i) {
         if (ppieces[i].userCanAdd == false) continue;
 
-        //qDebug() << ppieces[i].type << ppieces[i].rotation;
         QString fileName = pieceToIconId(&(ppieces[i]));
 
         QTableWidgetItem* item = new QTableWidgetItem(QIcon(fileName), "0", QTableWidgetItem::UserType + pieceToId(&(ppieces[i])));
@@ -274,7 +269,6 @@ void AvailablePieces::initGame(int count, AvailablePiece* pieces)
 
 void AvailablePieces::onItemClicked(QTableWidgetItem* item)
 {
-    qDebug() << "piece clicked";
     int id =  item->type() - QTableWidgetItem::UserType;
 
     const Piece* piece = idToPiece(id);
@@ -339,7 +333,6 @@ void GameController::startLevel(QString fileName)
 
     gameData >> rows;
     gameData >> cols;
-    qDebug() << rows << cols;
     if (rows < 2 || rows > 10 || cols < 2 || cols > 10)
         qFatal("Error reading game file: rows and cols");
 
@@ -414,6 +407,7 @@ void GameController::startLevel(QString fileName)
     doneButton->setEnabled(true);
     timer.start();
     levelRunning = true;
+    file.close();
 }
 
 void GameController::onTimeout()
@@ -428,16 +422,14 @@ void GameController::onTimeout()
 
 void GameController::onCellClicked(int row, int column)
 {
-  qDebug() << "clicked: " << row << column;
-  if (!levelRunning) return;
-  if (currentPiece->type == PieceNone) return;
-  if (fieldUi->setPiece(row, column, currentPiece))
-      emit pieceUsed(currentPiece);
+    if (!levelRunning) return;
+    if (currentPiece->type == PieceNone) return;
+    if (fieldUi->setPiece(row, column, currentPiece))
+        emit pieceUsed(currentPiece);
 }
 
 void GameController::onValidPieceSelected(const Piece* piece)
 {
-    qDebug() << "selected: " << piece->type << piece->rotation;
     currentPiece = piece;
 }
 
@@ -531,11 +523,9 @@ void GameController::computeFlow()
     }
 
     // Now we know the next piece and where the flow comes *from*
-    qDebug() << "flow to" << flowRow << flowCol;
 
     // Check which piece is there
     const Piece* piece = fieldUi->pieceAt(flowRow, flowCol);
-    qDebug() << "there is" << piece->type << piece->rotation;
     flowDir = flowsTo(piece, flowDir);
     // If the piece was pre-placed, record that the liquid has
     // flown through it once
@@ -548,21 +538,21 @@ LevelSwitcher::LevelSwitcher(GameController* gameController,
                              QPushButton* levelStartButton,
                              QWidget* startWidget, QLabel* startTitle, 
                              QLabel* startLabel, QPushButton* startButton,
-                             QLabel* levelLabel, QLabel* scoreLabel,
-                             QStringList levelCollections)
+                             QWidget* gameWidget, QLabel* levelLabel, QLabel* scoreLabel,
+                             QStringList collections)
     : gameController(gameController),
       levelWidget(levelWidget), levelList(levelList), levelStartButton(levelStartButton),
       startWidget(startWidget), startTitle(startTitle), startLabel(startLabel), startButton(startButton),
-      levelLabel(levelLabel), scoreLabel(scoreLabel),
-      levelCollections(levelCollections), level(0), totalScore(0)
+      gameWidget(gameWidget), levelLabel(levelLabel), scoreLabel(scoreLabel),
+      curColl(""), level(0), totalScore(0)
 {
     connect(levelStartButton, SIGNAL(clicked()), this, SLOT(onLevelCollectionChosen()));
 
     connect(startButton, SIGNAL(clicked()), this, SLOT(onStartClicked()));
     connect(gameController, SIGNAL(levelPassed(int)), this, SLOT(onLevelPassed(int)));
     connect(gameController, SIGNAL(levelFailed()), this, SLOT(onLevelFailed()));
-    startTitle->setText("Starting a new game.");
-    scoreLabel->setText("0");
+    readSavedGames();
+    readLevelCollections(collections);
     chooseLevelCollection();
 }
 
@@ -570,42 +560,68 @@ void LevelSwitcher::chooseLevelCollection()
 {
     levelList->clear();
     bool first = true;
-    foreach (const QString& collection, levelCollections) {
+    foreach (const QString& collection, levelCollections.keys()) {
         QListWidgetItem *newItem = new QListWidgetItem();
-        newItem->setText(collection);
+
+        // Check how many levels the user has already passed
+        int passed = 0;
+        if (savedGames.contains(collection)) {
+            passed = savedGames[collection];
+        }
+        int total = 0;
+        if (levelCollections.contains(collection)) {
+            total = levelCollections[collection].size();
+        }
+
+        newItem->setText(collection + ", passed: " + 
+                         QString::number(passed) + " / " + QString::number(total));
         levelList->addItem(newItem); // transfers ownership
-        if (first) {
+        if (first && passed < total) {
             levelList->setCurrentItem(newItem);
             first = false;
         }
     }
+    gameWidget->hide();
+    startWidget->hide();
     levelWidget->show();
 }
 
 void LevelSwitcher::onLevelCollectionChosen()
 {
     levelWidget->hide();
-    QString collection = levelList->currentItem()->text();
-    QFile file(QString(LEVDIR) + "/" + collection + ".dat");
-    if (!file.exists())
-        qFatal("Error reading game file: doesn't exist");
-    file.open(QIODevice::ReadOnly);
-    QTextStream levelData(&file);
-    levels.clear();
-    
-    while (!levelData.atEnd())
-        levels << levelData.readLine();
+    curColl = levelList->currentItem()->text().split(",").first();
+
+    if (levelCollections.contains(curColl)) {
+        levels = levelCollections[curColl];
+    }
+    else
+        qFatal("Error choosing a level collection: unrecognized");
 
     level = 0;
+    // Go to the level the user has not yet passed
+    if (savedGames.contains(curColl)) {
+        level = savedGames[curColl];
+        if (level >= levels.size()) {
+            level = 0;
+        }
+    }
+    
     totalScore = 0;
+    if (level == 0)
+        startTitle->setText("Starting a new game.");
+    else
+        startTitle->setText(QString("Continuing a game from level ") + QString::number(level) + QString("."));
+
+    scoreLabel->setText("0");
     initiateLevel();
 }
 
 void LevelSwitcher::onStartClicked()
 {
-    startWidget->hide();
     levelLabel->setText(QString::number(level+1));
     gameController->startLevel(QString(LEVDIR) + "/" + levels[level] + ".dat");
+    startWidget->hide();
+    gameWidget->show();
 }
 
 void LevelSwitcher::initiateLevel()
@@ -628,6 +644,7 @@ void LevelSwitcher::initiateLevel()
     startButton->disconnect();
     connect(startButton, SIGNAL(clicked()), this, SLOT(onStartClicked()));
     startLabel->setText(introText);
+    gameWidget->hide();
     startWidget->show();
 }
 
@@ -639,6 +656,11 @@ void LevelSwitcher::onLevelPassed(int score)
     if (level < levels.size() - 1) {
         ++ level;
         startTitle->setText(QString("Level ") + QString::number(level) + QString(" passed, proceeding to level ") + QString::number(level+1));
+        // Record that the level has been passed, so that the user can
+        // start again
+        savedGames.insert(curColl, level);
+        writeSavedGames();
+
         initiateLevel();
     }
     else {
@@ -646,7 +668,12 @@ void LevelSwitcher::onLevelPassed(int score)
         startLabel->setText("Start a new game?");
         startButton->disconnect();
         connect(startButton, SIGNAL(clicked()), this, SLOT(chooseLevelCollection()));
+        // Record that all levels have been passed
+        savedGames.insert(curColl, levels.size());
+        writeSavedGames();
+
         level = 0;
+        gameWidget->hide();
         startWidget->show();
     }
 }
@@ -657,14 +684,62 @@ void LevelSwitcher::onLevelFailed()
     initiateLevel();
 }
 
-// Todo next:
+void LevelSwitcher::readSavedGames()
+{
+    QFile file(QDir::homePath() + "/.evilplumber");
+    if (!file.exists()) {
+        qWarning() << "Save file doesn't exist";
+        return;
+    }
+    file.open(QIODevice::ReadOnly);
+    QTextStream saveData(&file);
+    QString collection = 0;
+    int level = 0;
+    while (!saveData.atEnd()) {
+        saveData >> collection;
+        saveData >> level;
+
+        if (collection != "")
+            savedGames.insert(collection, level);
+    }
+    file.close();
+}
+
+void LevelSwitcher::readLevelCollections(QStringList collections)
+{
+    foreach (const QString& coll, collections) {
+        QFile file(QString(LEVDIR) + "/" + coll + ".dat");
+
+        if (!file.exists())
+            qFatal("Error reading level collection: doesn't exist");
+        file.open(QIODevice::ReadOnly);
+        QTextStream levelData(&file);
+        QStringList readLevels;
+        while (!levelData.atEnd())
+            readLevels << levelData.readLine();
+
+        levelCollections.insert(coll, readLevels);
+        file.close();
+    }
+}
+
+void LevelSwitcher::writeSavedGames()
+{
+    QFile file(QDir::homePath() + "/.evilplumber");
+    file.open(QIODevice::Truncate | QIODevice::WriteOnly);
+    QTextStream saveData(&file);
+    foreach (const QString& collection, savedGames.keys()) {
+        saveData << collection << " " << savedGames[collection] << endl;
+    }
+    file.close();
+}
+
+// TODO:
+// --- 0.1 ---
+// more levels to the basic collection
+// --- 0.2 ---
+// ability to install level sets as different packages
 // better graphics
-// save & load
-// level collections: introduction + basic
-// more levels
-// make fixed pipes look different than non-fixed ones
-// color theme
-// --------------
 // re-placing pieces
 // graphical hints on what to do next
 // graphical help, showing the ui elements: demo