diff --git a/Bookmark.cpp b/Bookmark.cpp index 57f5c40..aef61f2 100644 --- a/Bookmark.cpp +++ b/Bookmark.cpp @@ -1,104 +1,104 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include "Bookmark.h" #include "History.h" #include "LevelMap.h" void Bookmark::fileName(QString &p) { p = QStandardPaths::writableLocation(QStandardPaths::DataLocation); QString n; n.setNum(number_); p += "/bookmark" + n; } Bookmark::Bookmark(int _num) : number_(_num), collection_(-1), level_(-1), moves_(0), data_("") { QString p; fileName(p); FILE *file = fopen(p.toLatin1(), "r"); if (file == NULL) return; char buf[4096]; buf[0] = '\0'; fgets (buf, 4096, file); if (sscanf(buf, "%d %d %d", &collection_, &level_, &moves_) != 3) { collection_ = level_ = -1; data_ = ""; fclose(file); return; } data_ = ""; int len; while (!feof(file)) { len = fread(buf, 1, 4095, file); if (ferror(file)) break; buf[len] = '\0'; data_ += buf; } fclose(file); data_ = data_.trimmed(); } void Bookmark::set(int _collection, int _level, int _moves, History *_h) { assert(_collection >= 0); if (_collection < 0) return; collection_ = _collection; level_ = _level; moves_ = _moves; data_ = ""; _h->save(data_); QString p; fileName(p); FILE *file = fopen(QFile::encodeName(p), "w"); if (file == NULL) return; fprintf(file, "%d %d %d\n", collection_, level_, moves_); fprintf(file, "%s\n", data_.toLatin1().constData()); fclose(file); } bool Bookmark::goTo(LevelMap *_map, History *_h) { return _h->load(_map, data_.toLatin1()) != 0; } diff --git a/Bookmark.h b/Bookmark.h index b63fa9f..9f1f13c 100644 --- a/Bookmark.h +++ b/Bookmark.h @@ -1,51 +1,51 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef BOOKMARK_H #define BOOKMARK_H class History; class LevelMap; #include class Bookmark { public: Bookmark(int _num); int collection() const { return collection_; } int level() const { return level_; } int moves() const { return moves_; } //int pushes() { return pushes_; } void set(int _collection, int _level, int _moves, History *_h); bool goTo(LevelMap *_map, History *_h); private: void fileName(QString &p); int number_; int collection_; int level_; int moves_; //int pushes_; QString data_; }; #endif /* BOOKMARK_H */ diff --git a/History.cpp b/History.cpp index 387b77f..6ff5cdb 100644 --- a/History.cpp +++ b/History.cpp @@ -1,134 +1,134 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "History.h" #include "Move.h" #include "MoveSequence.h" #include "LevelMap.h" History::History() { //past_.setAutoDelete(true); //future_.setAutoDelete(true); } History::~History() { for(QList::iterator it=past_.begin(); it!=past_.end(); it++) delete *it; for(QList::iterator it=future_.begin(); it!=future_.end(); it++) delete *it; } void History::add(Move *_m) { future_.clear(); past_.append(_m); } void History::clear() { past_.clear(); future_.clear(); } void History::save(QString &_str) { for(QList::Iterator iterator = past_.begin(); iterator != past_.end(); ++iterator) { (*iterator)->save(_str); } _str += '-'; for(QList::Iterator iterator = future_.begin(); iterator != future_.end(); ++iterator) { (*iterator)->save(_str); } } const char * History::load(LevelMap *map, const char *_str) { Move *m; int x = map->xpos(); int y = map->ypos(); clear(); while (*_str != '\0' && *_str != '-') { m = new Move(x, y); _str = m->load(_str); if (_str == 0) return 0; x = m->finalX(); y = m->finalY(); past_.append(m); if (!m->redo(map)) { //printf("redo failed: %s\n", _str); //abort(); return 0; } } if (*_str != '-') return 0; _str++; while (*_str != '\0') { m = new Move(x, y); _str = m->load(_str); if (_str == 0) return 0; x = m->finalX(); y = m->finalY(); future_.append(m); } return _str; } bool History::redo(LevelMap *map) { if (future_.isEmpty()) return false; Move *m=future_.takeAt(0); past_.append(m); return m->redo(map); } MoveSequence * History::deferRedo(LevelMap *map) { if (future_.isEmpty()) return 0; Move *m=future_.takeAt(0); past_.append(m); return new MoveSequence(m, map); } bool History::undo(LevelMap *map) { if (past_.isEmpty()) return false; Move *m = past_.takeAt(past_.count ()-1); future_.insert(0, m); return m->undo(map); } MoveSequence * History::deferUndo(LevelMap *map) { if (past_.isEmpty()) return 0; Move *m = past_.takeAt(past_.count()-1); future_.insert(0, m); return new MoveSequence(m, map, true); } diff --git a/History.h b/History.h index 4e13304..0bbff69 100644 --- a/History.h +++ b/History.h @@ -1,65 +1,65 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef HISTORY_H #define HISTORY_H #include #include #include "Move.h" class MoveSequence; /** * Maintains movement history * * @short Maintains game movement history * @author Anders Widell * @version 0.1 * @see PlayField */ class History { private: QList past_; QList future_; protected: public: History(); ~History(); /** * Add a move to the history. Deletes all currently undone moves. */ void add(Move *_m); /** * Clear the history and delete all Move objects stored in it. */ void clear(); void save(QString &_str); const char *load(LevelMap *map, const char *_str); bool redo(LevelMap *map); MoveSequence *deferRedo(LevelMap *map); bool undo(LevelMap *map); MoveSequence *deferUndo(LevelMap *map); }; #endif /* HISTORY_H */ diff --git a/ImageData.cpp b/ImageData.cpp index 742cdf2..493fd1a 100644 --- a/ImageData.cpp +++ b/ImageData.cpp @@ -1,216 +1,216 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include "ImageData.h" ImageData::ImageData() : floor_(10,10), indexSize_(0), size_(0), halfSize_(0) { random.setSeed(0); QPainter paint(&floor_); paint.fillRect(0,0,10,10, QColor(0x66,0x66,0x66, 255)); } ImageData::~ImageData() { } void ImageData::expandIndex(int size) { size++; assert(size < 2500); upperLargeIndex_.resize(size); lowerLargeIndex_.resize(size); leftSmallIndex_.resize(size); rightSmallIndex_.resize(size); for (int i=indexSize_; i= 0); if (indexSize_ <= index) expandIndex(index); return largeStone_xpm_[(unsigned char)upperLargeIndex_[index]]; } const QPixmap & ImageData::lowerLarge(int index) { assert(index >= 0); if (indexSize_ <= index) expandIndex(index); return largeStone_xpm_[(unsigned char)lowerLargeIndex_[index]]; } const QPixmap & ImageData::leftSmall(int index) { assert(index >= 0); if (indexSize_ <= index) expandIndex(index); return smallStone_xpm_[(unsigned char)leftSmallIndex_[index]]; } const QPixmap & ImageData::rightSmall(int index) { assert(index >= 0); if (indexSize_ <= index) expandIndex(index); return smallStone_xpm_[(unsigned char)rightSmallIndex_[index]]; } int ImageData::resize(int size) { assert(size > 0); size &= ~1u; if (size == size_) return size; size_ = size; halfSize_ = size/2; for (int i=0; i g && r > b) { // only modify redish pixels QColor col(r, g, b); QColor lcol = col.light(130); img.setPixel(x, y, lcol.rgb()); } } } } void ImageData::wall(QPainter &p, int x, int y, int index, bool left, bool right) { if (left) p.drawPixmap(x, y, upperLarge(index-1), halfSize_, 0, -1, -1); else p.drawPixmap(x, y, leftSmall(index)); if (right) p.drawPixmap(x+halfSize_, y, upperLarge(index), 0, 0, halfSize_, -1); else p.drawPixmap(x+halfSize_, y, rightSmall(index)); p.drawPixmap(x, y+halfSize_, lowerLarge(index)); } void ImageData::floor(QPainter &p, int x, int y) { //p.eraseRect(x, y, size_, size_); p.drawPixmap(x, y, floor_); } void ImageData::goal(QPainter &p, int x, int y) { p.drawPixmap(x, y, otherPixmaps_[2]); } void ImageData::man(QPainter &p, int x, int y) { p.drawPixmap(x, y, otherPixmaps_[3]); } void ImageData::object(QPainter &p, int x, int y) { p.drawPixmap(x, y, otherPixmaps_[0]); } void ImageData::saveman(QPainter &p, int x, int y) { p.drawPixmap(x, y, otherPixmaps_[4]); } void ImageData::treasure(QPainter &p, int x, int y) { p.drawPixmap(x, y, otherPixmaps_[1]); } void ImageData::brightObject(QPainter &p, int x, int y) { p.drawPixmap(x, y, brightObject_); } void ImageData::brightTreasure(QPainter &p, int x, int y) { p.drawPixmap(x, y, brightTreasure_); } diff --git a/ImageData.h b/ImageData.h index 47c7f1a..991e8df 100644 --- a/ImageData.h +++ b/ImageData.h @@ -1,87 +1,87 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IMAGEDATA_H #define IMAGEDATA_H #include #include #include class QPainter; #define SMALL_STONES 4 #define LARGE_STONES 6 #define OTHER_IMAGES 5 #define NO_OF_IMAGES (SMALL_STONES + LARGE_STONES + OTHER_IMAGES) class ImageData { public: virtual ~ImageData(); int resize(int size); int size() { return size_; } void wall(QPainter &p, int x, int y, int index, bool left, bool right); void floor(QPainter &p, int x, int y); void goal(QPainter &p, int x, int y); void man(QPainter &p, int x, int y); void object(QPainter &p, int x, int y); void saveman(QPainter &p, int x, int y); void treasure(QPainter &p, int x, int y); void brightObject(QPainter &p, int x, int y); void brightTreasure(QPainter &p, int x, int y); const QPixmap &background() { return background_; } const QImage& objectImg() const { return objectImg_; } protected: ImageData(); void expandIndex(int size); void image2pixmap(QImage img, QPixmap& xpm, bool diffuse=true); void brighten(QImage& img); const QPixmap &upperLarge(int index); const QPixmap &lowerLarge(int index); const QPixmap &leftSmall(int index); const QPixmap &rightSmall(int index); QImage images_[NO_OF_IMAGES]; QPixmap smallStone_xpm_[SMALL_STONES]; QPixmap largeStone_xpm_[LARGE_STONES]; QPixmap otherPixmaps_[OTHER_IMAGES]; QPixmap background_, brightObject_, brightTreasure_; QPixmap floor_; QImage objectImg_; int indexSize_; QByteArray upperLargeIndex_; QByteArray lowerLargeIndex_; QByteArray leftSmallIndex_; QByteArray rightSmallIndex_; int size_, halfSize_; KRandomSequence random; }; #endif /* IMAGEDATA_H */ diff --git a/InternalCollections.h b/InternalCollections.h index 56aec9e..a870e5f 100644 --- a/InternalCollections.h +++ b/InternalCollections.h @@ -1,54 +1,54 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998-2000 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef INTERNALCOLLECTIONS_H #define INTERNALCOLLECTIONS_H #include #include #include #include "LevelCollection.h" class InternalCollections { public: InternalCollections(); ~InternalCollections(); static int toInternalId(int _id) { if (_id < 10 || _id > 14) return 1000; return _id - 10; } int collections(); LevelCollection *operator[](int n); private: void add(LevelCollection* c); static int configCollection2Real(int collection); static int realCollection2Config(int collection); static QString collectionName(int _level); QVector collections_; char *data_; }; #endif /* INTERNALCOLLECTIONS_H */ diff --git a/LevelCollection.h b/LevelCollection.h index 2ff4f17..9855c27 100644 --- a/LevelCollection.h +++ b/LevelCollection.h @@ -1,66 +1,66 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998,1999 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef LEVELCOLLECTION_H #define LEVELCOLLECTION_H #include #include #include class Map; class LevelCollection { public: LevelCollection(const char *_def, int _len, const QString &_name, int _id=-1); LevelCollection(const QString &_path, const QString &_name, int _id=-1); ~LevelCollection(); const QString &name() const { return name_; } int id() const { return id_; } int level() const { return level_; } void level(int _level); void levelCompleted(); int completedLevels() const { return completedLevels_; } int noOfLevels() const { return noOfLevels_; } bool loadLevel(Map *_map); protected: void indexTextCollection(); void loadPrefs(); private: void addLevel(const char* _level); void addData(const char* _data, unsigned _len); void addSeparator(); QVector index_; QByteArray data_; //int dataLen_; int level_; int completedLevels_; int noOfLevels_; QString name_; QString path_; int id_; }; #endif /* LEVELCOLLECTION_H */ diff --git a/LevelMap.cpp b/LevelMap.cpp index d836bee..55192ea 100644 --- a/LevelMap.cpp +++ b/LevelMap.cpp @@ -1,200 +1,200 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include "LevelMap.h" #include "LevelCollection.h" #define BUFSIZE (128*1024) const QString & LevelMap::collectionName() { return collection_->name(); } LevelMap::LevelMap () : collection_(0), totalMoves_(0), totalPushes_(0), goodLevel_(false) { } LevelMap::~LevelMap () { } void LevelMap::changeCollection (LevelCollection *_collection) { collection_ = _collection; goodLevel_ = collection_->loadLevel(this); totalMoves_ = totalPushes_ = 0; } int LevelMap::level () const { if (collection_ == 0) return 0; return collection_->level(); } void LevelMap::level (int _level) { assert(collection_ != 0); collection_->level(_level); goodLevel_ = collection_->loadLevel(this); totalMoves_ = totalPushes_ = 0; } int LevelMap::noOfLevels () const { assert(collection_ != 0); return collection_->noOfLevels(); } int LevelMap::completedLevels () const{ assert(collection_ != 0); return collection_->completedLevels(); } int LevelMap::distance (int x1, int y1, int x2, int y2) { int d; if (x2 > x1) d = x2-x1; else d = x1-x2; if (y2 > y1) d += y2-y1; else d += y1-y2; return d; } bool LevelMap::step (int _x, int _y) { int oldX=xpos_, oldY=ypos_; bool success = Map::step (_x, _y); totalMoves_ += distance (oldX, oldY, xpos_, ypos_); return success; } bool LevelMap::push (int _x, int _y) { int oldX=xpos_, oldY=ypos_; bool success = Map::push (_x, _y); int d = distance (oldX, oldY, xpos_, ypos_); totalMoves_ += d; totalPushes_ += d; if (completed ()) collection_->levelCompleted(); return success; } bool LevelMap::unstep (int _x, int _y) { int oldX=xpos_, oldY=ypos_; bool success = Map::unstep (_x, _y); totalMoves_ -= distance (oldX, oldY, xpos_, ypos_); return success; } bool LevelMap::unpush (int _x, int _y) { int oldX=xpos_, oldY=ypos_; bool success = Map::unpush (_x, _y); int d = distance (oldX, oldY, xpos_, ypos_); totalMoves_ -= d; totalPushes_ -= d; return success; } #if 0 void LevelMap::random (void) { printf ("start!\n"); minX_ = 0; minY_ = 0; maxX_ = MAX_X; maxY_ = MAX_Y; totalMoves_ = totalPushes_ = 0; clearMap (); xpos_ = 13; ypos_ = 9; KRandomSequence random(0); for (int i=0; i<200; i++) { map (xpos_, ypos_, FLOOR); switch (random.getLong(4)) { case 0: if (ypos_ > 1) ypos_--; else i--; break; case 1: if (ypos_ < MAX_Y-1) ypos_++; else i--; break; case 2: if (xpos_ > 1) xpos_--; else i--; break; case 3: if (xpos_ < MAX_X-1) xpos_++; else i--; break; } } for (int y=1; y * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef LEVELMAP_H #define LEVELMAP_H #include #include #include "Map.h" class LevelCollection; //#define EXTERNAL_LEVEL 100 class LevelMap : public Map { public: LevelMap(); ~LevelMap(); LevelCollection *collection() const { return collection_; } const QString &collectionName(); void changeCollection(LevelCollection *_collection); int totalMoves() const { return totalMoves_; } int totalPushes() const { return totalPushes_; } void level(int _level); int level() const; int noOfLevels() const; int completedLevels() const; bool goodLevel() const { return goodLevel_; } bool step(int _x, int _y); bool push(int _x, int _y); bool unstep(int _x, int _y); bool unpush(int _x, int _y); //void random(); protected: LevelCollection *collection_; private: int totalMoves_; int totalPushes_; bool goodLevel_; static int distance(int x1, int y1, int x2, int y2); }; #endif /* LEVELMAP_H */ diff --git a/MainWindow.cpp b/MainWindow.cpp index 7743f1e..2471d2f 100644 --- a/MainWindow.cpp +++ b/MainWindow.cpp @@ -1,429 +1,429 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // #include #include #include #include #include //#include //#include //#include #include #include #include #include "MainWindow.h" #include "PlayField.h" #include "LevelCollection.h" #include "MainWindow.moc" void MainWindow::createCollectionMenu(QMenu* collection_) { QSignalMapper *sigmap = new QSignalMapper(this); level_act = new QAction*[internalCollections_.collections()]; for (int i=0; iname(), this); level_act[i] = qact; qact->setCheckable(true); connect(qact, SIGNAL(triggered()), sigmap, SLOT(map())); sigmap->setMapping(qact, i); collection_->addAction(qact); } connect(sigmap, SIGNAL(mapped(int)), this, SLOT(changeCollection(int))); checkedCollection_ = 0; KSharedConfigPtr cfg=KSharedConfig::openConfig(); KConfigGroup settingsGroup(cfg, "settings"); int id = settingsGroup.readEntry("collection", "10").toInt(); currentCollection_ = 0; for (int i=0; iid() == id) currentCollection_ = i; } changeCollection(currentCollection_); } MainWindow::MainWindow() : KMainWindow(0), externalCollection_(0) { int i; QPixmap pixmap; QAction *qact; //setEraseColor(QColor(0,0,0)); KSharedConfigPtr cfg=KSharedConfig::openConfig(); KConfigGroup geometryGroup(cfg, "Geometry"); int width = geometryGroup.readEntry("width", "750").toInt(); int height = geometryGroup.readEntry("height", "562").toInt(); resize(width, height); playField_ = new PlayField(this); setCentralWidget(playField_); //playField_->show(); menu_ = menuBar();// new KMenuBar(this); game_ = menu_->addMenu(i18n("&Game")); qact = new QAction(i18n("&Load Levels..."), this); connect(qact, SIGNAL(triggered()), this, SLOT(loadLevels())); game_->addAction(qact); qact = new QAction(i18n("&Next Level"), this); qact->setShortcut(Qt::Key_N); connect(qact, SIGNAL(triggered()), playField_, SLOT(nextLevel())); game_->addAction(qact); qact = new QAction(i18n("&Previous Level"), this); qact->setShortcut(Qt::Key_P); connect(qact, SIGNAL(triggered()), playField_, SLOT(previousLevel())); game_->addAction(qact); qact = new QAction(i18n("Re&start Level"), this); qact->setShortcut(Qt::Key_Escape); connect(qact, SIGNAL(triggered()), playField_, SLOT(restartLevel())); game_->addAction(qact); createCollectionMenu(game_->addMenu(i18n("&Level Collection"))); qact = new QAction(i18n("&Undo"), this); qact->setShortcut((KStandardShortcut::undo())[0]); connect(qact, SIGNAL(triggered()), playField_, SLOT(undo())); game_->addAction(qact); qact = new QAction(i18n("&Redo"), this); qact->setShortcut((KStandardShortcut::redo())[0]); connect(qact, SIGNAL(triggered()), playField_, SLOT(redo())); game_->addAction(qact); game_->addSeparator(); qact = new QAction(i18n("&Quit"), this); qact->setShortcut((KStandardShortcut::quit())[0]); connect(qact, SIGNAL(triggered()), qApp, SLOT(closeAllWindows())); game_->addAction(qact); animation_ = menu_->addMenu(i18n("&Animation")); qa_slow = new QAction(i18n("&Slow"), this); qa_slow->setCheckable(true); qa_medium = new QAction(i18n("&Medium"), this); qa_medium->setCheckable(true); qa_fast = new QAction(i18n("&Fast"), this); qa_fast->setCheckable(true); qa_off = new QAction(i18n("&Off"), this); qa_off->setCheckable(true); animation_->addAction(qa_slow); animation_->addAction(qa_medium); animation_->addAction(qa_fast); animation_->addAction(qa_off); QSignalMapper *sigmap = new QSignalMapper(this); connect(qa_slow, SIGNAL(triggered()), sigmap, SLOT(map())); sigmap->setMapping(qa_slow, 3); connect(qa_medium, SIGNAL(triggered()), sigmap, SLOT(map())); sigmap->setMapping(qa_medium, 2); connect(qa_fast, SIGNAL(triggered()), sigmap, SLOT(map())); sigmap->setMapping(qa_fast, 1); connect(qa_off, SIGNAL(triggered()), sigmap, SLOT(map())); sigmap->setMapping(qa_off, 0); connect(sigmap, SIGNAL(mapped(int)), this, SLOT(updateAnimMenu(int))); connect(sigmap, SIGNAL(mapped(int)), playField_, SLOT(changeAnim(int))); checkedAnim_ = playField_->animDelay(); updateAnimMenu(checkedAnim_); bookmarkMenu_ = menu_->addMenu(i18n("&Bookmarks")); setBM_ = bookmarkMenu_->addMenu(i18n("&Set Bookmark")); sigmap = new QSignalMapper(this); setBM_act[0] = setBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::CTRL+Qt::Key_1); setBM_act[1] = setBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::CTRL+Qt::Key_2); setBM_act[2] = setBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::CTRL+Qt::Key_3); setBM_act[3] = setBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::CTRL+Qt::Key_4); setBM_act[4] = setBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::CTRL+Qt::Key_5); setBM_act[5] = setBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::CTRL+Qt::Key_6); setBM_act[6] = setBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::CTRL+Qt::Key_7); setBM_act[7] = setBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::CTRL+Qt::Key_8); setBM_act[8] = setBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::CTRL+Qt::Key_9); setBM_act[9] = setBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::CTRL+Qt::Key_0); for(i=0; i<10; i++) { sigmap->setMapping(setBM_act[i], i+1); } connect(sigmap, SIGNAL(mapped(int)), this,SLOT(setBookmark(int))); goToBM_ = bookmarkMenu_->addMenu(i18n("&Go to Bookmark")); sigmap = new QSignalMapper(this); goToBM_act[0] = goToBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::Key_1); goToBM_act[1] = goToBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::Key_2); goToBM_act[2] = goToBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::Key_3); goToBM_act[3] = goToBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::Key_4); goToBM_act[4] = goToBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::Key_5); goToBM_act[5] = goToBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::Key_6); goToBM_act[6] = goToBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::Key_7); goToBM_act[7] = goToBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::Key_8); goToBM_act[8] = goToBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::Key_9); goToBM_act[9] = goToBM_->addAction(i18n("(unused)"), sigmap, SLOT(map()), Qt::Key_0); for(i=0; i<10; i++) { sigmap->setMapping(goToBM_act[i], i+1); } connect(sigmap, SIGNAL(mapped(int)), this,SLOT(goToBookmark(int))); for (i=1; i<=10; i++) { bookmarks_[i-1] = new Bookmark(i); updateBookmark(i); } help_ = new KHelpMenu(this, QString::null, false); menu_->addSeparator(); menu_->addMenu( help_->menu() ); menu_->show(); playField_->show(); setAcceptDrops(true); } MainWindow::~MainWindow() { KSharedConfigPtr cfg=KSharedConfig::openConfig(); KConfigGroup geometryGroup(cfg, "Geometry"); geometryGroup.writeEntry("width", QString("%1").arg(width())); geometryGroup.writeEntry("height", QString("%1").arg(height())); KConfigGroup settingsGroup(cfg, "settings"); settingsGroup.writeEntry("collection", QString("%1").arg(internalCollections_[checkedCollection_]->id())); for (int i=1; i<=10; i++) { delete bookmarks_[i-1]; } delete externalCollection_; // The following line segfaults when linked against qt 1.44 //delete help_; //delete goToBM_; //delete setBM_; //delete bookmarkMenu_; //delete animation_; //delete collection_; //delete game_; //delete menu_; //delete playField_; } void MainWindow::focusInEvent(QFocusEvent *) { playField_->setFocus(); } void MainWindow::updateAnimMenu(int id) { switch(checkedAnim_) { case 0: qa_off->setChecked(false); break; case 1: qa_fast->setChecked(false); break; case 2: qa_medium->setChecked(false); break; case 3: qa_slow->setChecked(false); break; } switch(id) { case 0: qa_off->setChecked(true); break; case 1: qa_fast->setChecked(true); break; case 2: qa_medium->setChecked(true); break; case 3: qa_slow->setChecked(true); break; } checkedAnim_ = id; } void MainWindow::updateBookmark(int num) { int col = internalCollections_.toInternalId(bookmarks_[num-1]->collection()); int lev = bookmarks_[num-1]->level(); int mov = bookmarks_[num-1]->moves(); if (col < 0 || lev < 0) return; QString name; if (col >= 0 && col < internalCollections_.collections()) name = internalCollections_[col]->name(); else name = i18n("(invalid)"); QString l; l.setNum(lev+1); name += " #" + l; l.setNum(mov); name += " (" + l + ")"; setBM_act[num-1]->setText(name); goToBM_act[num-1]->setText(name); } void MainWindow::setBookmark(int id) { assert(id >= 1 && id <= 10); playField_->setBookmark(bookmarks_[id-1]); updateBookmark(id); } void MainWindow::goToBookmark(int id) { assert(id >= 1 && id <= 10); Bookmark *bm = bookmarks_[id-1]; int collection = internalCollections_.toInternalId(bm->collection()); int level = bm->level(); if (collection < 0 || collection >= internalCollections_.collections()) return; LevelCollection* colPtr = internalCollections_[collection]; if (colPtr == 0) return; if (level < 0 || level >= colPtr->noOfLevels()) return; if (level > colPtr->completedLevels()) return; playField_->setUpdatesEnabled(false); changeCollection(collection); playField_->setUpdatesEnabled(true); playField_->goToBookmark(bookmarks_[id-1]); } void MainWindow::changeCollection(int id) { level_act[checkedCollection_]->setChecked(false); checkedCollection_ = id; level_act[checkedCollection_]->setChecked(true); delete externalCollection_; externalCollection_ = 0; playField_->changeCollection(internalCollections_[id]); } void MainWindow::loadLevels() { KSharedConfigPtr cfg=KSharedConfig::openConfig(); KConfigGroup settingsGroup(cfg, "settings"); QString lastFile = settingsGroup.readPathEntry("lastLevelFile",QString("")); QUrl result = QFileDialog::getOpenFileUrl(this, i18n("Load Levels From File"), lastFile, "*"); if (result.isEmpty()) return; openURL(result); } void MainWindow::openURL(QUrl _url) { KSharedConfigPtr cfg=KSharedConfig::openConfig(); // int namepos = _url.path().findRev('/') + 1; // NOTE: findRev can return -1 // QString levelName = _url.path().mid(namepos); QString levelName = _url.fileName(); QString levelFile; QTemporaryFile f; if (_url.isLocalFile()) { levelFile = _url.path(); } else { // levelFile = locateLocal("appdata", "levels/" + levelName); KIO::TransferJob * job = KIO::get(_url); job->exec(); if (job->error()) { return; } f.open(); QByteArray data; job->data(job, data); f.write(data); levelFile = f.fileName(); } LevelCollection *tmpCollection = new LevelCollection(levelFile, levelName); if (tmpCollection->noOfLevels() < 1) { KMessageBox::sorry(this, i18n("No levels found in file")); delete tmpCollection; return; } if (_url.isLocalFile()) { KConfigGroup settingsGroup(cfg,"settings"); settingsGroup.writePathEntry("lastLevelFile", _url.path()); } delete externalCollection_; externalCollection_ = tmpCollection; level_act[checkedCollection_]->setChecked(false); playField_->changeCollection(externalCollection_); } /* void MainWindow::dragEnterEvent(QDragEnterEvent* event) { event->accept(KURLDrag::canDecode(event)); } */ void MainWindow::dropEvent(QDropEvent* event) { QList urls = KUrlMimeData::urlsFromMimeData(event->mimeData()); if (!urls.isEmpty()) { // kdDebug() << "MainWindow:Handling QUriDrag..." << endl; if (urls.count() > 0) { const QUrl &url = urls.first(); openURL(url); } } } diff --git a/MainWindow.h b/MainWindow.h index 899f49e..a9f2787 100644 --- a/MainWindow.h +++ b/MainWindow.h @@ -1,82 +1,82 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include "Bookmark.h" #include "InternalCollections.h" class PlayField; class QMenu; class QAction; class QFocusEvent; class QDragEnterEvent; class QDropEvent; class LevelCollection; class MainWindow : public KMainWindow { Q_OBJECT public: MainWindow(); ~MainWindow(); void openURL(QUrl _url); public slots: void changeCollection(int id); void updateAnimMenu(int id); void setBookmark(int id); void goToBookmark(int id); void loadLevels(); protected: void focusInEvent(QFocusEvent*); void createCollectionMenu(QMenu* collection_); //virtual void dragEnterEvent(QDragEnterEvent*); virtual void dropEvent(QDropEvent*); private: InternalCollections internalCollections_; LevelCollection *externalCollection_; QMenuBar *menu_; PlayField *playField_; Bookmark *bookmarks_[10]; int currentCollection_; QMenu *game_; QMenu *collection_; QMenu *animation_; QMenu *bookmarkMenu_; QMenu *setBM_; QMenu *goToBM_; QAction *qa_slow, *qa_medium, *qa_fast, *qa_off, *setBM_act[10], *goToBM_act[10], **level_act; KHelpMenu *help_; int checkedCollection_; int checkedAnim_; void updateBookmark(int num); }; #endif /* MAINWINDOW_H */ diff --git a/Map.cpp b/Map.cpp index 7dbb1cf..61157be 100644 --- a/Map.cpp +++ b/Map.cpp @@ -1,204 +1,204 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include "Map.h" Map::Map() : xpos_(-1), ypos_(-1), width_(0), height_(0), objectsLeft_(-1) { } void Map::map (int x, int y, int val) { assert (x>=0 && x<=MAX_X && y>=0 && y<=MAX_Y); if ((map (x, y) & (OBJECT | GOAL)) == OBJECT) objectsLeft_--; if ((val & (OBJECT | GOAL)) == OBJECT) objectsLeft_++; currentMap_[y+1][x+1] = val; if (val != 0) { if (width_ <= x) width_ = x+1; if (height_ <= y) height_ = y+1; } } void Map::setMap (int x, int y, int bits) { assert ((map (x, y) & bits) == 0); if (goal (x, y) && ((bits & OBJECT) == OBJECT)) objectsLeft_--; assert (objectsLeft_ >= 0); currentMap_[y+1][x+1] |= bits; if (bits != 0) { if (width_ <= x) width_ = x+1; if (height_ <= y) height_ = y+1; } } void Map::clearMap (int x, int y, int bits) { assert ((map (x, y) & bits) == bits); if (goal (x, y) && ((bits & OBJECT) == OBJECT)) objectsLeft_++; currentMap_[y+1][x+1] &= ~bits; } void Map::clearMap () { memset (currentMap_, 0, (MAX_Y+3)*(MAX_X+3)*sizeof (char)); objectsLeft_ = 0; width_ = height_ = 0; } bool Map::fillFloor (int x, int y) { if (badCoords (x, y)) return false; if ((currentMap_[y+1][x+1] & (WALL|FLOOR)) != 0) return true; currentMap_[y+1][x+1] |= FLOOR; bool a = fillFloor (x, y-1); bool b = fillFloor (x, y+1); bool c = fillFloor (x-1, y); bool d = fillFloor (x+1, y); return a && b && c && d; } bool Map::step (int _x, int _y) { assert (!badCoords (xpos_, ypos_)); assert (empty (xpos_, ypos_)); int xd=0, yd=0; if (_x < xpos_) xd = -1; if (_x > xpos_) xd = 1; if (_y < ypos_) yd = -1; if (_y > ypos_) yd = 1; if (badDelta (xd, yd) || badCoords (_x, _y)) return false; int x=xpos_, y=ypos_; do { x += xd; y += yd; if (!empty (x, y)) return false; } while (!(x==_x && y==_y)); xpos_ = _x; ypos_ = _y; return true; } bool Map::push (int _x, int _y) { assert (!badCoords (xpos_, ypos_)); assert (empty (xpos_, ypos_)); int xd=0, yd=0; if (_x < xpos_) xd = -1; if (_x > xpos_) xd = 1; if (_y < ypos_) yd = -1; if (_y > ypos_) yd = 1; if (badDelta (xd, yd) || badCoords (_x+xd, _y+yd)) return false; int x=xpos_+xd, y=ypos_+yd; if (!object (x, y)) return false; if (!empty (_x+xd, _y+yd)) return false; while (!(x==_x && y==_y)) { x += xd; y += yd; if (!empty (x, y)) return false; } clearMap (xpos_+xd, ypos_+yd, OBJECT); setMap (_x+xd, _y+yd, OBJECT); xpos_ = _x; ypos_ = _y; return true; } bool Map::unstep (int _x, int _y) { return Map::step (_x, _y); } bool Map::unpush (int _x, int _y) { assert (!badCoords (xpos_, ypos_)); assert (empty (xpos_, ypos_)); int xd=0, yd=0; if (_x < xpos_) xd = -1; if (_x > xpos_) xd = 1; if (_y < ypos_) yd = -1; if (_y > ypos_) yd = 1; if (badDelta (xd, yd) || badCoords (_x+xd, _y+yd)) return false; int x=xpos_, y=ypos_; if (!object (x-xd, y-yd)) return false; do { x += xd; y += yd; if (!empty (x, y)) return false; } while (!(x==_x && y==_y)); clearMap (xpos_-xd, ypos_-yd, OBJECT); setMap (_x-xd, _y-yd, OBJECT); xpos_ = _x; ypos_ = _y; return true; } void Map::printMap(void) { for (int y=0; y", map(x,y)&FLOOR); break; } } printf ("\n"); } } diff --git a/Map.h b/Map.h index 32cd9dd..1b5ee0e 100644 --- a/Map.h +++ b/Map.h @@ -1,122 +1,122 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MAP_H #define MAP_H #include #define MAX_X 49 #define MAX_Y 49 #define WALL 1 #define GOAL 2 #define OBJECT 4 #define FLOOR 8 class Map { friend class MapDelta; friend class LevelCollection; public: Map(); bool completed () const { return objectsLeft_ <= 0; } bool step (int _x, int _y); bool push (int _x, int _y); bool unstep (int _x, int _y); bool unpush (int _x, int _y); static bool badCoords (int _x, int _y) { return _x<0 || _y<0 || _x>MAX_X || _y>MAX_Y; } static bool badDelta (int _xd, int _yd) { return (_xd!=0 && _yd!=0) || (_xd==0 && _yd==0); } int xpos () const { return xpos_; } int ypos () const { return ypos_; } bool empty (int x, int y) { assert (x>=0 && x<=MAX_X && y>=0 && y<=MAX_Y); return (currentMap_[y+1][x+1] & (WALL|OBJECT)) == 0; } bool wall (int x, int y) { assert (x>=0 && x<=MAX_X && y>=0 && y<=MAX_Y); return (currentMap_[y+1][x+1] & WALL) != 0; } bool goal (int x, int y) { assert (x>=0 && x<=MAX_X && y>=0 && y<=MAX_Y); return (currentMap_[y+1][x+1] & GOAL) != 0; } bool object (int x, int y) { assert (x>=0 && x<=MAX_X && y>=0 && y<=MAX_Y); return (currentMap_[y+1][x+1] & OBJECT) != 0; } bool floor (int x, int y) { assert (x>=0 && x<=MAX_X && y>=0 && y<=MAX_Y); return (currentMap_[y+1][x+1] & FLOOR) != 0; } bool wallUp (int x, int y) { assert (x>=0 && x<=MAX_X && y>=0 && y<=MAX_Y); return (currentMap_[y ][x+1] & WALL) != 0; } bool wallDown (int x, int y) { assert (x>=0 && x<=MAX_X && y>=0 && y<=MAX_Y); return (currentMap_[y+2][x+1] & WALL) != 0; } bool wallLeft (int x, int y) { assert (x>=0 && x<=MAX_X && y>=0 && y<=MAX_Y); return (currentMap_[y+1][x ] & WALL) != 0; } bool wallRight (int x, int y) { assert (x>=0 && x<=MAX_X && y>=0 && y<=MAX_Y); return (currentMap_[y+1][x+2] & WALL) != 0; } void printMap (); int width() const { return width_; } int height() const { return height_; } protected: int map (int x, int y) { assert (x>=0 && x<=MAX_X && y>=0 && y<=MAX_Y); return currentMap_[y+1][x+1]; } void map (int x, int y, int val); void setMap (int x, int y, int bits); void clearMap (int x, int y, int bits); void clearMap (); bool fillFloor (int x, int y); int objectsLeft () const { return objectsLeft_; } int xpos_, ypos_; private: char currentMap_[MAX_Y+3][MAX_X+3]; int width_, height_; int objectsLeft_; }; #endif /* MAP_H */ diff --git a/MapDelta.cpp b/MapDelta.cpp index bbf16ff..a283090 100644 --- a/MapDelta.cpp +++ b/MapDelta.cpp @@ -1,63 +1,63 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "MapDelta.h" MapDelta::MapDelta (Map *m) { source_ = m; ended_ = true; start (); } void MapDelta::start () { assert (ended_); ((Map &) *this) = *source_; #if 0 memcpy (map_, source_->currentMap_, (MAX_Y+3)*(MAX_X+3)*sizeof (int)); for (int y=1; ycurrentMap_[y][x]; } } xpos_ = source_->xpos_; ypos_ = source_->ypos_; #endif ended_ = false; } void MapDelta::end () { assert (!ended_); for (int y=0; y<=MAX_Y; y++) { for (int x=0; x<=MAX_X; x++) { map (x, y, map (x, y) != source_->map (x, y)); } } if (xpos_ != source_->xpos_ || ypos_ != source_->ypos_) { map (xpos_, ypos_, 1); map (source_->xpos_, source_->ypos_, 1); } ended_ = true; } diff --git a/MapDelta.h b/MapDelta.h index c4e6763..5617f83 100644 --- a/MapDelta.h +++ b/MapDelta.h @@ -1,44 +1,44 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MAPDELTA_H #define MAPDELTA_H #include #include "Map.h" class MapDelta : private Map { public: MapDelta (Map *m); void start (); void end (); bool hasChanged (int x, int y) { assert (ended_); return map (x, y) == 1; } private: Map *source_; bool ended_; }; #endif /* MAPDELTA_H */ diff --git a/ModalLabel.cpp b/ModalLabel.cpp index 44223e3..410666d 100644 --- a/ModalLabel.cpp +++ b/ModalLabel.cpp @@ -1,111 +1,111 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include "ModalLabel.h" #include "ModalLabel.moc" ModalLabel::ModalLabel(const QString &text, QWidget *parent, Qt::WindowFlags f) : QLabel(text, parent, f) { QFont font(QFontDatabase::systemFont(QFontDatabase::GeneralFont).family(), 24, QFont::Bold); QFontMetrics fontMet(font); setAutoFillBackground(true); QString currentLine; QRect bounds; int lineLen, width=0, height=0; for (int linePos=0; linePos < (int) text.length(); linePos += lineLen+1) { lineLen = text.indexOf('\n', linePos); if (lineLen < 0) lineLen = text.length() - linePos; else lineLen -= linePos; currentLine = text.mid(linePos, lineLen); bounds = fontMet.boundingRect(currentLine); if (bounds.width() > width) width = bounds.width(); height += bounds.height(); } width += 32; height += 32; if (width < 300) width = 300; if (height < 75) height = 75; setAlignment (Qt::AlignCenter); setFrameStyle (QFrame::Panel | QFrame::Raised); setLineWidth (4); setFont (font); move (parent->width ()/2 - width/2, parent->height ()/2 - height/2); resize (width, height); show (); QWidgetList list = QApplication::allWidgets(); for(QWidgetList::Iterator it=list.begin(); it!=list.end(); it++) { (*it)->installEventFilter (this); } completed_ = false; startTimer (1000); } void ModalLabel::timerEvent (QTimerEvent *) { completed_ = true; } bool ModalLabel::eventFilter (QObject *, QEvent *e) { switch (e->type()) { case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: case QEvent::MouseMove: case QEvent::KeyPress: case QEvent::KeyRelease: //case QEvent::Accel: //case QEvent::DragEnter: case QEvent::DragMove: case QEvent::DragLeave: case QEvent::Drop: //case QEvent::DragResponse: //kdDebug << "Ate event" << endl; return true; break; default: return false; } } void ModalLabel::message (const QString &text, QWidget *parent) { QApplication *app = qApp; ModalLabel cl (text, parent); while (!cl.completed_) app->processEvents (); } diff --git a/ModalLabel.h b/ModalLabel.h index 725006f..13859d7 100644 --- a/ModalLabel.h +++ b/ModalLabel.h @@ -1,39 +1,39 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MODALLABEL_H #define MODALLABEL_H #include class ModalLabel : public QLabel { Q_OBJECT public: static void message (const QString &text, QWidget *parent); void timerEvent (QTimerEvent *); bool eventFilter (QObject *, QEvent *); bool completed_; protected: ModalLabel (const QString &text, QWidget *parent, Qt::WindowFlags f=0); }; #endif /* MODALLABEL_H */ diff --git a/Move.cpp b/Move.cpp index 2277377..83ceb85 100644 --- a/Move.cpp +++ b/Move.cpp @@ -1,213 +1,213 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "Move.h" #include "LevelMap.h" Move::Move (int _startX, int _startY) { assert (_startX>=0 && _startX<=MAX_X && _startY>=0 && _startY<=MAX_Y); moves_ = new unsigned short[400]; moves_[0] = _startX | (_startY<<8); moveIndex_ = 1; finished_ = false; #ifndef NDEBUG lastX_ = _startX; lastY_ = _startY; #endif } Move::~Move () { delete [] moves_; } void Move::finish () { assert (!finished_); assert (moveIndex_ > 1); unsigned short *newMoves = new unsigned short[moveIndex_]; memcpy (newMoves, moves_, moveIndex_*sizeof (unsigned short)); delete [] moves_; moves_ = newMoves; finished_ = true; } void Move::save (QString &s) { static const char move1[] = "lrud"; static const char push1[] = "LRUD"; static const char move2[] = "wens"; static const char push2[] = "WENS"; assert (finished_); int x=startX (); int y=startY (); int pos=1; int x2, y2, dist=0; int dir=-1; bool push=false; while (pos= 0) s += push ? push1[dir] : move1[dir]; x2 = moves_[pos]&0x7f; y2 = (moves_[pos]>>8)&0x7f; push = (moves_[pos++]&0x80)==0x80; if (x2x) { dir = 1; dist = x2-x; } else if (y2y) { dir = 3; dist = y2-y; } else { assert (0); } assert (dist > 0); if (dist > 1) { if (dist>=10) { s += '0' + (dist/10); dist %= 10; } s += '0' + dist; } x = x2; y = y2; } if (dir >= 0) s += push ? push2[dir] : move2[dir]; } const char * Move::load (const char *s) { assert (!finished_); int x=finalX (); int y=finalY (); int dist; bool last=false; char c; while ((c = *s++) != '\0') { dist = 1; if (c >= '0' && c <= '9') { dist = c - '0'; c = *s++; if (c >= '0' && c <= '9') { dist = 10*dist + c - '0'; c = *s++; } } switch (tolower (c)) { case 'w': last = true; case 'l': x -= dist; break; case 'e': last = true; case 'r': x += dist; break; case 'n': last = true; case 'u': y -= dist; break; case 's': last = true; case 'd': y += dist; break; default: //printf ("2><>%s\n", s); //abort (); return 0; } if (x<=0 || x>=MAX_X || y<=0 || y>=MAX_Y) { //printf ("x: %d, y:%d ><>%s\n", x, y, s); //abort (); return 0; } if (isupper (c)) push (x, y); else step (x, y); if (last) break; } finish (); return s; } bool Move::redo (LevelMap *map) { assert (finished_); for (int pos=1; pos>8)&0x7f; bool push = (moves_[pos]&0x80)==0x80; bool ret; if (push) ret = map->push (x, y); else ret = map->step (x, y); if (!ret) return false; } return true; } bool Move::undo (LevelMap *map) { assert (finished_); for (int pos=moveIndex_-2; pos>=0; --pos) { int x = moves_[pos]&0x7f; int y = (moves_[pos]>>8)&0x7f; bool push = (moves_[pos+1]&0x80)==0x80; bool ret; if (push) ret = map->unpush (x, y); else ret = map->unstep (x, y); if (!ret) return false; } return true; } diff --git a/Move.h b/Move.h index 3b68ca5..62954af 100644 --- a/Move.h +++ b/Move.h @@ -1,115 +1,115 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MOVE_H #define MOVE_H #include #include #include "Map.h" class LevelMap; /** * Holds information about a move * * The move can consist of several atomic steps and pushes. An atomic * step/push is a step/push along a straight line. The reason why these are * grouped together in a Move object is that they belong to the same logical * move in the player's point of view. An undo/redo will undo/redo all the * atomic moves in one step. * * @short Maintains game movement move * @author Anders Widell * @version 0.1 * @see History */ class Move { friend class MoveSequence; private: unsigned short *moves_; int moveIndex_; bool finished_; #ifndef NDEBUG int lastX_, lastY_; #endif public: Move (int _startX, int _startY); ~Move (); /** * Add an atomic move. * NOTE: either (x != (previous x)) or (y != (previous y)) * must be true (but not both). * * @see LevelMap#move * * @param x x position of destination * @param y y position of destination */ void step (int _x, int _y) { #ifndef NDEBUG assert (!finished_); assert (_x>=0 && _x<=MAX_X && _y>=0 && _y<=MAX_Y); assert (moveIndex_ < 400); assert ((_x!=lastX_ && _y==lastY_) || (_x==lastX_ && _y!=lastY_)); lastX_ = _x; lastY_ = _y; #endif moves_[moveIndex_++] = _x | (_y<<8); } /** * Same as move above, but used when an object is pushed. * * @see LevelMap#push */ void push (int _x, int _y) { #ifndef NDEBUG assert (!finished_); assert (_x>=0 && _x<=MAX_X && _y>=0 && _y<=MAX_Y); assert (moveIndex_ < 400); assert ((_x!=lastX_ && _y==lastY_) || (_x==lastX_ && _y!=lastY_)); lastX_ = _x; lastY_ = _y; #endif moves_[moveIndex_++] = _x | (_y<<8) | 0x80; } void finish (); int startX () const { return moves_[0]&0x7f; } int startY () const { return (moves_[0]>>8)&0x7f; } int finalX () const { return moves_[moveIndex_-1]&0x7f; } int finalY () const { return (moves_[moveIndex_-1]>>8)&0x7f; } void save (QString &_str); const char *load (const char *_str); bool redo (LevelMap *map); bool undo (LevelMap *map); }; #endif /* MOVE_H */ diff --git a/MoveSequence.cpp b/MoveSequence.cpp index b5a5c82..23618c4 100644 --- a/MoveSequence.cpp +++ b/MoveSequence.cpp @@ -1,81 +1,81 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "MoveSequence.h" #include "LevelMap.h" #include "Move.h" MoveSequence::MoveSequence (Move *_move, LevelMap *_map, bool _undo) { assert (_move->finished_); move_ = _move; map_ = _map; undo_ = _undo; if (undo_) { pos_ = move_->moveIndex_-2; xDest_ = x_ = move_->moves_[move_->moveIndex_-1]&0x7f; yDest_ = y_ = (move_->moves_[move_->moveIndex_-1]>>8)&0x7f; } else { pos_ = 1; xDest_ = x_ = move_->moves_[0]&0x7f; yDest_ = y_ = (move_->moves_[0]>>8)&0x7f; } newStep (); } bool MoveSequence::newStep () { if (pos_>=move_->moveIndex_ || pos_<0) return false; xDest_ = move_->moves_[pos_]&0x7f; yDest_ = (move_->moves_[pos_]>>8)&0x7f; if (undo_) push_ = (move_->moves_[pos_+1]&0x80)==0x80; else push_ = (move_->moves_[pos_]&0x80)==0x80; xd_ = yd_ = 0; if (xDest_ < x_) xd_ = -1; if (xDest_ > x_) xd_ = 1; if (yDest_ < y_) yd_ = -1; if (yDest_ > y_) yd_ = 1; if (undo_) pos_--; else pos_++; return true; } bool MoveSequence::next () { if (x_ == xDest_ && y_ == yDest_ && !newStep ()) return false; x_ += xd_; y_ += yd_; if (undo_) { if (push_) return map_->unpush (x_, y_); else return map_->unstep (x_, y_); } else { if (push_) return map_->push (x_, y_); else return map_->step (x_, y_); } } diff --git a/MoveSequence.h b/MoveSequence.h index 14cf5ac..af64286 100644 --- a/MoveSequence.h +++ b/MoveSequence.h @@ -1,45 +1,45 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MOVESEQUENCE_H #define MOVESEQUENCE_H #include class Move; class LevelMap; class MoveSequence { public: MoveSequence (Move *_move, LevelMap *_map, bool _undo=false); bool newStep (); bool next (); private: LevelMap *map_; Move *move_; int pos_; int x_, xDest_, y_, yDest_, xd_, yd_; bool push_; bool undo_; }; #endif /* MOVESEQUENCE_H */ diff --git a/PathFinder.cpp b/PathFinder.cpp index a7d8bd4..12b05d2 100644 --- a/PathFinder.cpp +++ b/PathFinder.cpp @@ -1,176 +1,176 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //#include #include "PathFinder.h" #include "LevelMap.h" #include "Queue.h" #include "Move.h" void PathFinder::BFS (int _x, int _y) { Queue xq; Queue yq; Queue dq; int x, y, d; xq.enqueue (_x); yq.enqueue (_y); dq.enqueue (1); while (!xq.empty ()) { x = xq.dequeue (); y = yq.dequeue (); d = dq.dequeue (); if (x<0 || x>MAX_X || y<0 || y>MAX_Y || dist[y][x]) continue; dist[y][x] = d; xq.enqueue (x); xq.enqueue (x); xq.enqueue (x-1); xq.enqueue (x+1); yq.enqueue (y-1); yq.enqueue (y+1); yq.enqueue (y); yq.enqueue (y); dq.enqueue (d+1); dq.enqueue (d+1); dq.enqueue (d+1); dq.enqueue (d+1); } } Move * PathFinder::search (Map *_map, int _x, int _y) { int xpos=_map->xpos (); int ypos=_map->ypos (); if (xpos == _x && ypos == _y) return 0; for (int y=0; y<=MAX_Y; y++) { for (int x=0; x<=MAX_X; x++) { if (_map->empty (x, y)) dist[y][x] = 0; else dist[y][x] = PATH_WALL; } } BFS (_x, _y); #if 0 for (int y=0; y<=MAX_Y; y++) { for (int x=0; x<=MAX_X; x++) { //if (x==_x && y==_y) {printf ("++ "); continue;} //if (x==xpos && y==ypos) {printf ("@@ "); continue;} if (dist[y][x] == PATH_WALL) {printf ("## "); continue;} printf ("%02d ", dist[y][x]); } printf ("\n"); } #endif int d; Move *move=new Move (xpos, ypos); int oldX, oldY; for (;;) { oldX = xpos; oldY = ypos; if (xpos == _x && ypos == _y) { move->finish (); //printf ("move->finish ()\n"); return move; } d = dist[ypos][xpos]; while (ypos-1 >= 0 && dist[ypos-1][xpos] < d) { ypos--; d = dist[ypos][xpos]; } if (oldY != ypos) { move->step (xpos, ypos); //printf ("step (%d, %d)\n", xpos, ypos); continue; } while (ypos+1 <= MAX_Y && dist[ypos+1][xpos] < d) { ypos++; d = dist[ypos][xpos]; } if (oldY != ypos) { move->step (xpos, ypos); //printf ("step (%d, %d)\n", xpos, ypos); continue; } while (xpos-1 >= 0 && dist[ypos][xpos-1] < d) { xpos--; d = dist[ypos][xpos]; } if (oldX != xpos) { move->step (xpos, ypos); //printf ("step (%d, %d)\n", xpos, ypos); continue; } while (xpos+1 <= MAX_X && dist[ypos][xpos+1] < d) { xpos++; d = dist[ypos][xpos]; } if (oldX != xpos) { move->step (xpos, ypos); //printf ("step (%d, %d)\n", xpos, ypos); continue; } delete move; return 0; } } Move* PathFinder::drag(int /* x1 */, int /* y1 */, int /* x2 */, int /* y2 */) { return 0; } bool PathFinder::canDrag(int /* x */, int /* y */) const { return false; } bool PathFinder::canWalkTo(int /* x */, int /* y */) const { return false; } bool PathFinder::canDragTo(int /* x */, int /* y */) const { return false; } void PathFinder::updatePossibleMoves() { } void PathFinder::updatePossibleDestinations(int /* x */, int /* y */) { } diff --git a/PathFinder.h b/PathFinder.h index 6318781..b9020af 100644 --- a/PathFinder.h +++ b/PathFinder.h @@ -1,48 +1,48 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef PATHFINDER_H #define PATHFINDER_H #include "Map.h" class Move; #define PATH_WALL 32767 class PathFinder { public: Move *search (Map *_map, int _x, int _y); Move* drag(int x1, int y1, int x2, int y2); bool canDrag(int x, int y) const; bool canWalkTo(int x, int y) const; bool canDragTo(int x, int y) const; void updatePossibleMoves(); void updatePossibleDestinations(int x, int y); protected: //static const int PATH_WALL=32767; int dist[MAX_Y+1][MAX_X+1]; void BFS (int _x, int _y); }; #endif /* PATHFINDER_H */ diff --git a/PlayField.cpp b/PlayField.cpp index 1b94224..22b5cb4 100644 --- a/PlayField.cpp +++ b/PlayField.cpp @@ -1,994 +1,994 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "PlayField.h" #include "ModalLabel.h" #include "LevelMap.h" #include "Move.h" #include "History.h" #include "PathFinder.h" #include "MapDelta.h" #include "MoveSequence.h" #include "StaticImage.h" #include "HtmlPrinter.h" #include "Bookmark.h" #include "LevelCollection.h" #include "PlayField.moc" PlayField::PlayField(QWidget *parent) : QWidget(parent), imageData_(0), lastLevel_(-1), moveSequence_(0), moveInProgress_(false), dragInProgress_(false), xOffs_(0), yOffs_(0), wheelDelta_(0), debug_counter(0), sizeAllCursor(Qt::SizeAllCursor), crossCursor(Qt::CrossCursor), levelText_(i18n("Level:")), stepsText_(i18n("Steps:")), pushesText_(i18n("Pushes:")), pnumXpm_(NULL), ptxtXpm_(NULL), snumXpm_(NULL), stxtXpm_(NULL), lnumXpm_(NULL), ltxtXpm_(NULL), collXpm_(NULL), statusFont_(QFontDatabase::systemFont(QFontDatabase::GeneralFont).family(), 18, QFont::Bold), statusMetrics_(statusFont_) { //setAttribute(Qt::WA_PaintOutsidePaintEvent); setFocusPolicy(Qt::StrongFocus); setFocus(); setMouseTracking(true); highlightX_ = highlightY_ = 0; KSharedConfigPtr cfg = KSharedConfig::openConfig(); KConfigGroup settingsGroup(cfg, "settings"); imageData_ = new StaticImage; animDelay_ = settingsGroup.readEntry("animDelay", QString("2")).toInt(); if (animDelay_ < 0 || animDelay_ > 3) animDelay_ = 2; history_ = new History; background_.setTexture(imageData_->background()); //floor_ = QColor(0x66,0x66,0x66, 255); levelMap_ = new LevelMap; mapDelta_ = new MapDelta(levelMap_); mapDelta_->end(); levelChange(); } PlayField::~PlayField() { KSharedConfigPtr cfg = KSharedConfig::openConfig(); KConfigGroup settingsGroup(cfg, "settings"); settingsGroup.writeEntry("animDelay", QString("%1").arg(animDelay_)); delete mapDelta_; delete history_; delete levelMap_; delete imageData_; if(ltxtXpm_) delete ltxtXpm_; if(lnumXpm_) delete lnumXpm_; if(stxtXpm_) delete stxtXpm_; if(snumXpm_) delete snumXpm_; if(ptxtXpm_) delete ptxtXpm_; if(pnumXpm_) delete pnumXpm_; if(collXpm_) delete collXpm_; } void PlayField::changeCursor(const QCursor* c) { if (cursor_ == c) return; cursor_ = c; if (c == 0) unsetCursor(); else setCursor(*c); } int PlayField::level() const { if (levelMap_ == 0) return 0; return levelMap_->level(); } const QString & PlayField::collectionName() { static QString error = "????"; if (levelMap_ == 0) return error; return levelMap_->collectionName(); } int PlayField::totalMoves() const { if (levelMap_ == 0) return 0; return levelMap_->totalMoves(); } int PlayField::totalPushes() const{ if (levelMap_ == 0) return 0; return levelMap_->totalPushes(); } void PlayField::levelChange() { stopMoving(); stopDrag(); history_->clear(); setSize(width(), height()); updateLevelXpm(); updateStepsXpm(); updatePushesXpm(); highlight(); } void PlayField::paintSquare(int x, int y, QPainter &paint) { if (levelMap_->xpos() == x && levelMap_->ypos() == y) { if (levelMap_->goal(x, y)) imageData_->saveman(paint, x2pixel(x), y2pixel(y)); else { imageData_->man(paint, x2pixel(x), y2pixel(y)); //printf("imageData_->man() %d; %d\n",x2pixel(x), y2pixel(y)); } return; } if (levelMap_->empty(x, y)) { if (levelMap_->floor(x, y)) { if (levelMap_->goal(x, y)) imageData_->goal(paint, x2pixel(x), y2pixel(y)); else{ //paint.fillRect(x2pixel(x), y2pixel(y), size_, size_, floor_); imageData_->floor(paint, x2pixel(x), y2pixel(y)); //printf("executing paint.fillRect(): %d; %d,%d,%d,%d\n",++debug_counter, x2pixel(x), y2pixel(y), size_, size_); } } else { paint.fillRect(x2pixel(x), y2pixel(y), size_, size_, background_); } return; } if (levelMap_->wall(x, y)) { imageData_->wall(paint, x2pixel(x), y2pixel(y), x+y*(MAX_X+1), levelMap_->wallLeft(x, y), levelMap_->wallRight(x, y)); return; } if (levelMap_->object(x, y)) { if (highlightX_ == x && highlightY_ == y) { if (levelMap_->goal(x, y)) imageData_->brightTreasure(paint, x2pixel(x), y2pixel(y)); else imageData_->brightObject(paint, x2pixel(x), y2pixel(y)); } else { if (levelMap_->goal(x, y)) imageData_->treasure(paint, x2pixel(x), y2pixel(y)); else imageData_->object(paint, x2pixel(x), y2pixel(y)); } return; } } void PlayField::paintDelta() { repaint(); } void PlayField::paintEvent(QPaintEvent *e) { QPainter paint; paint.begin(this); // the following line is a workaround for a bug in Qt 2.0.1 // (and possibly earlier versions) paint.setBrushOrigin(0, 0); paint.setClipRegion(e->region()); paint.setClipping(true); paintPainter(paint, e->rect()); paint.end(); } void PlayField::paintPainterClip(QPainter &paint, int x, int y, int w, int h) { QRect rect(x, y, w, h); paint.setClipRect(rect); paint.setClipping(true); paintPainter(paint, rect); } void PlayField::paintPainter(QPainter &paint, const QRect &rect) { if (size_ <= 0) return; int minx = pixel2x(rect.x()); int miny = pixel2y(rect.y()); int maxx = pixel2x(rect.x()+rect.width()-1); int maxy = pixel2y(rect.y()+rect.height()-1); if (minx < 0) minx = 0; if (miny < 0) miny = 0; if (maxx >= levelMap_->width()) maxx = levelMap_->width()-1; if (maxy >= levelMap_->height()) maxy = levelMap_->height()-1; { int x1, x2, y1, y2; y1 = y2pixel(miny); if (y1 > rect.y()) paint.fillRect(rect.x(), rect.y(), rect.width(), y1-rect.y(), background_); int bot=rect.y()+rect.height(); if (bot > height()-collRect_.height()) bot = height()-collRect_.height(); y2 = y2pixel(maxy+1); if (y2 < bot) paint.fillRect(rect.x(), y2, rect.width(), bot-y2, background_); x1 = x2pixel(minx); if (x1 > rect.x()) paint.fillRect(rect.x(), y1, x1-rect.x(), y2-y1, background_); x2 = x2pixel(maxx+1); if (x2 < rect.x()+rect.width()) paint.fillRect(x2, y1, rect.x()+rect.width()-x2, y2-y1, background_); // paint.eraseRect } for (int y=miny; y<=maxy; y++) { for (int x=minx; x<=maxx; x++) { paintSquare(x, y, paint); } } if (collRect_.intersects(rect) && collXpm_) paint.drawPixmap(collRect_.x(), collRect_.y(), *collXpm_); if (ltxtRect_.intersects(rect) && ltxtXpm_) paint.drawPixmap(ltxtRect_.x(), ltxtRect_.y(), *ltxtXpm_); if (lnumRect_.intersects(rect) && lnumXpm_) paint.drawPixmap(lnumRect_.x(), lnumRect_.y(), *lnumXpm_); if (stxtRect_.intersects(rect) && stxtXpm_) paint.drawPixmap(stxtRect_.x(), stxtRect_.y(), *stxtXpm_); if (snumRect_.intersects(rect) && snumXpm_) paint.drawPixmap(snumRect_.x(), snumRect_.y(), *snumXpm_); if (ptxtRect_.intersects(rect) && ptxtXpm_) paint.drawPixmap(ptxtRect_.x(), ptxtRect_.y(), *ptxtXpm_); if (pnumRect_.intersects(rect) && pnumXpm_) paint.drawPixmap(pnumRect_.x(), pnumRect_.y(), *pnumXpm_); } void PlayField::resizeEvent(QResizeEvent *e) { setSize(e->size().width(), e->size().height()); } void PlayField::mouseMoveEvent(QMouseEvent *e) { lastMouseXPos_ = e->x(); lastMouseYPos_ = e->y(); if (!dragInProgress_) return highlight(); int old_x = dragX_, old_y = dragY_; dragX_ = lastMouseXPos_ - mousePosX_; dragY_ = lastMouseYPos_ - mousePosY_; { int x = pixel2x(dragX_ + size_/2); int y = pixel2y(dragY_ + size_/2); if (x >= 0 && x < levelMap_->width() && y >= 0 && y < levelMap_->height() && pathFinder_.canDragTo(x, y)) { x = x2pixel(x); y = y2pixel(y); if (dragX_ >= x - size_/4 && dragX_ < x + size_/4 && dragY_ >= y - size_/4 && dragY_ < y + size_/4) { dragX_ = x; dragY_ = y; } } } if (dragX_ == old_x && dragY_ == old_y) return; repaint(); } void PlayField::highlight() { // FIXME: the line below should not be needed if (size_ == 0) return; int x=pixel2x(lastMouseXPos_); int y=pixel2y(lastMouseYPos_); if (x < 0 || y < 0 || x >= levelMap_->width() || y >= levelMap_->height()) return; if (x == highlightX_ && y == highlightY_) return; if (pathFinder_.canDrag(x, y)) { highlightX_ = x; highlightY_ = y; repaint(); } else { if (pathFinder_.canWalkTo(x, y)) changeCursor(&crossCursor); else changeCursor(0); if (highlightX_ >= 0) { repaint(); } } } void PlayField::stopMoving() { killTimers(); delete moveSequence_; moveSequence_ = 0; moveInProgress_ = false; updateStepsXpm(); updatePushesXpm(); repaint(); pathFinder_.updatePossibleMoves(); } void PlayField::startMoving(Move *m) { startMoving(new MoveSequence(m, levelMap_)); } void PlayField::startMoving(MoveSequence *ms) { static const int delay[4] = {0, 15, 35, 60}; assert(moveSequence_ == 0 && !moveInProgress_); moveSequence_ = ms; moveInProgress_ = true; if (animDelay_) timers.append(startTimer(delay[animDelay_])); timerEvent(0); } void PlayField::timerEvent(QTimerEvent *) { assert(moveInProgress_); if (moveSequence_ == 0) { killTimers(); moveInProgress_ = false; return; } bool more=false; mapDelta_->start(); if (animDelay_) more = moveSequence_->next(); else { while (moveSequence_->next()) if (levelMap_->completed()) break; more = true; // FIXME: clean this up stopMoving(); } mapDelta_->end(); if (more) { paintDelta(); if (levelMap_->completed()) { stopMoving(); ModalLabel::message(i18n("Level completed"), this); nextLevel(); return; } } else stopMoving(); } void PlayField::step(int _x, int _y) { if (!canMoveNow()) return; int oldX=levelMap_->xpos(); int oldY=levelMap_->ypos(); int x=oldX, y=oldY; int dx=0, dy=0; if (_x>oldX) dx=1; if (_xoldY) dy=1; if (_ystep(x+dx, y+dy)) { x += dx; y += dy; } if (x!=oldX || y!=oldY) { Move *m = new Move(oldX, oldY); m->step(x, y); m->finish(); history_->add(m); m->undo(levelMap_); startMoving(m); } } void PlayField::push(int _x, int _y) { if (!canMoveNow()) return; int oldX=levelMap_->xpos(); int oldY=levelMap_->ypos(); int x=oldX, y=oldY; int dx=0, dy=0; if (_x>oldX) dx=1; if (_xoldY) dy=1; if (_ystep(x+dx, y+dy)) { x += dx; y += dy; } int objX=x, objY=y; while (!(x==_x && y==_y) && levelMap_->push(x+dx, y+dy)) { x += dx; y += dy; } if (x!=oldX || y!=oldY) { Move *m = new Move(oldX, oldY); if (objX!=oldX || objY!=oldY) m->step(objX, objY); if (objX!=x || objY!=y) { m->push(x, y); objX += dx; objY += dy; } m->finish(); history_->add(m); m->undo(levelMap_); startMoving(m); } } void PlayField::keyPressEvent(QKeyEvent * e) { int x=levelMap_->xpos(); int y=levelMap_->ypos(); switch (e->key()) { case Qt::Key_Up: if (e->modifiers() & Qt::ControlModifier) step(x, 0); else if (e->modifiers() & Qt::ShiftModifier) push(x, 0); else push(x, y-1); break; case Qt::Key_Down: if (e->modifiers() & Qt::ControlModifier) step(x, MAX_Y); else if (e->modifiers() & Qt::ShiftModifier) push(x, MAX_Y); else push(x, y+1); break; case Qt::Key_Left: if (e->modifiers() & Qt::ControlModifier) step(0, y); else if (e->modifiers() & Qt::ShiftModifier) push(0, y); else push(x-1, y); break; case Qt::Key_Right: if (e->modifiers() & Qt::ControlModifier) step(MAX_X, y); else if (e->modifiers() & Qt::ShiftModifier) push(MAX_X, y); else push(x+1, y); break; case Qt::Key_Q: qApp->closeAllWindows(); break; case Qt::Key_Backspace: case Qt::Key_Delete: if (e->modifiers() & Qt::ControlModifier) redo(); else undo(); break; #if 0 case Qt::Key_X: levelMap_->random(); levelChange(); repaint(false); break; case Qt::Key_R: level(levelMap_->level()); return; break; case Qt::Key_N: nextLevel(); return; break; case Qt::Key_P: previousLevel(); return; break; case Qt::Key_U: undo(); return; break; case Qt::Key_I: history_->redo(levelMap_); repaint(false); return; break; case Qt::Key_S: { QString buf; history_->save(buf); printf("%s\n", (char *) buf); } return; break; case Qt::Key_L: stopMoving(); history_->clear(); level(levelMap_->level()); { char buf[4096]="r1*D1*D1*r1*@r1*D1*"; //scanf("%s", buf); history_->load(levelMap_, buf); } updateStepsXpm(); updatePushesXpm(); repaint(false); return; break; #endif case Qt::Key_Print: HtmlPrinter::printHtml(levelMap_); break; default: e->ignore(); return; break; } } void PlayField::stopDrag() { if (!dragInProgress_) return; changeCursor(0); repaint(); dragInProgress_ = false; } void PlayField::dragObject(int xpixel, int ypixel) { int x=pixel2x(xpixel - mousePosX_ + size_/2); int y=pixel2y(ypixel - mousePosY_ + size_/2); if (x == highlightX_ && y == highlightY_) return; printf("drag %d,%d to %d,%d\n", highlightX_, highlightY_, x, y); pathFinder_.drag(highlightX_, highlightY_, x, y); stopDrag(); } void PlayField::mousePressEvent(QMouseEvent *e) { if (!canMoveNow()) return; if (dragInProgress_) { if (e->button() == Qt::LeftButton) dragObject(e->x(), e->y()); else stopDrag(); return; } int x=pixel2x(e->x()); int y=pixel2y(e->y()); if (x < 0 || y < 0 || x >= levelMap_->width() || y >= levelMap_->height()) return; if (e->button() == Qt::LeftButton && pathFinder_.canDrag(x, y)) { repaint(); highlightX_ = x; highlightY_ = y; pathFinder_.updatePossibleDestinations(x, y); dragX_ = x2pixel(x); dragY_ = y2pixel(y); mousePosX_ = e->x() - dragX_; mousePosY_ = e->y() - dragY_; dragInProgress_ = true; } Move *m; switch (e->button()) { case Qt::LeftButton: m = pathFinder_.search(levelMap_, x, y); if (m != 0) { history_->add(m); startMoving(m); } break; case Qt::MidButton: undo(); return; break; case Qt::RightButton: push(x, y); break; default: return; } } void PlayField::wheelEvent(QWheelEvent *e) { wheelDelta_ += e->delta(); if (wheelDelta_ >= 120) { wheelDelta_ %= 120; redo(); } else if (wheelDelta_ <= -120) { wheelDelta_ = -(-wheelDelta_ % 120); undo(); } } void PlayField::mouseReleaseEvent(QMouseEvent *e) { if (dragInProgress_) dragObject(e->x(), e->y()); } void PlayField::focusInEvent(QFocusEvent *) { //printf("PlayField::focusInEvent\n"); } void PlayField::focusOutEvent(QFocusEvent *) { //printf("PlayField::focusOutEvent\n"); } void PlayField::leaveEvent(QEvent *) { stopDrag(); } void PlayField::setSize(int w, int h) { int sbarHeight = statusMetrics_.height(); int sbarNumWidth = statusMetrics_.boundingRect("88888").width()+8; int sbarLevelWidth = statusMetrics_.boundingRect(levelText_).width()+8; int sbarStepsWidth = statusMetrics_.boundingRect(stepsText_).width()+8; int sbarPushesWidth = statusMetrics_.boundingRect(pushesText_).width()+8; pnumRect_.setRect(w-sbarNumWidth, h-sbarHeight, sbarNumWidth, sbarHeight); ptxtRect_.setRect(pnumRect_.x()-sbarPushesWidth, h-sbarHeight, sbarPushesWidth, sbarHeight); snumRect_.setRect(ptxtRect_.x()-sbarNumWidth, h-sbarHeight, sbarNumWidth, sbarHeight); stxtRect_.setRect(snumRect_.x()-sbarStepsWidth, h-sbarHeight, sbarStepsWidth, sbarHeight); lnumRect_.setRect(stxtRect_.x()-sbarNumWidth, h-sbarHeight, sbarNumWidth, sbarHeight); ltxtRect_.setRect(lnumRect_.x()-sbarLevelWidth, h-sbarHeight, sbarLevelWidth, sbarHeight); collRect_.setRect(0, h-sbarHeight, ltxtRect_.x(), sbarHeight); //printf("collRect_:%d;%d;%d;%d\n",collRect_.x(), collRect_.y(), collRect_.width(), collRect_.height()); if(ltxtXpm_) delete ltxtXpm_; if(lnumXpm_) delete lnumXpm_; if(stxtXpm_) delete stxtXpm_; if(snumXpm_) delete snumXpm_; if(ptxtXpm_) delete ptxtXpm_; if(pnumXpm_) delete pnumXpm_; if(collXpm_) delete collXpm_; ltxtXpm_ = new QPixmap(ltxtRect_.size()); lnumXpm_ = new QPixmap(lnumRect_.size()); stxtXpm_ = new QPixmap(stxtRect_.size()); snumXpm_ = new QPixmap(snumRect_.size()); ptxtXpm_ = new QPixmap(ptxtRect_.size()); pnumXpm_ = new QPixmap(pnumRect_.size()); collXpm_ = new QPixmap(collRect_.size()); h -= sbarHeight; int cols = levelMap_->width(); int rows = levelMap_->height(); // FIXME: the line below should not be needed if (cols == 0 || rows == 0) return; int xsize = w / cols; int ysize = h / rows; if (xsize < 8) xsize = 8; if (ysize < 8) ysize = 8; size_ = imageData_->resize(xsize > ysize ? ysize : xsize); xOffs_ = (w - cols*size_) / 2; yOffs_ = (h - rows*size_) / 2; updateCollectionXpm(); updateTextXpm(); updateLevelXpm(); updateStepsXpm(); updatePushesXpm(); } void PlayField::nextLevel() { if (levelMap_->level()+1 >= levelMap_->noOfLevels()) { ModalLabel::message(i18n("\ This is the last level in\n\ the current collection."), this); return; } if (levelMap_->level() >= levelMap_->completedLevels()) { ModalLabel::message(i18n("\ You have not completed\n\ this level yet."), this); return; } level(levelMap_->level()+1); levelChange(); repaint(); } void PlayField::previousLevel() { if (levelMap_->level() <= 0) { ModalLabel::message(i18n("\ This is the first level in\n\ the current collection."), this); return; } level(levelMap_->level()-1); levelChange(); repaint(); } void PlayField::undo() { if (!canMoveNow()) return; startMoving(history_->deferUndo(levelMap_)); } void PlayField::redo() { if (!canMoveNow()) return; startMoving(history_->deferRedo(levelMap_)); } void PlayField::restartLevel() { stopMoving(); history_->clear(); level(levelMap_->level()); updateStepsXpm(); updatePushesXpm(); repaint(); } void PlayField::changeCollection(LevelCollection *collection) { if (levelMap_->collection() == collection) return; levelMap_->changeCollection(collection); levelChange(); //erase(collRect_); repaint(); } void PlayField::updateCollectionXpm() { if (!collXpm_) return; if (collXpm_->isNull()) return; //printf("executing PlayField::updateCollectionXpm() w:%d, h:%d\n",collXpm_->width(), collXpm_->height()); QPainter paint(collXpm_); paint.setBrushOrigin(- collRect_.x(), - collRect_.y()); paint.fillRect(0, 0, collRect_.width(), collRect_.height(), background_); paint.setFont(statusFont_); paint.setPen(QColor(0,255,0)); paint.drawText(0, 0, collRect_.width(), collRect_.height(), Qt::AlignLeft, collectionName()); } void PlayField::updateTextXpm() { if (!ltxtXpm_) return; if (ltxtXpm_->isNull()) return; //printf("executing PlayField::updateTextXpm() w:%d, h:%d\n",ltxtXpm_->width(), ltxtXpm_->height()); QPainter paint; paint.begin(ltxtXpm_); paint.setBrushOrigin(- ltxtRect_.x(), - ltxtRect_.y()); paint.fillRect(0, 0, ltxtRect_.width(), ltxtRect_.height(), background_); paint.setFont(statusFont_); paint.setPen(QColor(128,128,128)); paint.drawText(0, 0, ltxtRect_.width(), ltxtRect_.height(), Qt::AlignLeft, levelText_); paint.end(); paint.begin(stxtXpm_); paint.setBrushOrigin(- stxtRect_.x(), - stxtRect_.y()); paint.fillRect(0, 0, stxtRect_.width(), stxtRect_.height(), background_); paint.setFont(statusFont_); paint.setPen(QColor(128,128,128)); paint.drawText(0, 0, stxtRect_.width(), stxtRect_.height(), Qt::AlignLeft, stepsText_); paint.end(); paint.begin(ptxtXpm_); paint.setBrushOrigin(- ptxtRect_.x(), - ptxtRect_.y()); paint.fillRect(0, 0, ptxtRect_.width(), ptxtRect_.height(), background_); paint.setFont(statusFont_); paint.setPen(QColor(128,128,128)); paint.drawText(0, 0, ptxtRect_.width(), ptxtRect_.height(), Qt::AlignLeft, pushesText_); paint.end(); } void PlayField::updateLevelXpm() { if (!lnumXpm_) return; if (lnumXpm_->isNull()) return; //printf("executing PlayField::updateLevelXpm()\n"); QPainter paint(lnumXpm_); paint.setBrushOrigin(- lnumRect_.x(), - lnumRect_.y()); paint.fillRect(0, 0, lnumRect_.width(), lnumRect_.height(), background_); QString str; paint.setFont(statusFont_); paint.setPen(QColor(255,0,0)); paint.drawText(0, 0, lnumRect_.width(), lnumRect_.height(), Qt::AlignLeft, str.sprintf("%05d", level()+1)); } void PlayField::updateStepsXpm() { if (!snumXpm_) return; if (snumXpm_->isNull()) return; //printf("executing PlayField::updateStepsXpm()\n"); QPainter paint(snumXpm_); paint.setBrushOrigin(- snumRect_.x(), - snumRect_.y()); paint.fillRect(0, 0, snumRect_.width(), snumRect_.height(), background_); QString str; paint.setFont(statusFont_); paint.setPen(QColor(255,0,0)); paint.drawText(0, 0, snumRect_.width(), snumRect_.height(), Qt::AlignLeft, str.sprintf("%05d", totalMoves())); } void PlayField::updatePushesXpm() { if (!pnumXpm_) return; if (pnumXpm_->isNull()) return; //printf("executing PlayField::updatePushesXpm()\n"); QPainter paint(pnumXpm_); paint.setBrushOrigin(- pnumRect_.x(), - pnumRect_.y()); paint.fillRect(0, 0, pnumRect_.width(), pnumRect_.height(), background_); QString str; paint.setFont(statusFont_); paint.setPen(QColor(255,0,0)); paint.drawText(0, 0, pnumRect_.width(), pnumRect_.height(), Qt::AlignLeft, str.sprintf("%05d", totalPushes())); } void PlayField::changeAnim(int num) { assert(num >= 0 && num <= 3); animDelay_ = num; } // FIXME: clean up bookmark stuff // static const int bookmark_id[] = { // 0, 1, 8, 2, 9, 3, 5, 6, 7, 4 // }; void PlayField::setBookmark(Bookmark *bm) { if (!levelMap_->goodLevel()) return; if (collection()->id() < 0) { KMessageBox::sorry(this, i18n("Sorry, bookmarks for external levels\n" "is not implemented yet.")); return; } bm->set(collection()->id(), levelMap_->level(), levelMap_->totalMoves(), history_); } void PlayField::goToBookmark(Bookmark *bm) { level(bm->level()); levelChange(); if (!bm->goTo(levelMap_, history_)) fprintf(stderr, "Warning: bad bookmark\n"); //updateLevelXpm(); updateStepsXpm(); updatePushesXpm(); repaint(); } bool PlayField::canMoveNow() { if (moveInProgress_) return false; if (!levelMap_->goodLevel()) { ModalLabel::message(i18n("This level is broken"), this); return false; } return true; } void PlayField::killTimers() { for(QList::Iterator it=timers.begin(); it!=timers.end(); it++) { killTimer(*it); } timers.clear(); } diff --git a/PlayField.h b/PlayField.h index 94b7e35..d7b7e18 100644 --- a/PlayField.h +++ b/PlayField.h @@ -1,154 +1,154 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef PLAYFIELD_H #define PLAYFIELD_H #include #include #include #include #include #include #include #include "ImageData.h" #include "LevelMap.h" class MapDelta; class MoveSequence; class Move; #include "PathFinder.h" class History; class Bookmark; class LevelCollection; class QPainter; class QCursor; class PlayField : public QWidget { Q_OBJECT public: PlayField(QWidget *parent); ~PlayField (); bool canMoveNow(); int animDelay() { return animDelay_; } void setSize(int w, int h); void level(int _l) { levelMap_->level(_l); } LevelCollection *collection() const { return levelMap_->collection(); } void setBookmark(Bookmark *bm); void goToBookmark(Bookmark *bm); int level() const; const QString &collectionName(); int totalMoves() const; int totalPushes() const; void updateCollectionXpm(); void updateTextXpm(); void updateLevelXpm(); void updateStepsXpm(); void updatePushesXpm(); public slots: void nextLevel(); void previousLevel(); void undo(); void redo(); void restartLevel(); void changeCollection(LevelCollection *collection); void changeAnim(int num); protected: ImageData *imageData_; LevelMap *levelMap_; History *history_; int lastLevel_; MoveSequence *moveSequence_; MapDelta *mapDelta_; bool moveInProgress_; bool dragInProgress_; PathFinder pathFinder_; int animDelay_; const QCursor* cursor_; void levelChange (); void paintSquare (int x, int y, QPainter &paint); void paintDelta (); void paintEvent (QPaintEvent *e); void paintPainterClip(QPainter& paint, int x, int y, int w, int h); void paintPainter(QPainter& paint, const QRect& rect); void resizeEvent (QResizeEvent *e); void mouseMoveEvent(QMouseEvent* e); void keyPressEvent (QKeyEvent *); void focusInEvent (QFocusEvent *); void focusOutEvent (QFocusEvent *); void mousePressEvent (QMouseEvent *); void mouseReleaseEvent(QMouseEvent*); void leaveEvent(QEvent*); void wheelEvent (QWheelEvent *); void step (int _x, int _y); void push (int _x, int _y); virtual void timerEvent (QTimerEvent *); void stopDrag(); void dragObject(int xpixel, int ypixel); void highlight(); void changeCursor(const QCursor* c); void eatKeyPressEvents(); private: int size_, xOffs_, yOffs_; int highlightX_, highlightY_; int dragX_, dragY_; int lastMouseXPos_, lastMouseYPos_; int mousePosX_, mousePosY_; int wheelDelta_; int debug_counter; QList timers; void killTimers(); QCursor sizeAllCursor; QCursor crossCursor; int x2pixel (int x) const { return size_*x+xOffs_; } int y2pixel (int y) const { return size_*y+yOffs_; } int pixel2x (int x) const { return (x-xOffs_)/size_; } int pixel2y (int y) const { return (y-yOffs_)/size_; } void startMoving (Move *m); void startMoving (MoveSequence *ms); void stopMoving (); QRect pnumRect_, ptxtRect_, snumRect_, stxtRect_, lnumRect_, ltxtRect_; QRect collRect_; const QString levelText_, stepsText_, pushesText_; QPixmap *pnumXpm_, *ptxtXpm_, *snumXpm_, *stxtXpm_, *lnumXpm_, *ltxtXpm_; QPixmap *collXpm_; QPixmap dragXpm_; QImage dragImage_; QFont statusFont_; QFontMetrics statusMetrics_; QBrush background_; QBrush floor_; }; #endif /* PLAYFIELD_H */ diff --git a/Queue.h b/Queue.h index cab9db9..bce3626 100644 --- a/Queue.h +++ b/Queue.h @@ -1,56 +1,56 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef QUEUE_H #define QUEUE_H #include template class Queue { private: Type *queue_; long head_, tail_; public: void clear() { head_ = tail_ = 0; } bool empty() { return head_ == tail_; } bool full() { return ((tail_ + 1) & ((1l< copyright 2012 £ukasz Kalam³acki ksokoban is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License. See the file COPYING for details. See http://hem.passagen.se/awl/ksokoban/ for later versions of ksokoban. See the file AUTHORS for details about where the levels come from. ------------------------------------------------------------------------ PLAYING ======= The objective of the game is to push all the red gems (these should actually have been crates, but gems looked nicer) to the goal squares, which are marked with green glassy things on the floor. Use the cursor keys to move about. If you move onto a gem and there is noting blocking it on the opposite side, then you will push the gem. Use the CONTROL key together with the cursor keys to move as far as possible in a direction without pushing any gems. With the SHIFT key you will move as far as possible in a direction, possibly pushing a gem if it is in the way. Use the left mouse button to move to any place you can reach without pushing any gems. The middle mouse moves in a straight line, possibly pushing a gem if it is in the way. The U key or the right mouse button undoes the last move. diff --git a/StaticImage.cpp b/StaticImage.cpp index 3948c48..03bf985 100644 --- a/StaticImage.cpp +++ b/StaticImage.cpp @@ -1,84 +1,84 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "StaticImage.h" #include "images/data.c" const unsigned char *const imageData[NO_OF_IMAGES] = { halfstone_1_data_, halfstone_2_data_, halfstone_3_data_, halfstone_4_data_, stone_1_data_, stone_2_data_, stone_3_data_, stone_4_data_, stone_5_data_, stone_6_data_, object_data_, treasure_data_, goal_data_, man_data_, saveman_data_, }; const unsigned imageSize[NO_OF_IMAGES] = { sizeof halfstone_1_data_, sizeof halfstone_2_data_, sizeof halfstone_3_data_, sizeof halfstone_4_data_, sizeof stone_1_data_, sizeof stone_2_data_, sizeof stone_3_data_, sizeof stone_4_data_, sizeof stone_5_data_, sizeof stone_6_data_, sizeof object_data_, sizeof treasure_data_, sizeof goal_data_, sizeof man_data_, sizeof saveman_data_, }; StaticImage::StaticImage () { bool valid = background_.loadFromData((const uchar *) starfield_data_, (uint) sizeof (starfield_data_)); if (!valid) { background_ = background_.copy(0, 0, 128, 128); background_.fill(Qt::black); } for (int i=0; i * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef STATICIMAGE_H #define STATICIMAGE_H #include "ImageData.h" class StaticImage : public ImageData { public: StaticImage (); virtual ~StaticImage (); }; #endif /* STATICIMAGE_H */ diff --git a/main.cpp b/main.cpp index 1cc087a..6324c12 100644 --- a/main.cpp +++ b/main.cpp @@ -1,85 +1,85 @@ /* - * ksokoban - a Sokoban game for KDE + * ksokoban - a Sokoban game by KDE * Copyright (C) 1998-2000 Anders Widell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include "MainWindow.h" static const char version[] = "0.5.0"; int main (int argc, char **argv) { QApplication app(argc, argv); KAboutData aboutData("ksokoban", "ksokoban", version, "The japanese warehouse keeper game", KAboutLicense::GPL, "(c) 1998 Anders Widell \n(c) 2012 Lukasz Kalamlacki", QString(), "http://www.shlomifish.org/open-source/projects/ksokoban/", "shlomif@cpan.org" ); aboutData.addAuthor("Shlomi Fish", "For porting to Qt5/KF5 and doing other cleanups", "shlomif@cpan.org", "http://www.shlomifish.org/"); aboutData.addAuthor("Lukasz Kalamlacki", "For rewriting the original ksokoban game from kde3 to kde4", "kalamlacki@gmail.com", "http://sf.net/projects/ksokoban"); aboutData.addAuthor("Anders Widell", "For writing the original ksokoban game", "awl@hem.passagen.se", "http://hem.passagen.se/awl/ksokoban/"); aboutData.addCredit("David W. Skinner", "For contributing the Sokoban levels included in this game", "sasquatch@bentonrea.com", "http://users.bentonrea.com/~sasquatch/"); QCommandLineParser parser; KAboutData::setApplicationData(aboutData); parser.addVersionOption(); parser.addHelpOption(); aboutData.setupCommandLine(&parser); parser.process(app); aboutData.processCommandLine(&parser); parser.addPositionalArgument(QLatin1String("[file]"), "Level collection file to load"); QApplication::setColorSpec(QApplication::ManyColor); MainWindow *widget = new MainWindow(); widget->show(); if (parser.positionalArguments().count() > 0) { widget->openURL(parser.positionalArguments().at(0)); } QObject::connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())); return app.exec(); }