diff --git a/LevelCollection.cpp b/LevelCollection.cpp index 0a8ade6..62f7f63 100644 --- a/LevelCollection.cpp +++ b/LevelCollection.cpp @@ -1,431 +1,428 @@ #include #include #include #include #include #include #include #include "LevelCollection.h" #include "Map.h" #if 1 #define GETUID() 501 #else #ifndef WIN32 #define GETUID() getuid() #else #define GETUID() 1000 #endif #endif static inline unsigned long forward(unsigned long a, unsigned long b, unsigned long c, unsigned long d) { unsigned long x=(a^b)&0xfffffffful; return (((x<>((32ul-c)&31ul)))*d)&0xfffffffful; } static inline unsigned long backward(unsigned long a, unsigned long b, unsigned long c, unsigned long d) { unsigned long x=(a*b)&0xfffffffful; return (((x<>((32ul-c)&31ul)))^d)&0xfffffffful; } void LevelCollection::indexTextCollection() { enum states { BEFORE_NONE, BEFORE_VALID, BEFORE_INVALID, DURING_NONE, DURING_VALID, DURING_INVALID } state = BEFORE_NONE; int levelstart=0, levelend=0; for (int pos=0; pos<(data_.size()-1); pos++) { switch (state) { case BEFORE_NONE: switch (data_[pos]) { case '#': case '.': case '$': case '+': case '*': case '@': state = BEFORE_VALID; break; case ' ': case '\t': case '\r': break; case '\n': levelstart = pos + 1; break; default: state = BEFORE_INVALID; break; } break; case BEFORE_VALID: switch (data_[pos]) { case '#': case '.': case '$': case '+': case '*': case '@': case ' ': case '\t': case '\r': break; case '\n': addLevel(data_.constData() + levelstart); levelend = levelstart; state = DURING_NONE; break; default: state = BEFORE_INVALID; break; } break; case BEFORE_INVALID: switch (data_[pos]) { case '\n': levelstart = pos + 1; state = BEFORE_NONE; break; } break; case DURING_NONE: switch (data_[pos]) { case '#': case '.': case '$': case '+': case '*': case '@': state = DURING_VALID; break; case ' ': case '\t': case '\r': break; case '\n': data_[levelend] = '\0'; levelstart = pos + 1; state = BEFORE_NONE; break; default: state = DURING_INVALID; break; } break; case DURING_VALID: switch (data_[pos]) { case '#': case '.': case '$': case '+': case '*': case '@': case ' ': case '\t': case '\r': break; case '\n': levelend = pos; state = DURING_NONE; break; default: state = DURING_INVALID; break; } break; case DURING_INVALID: switch (data_[pos]) { case '\n': data_[levelend] = '\0'; levelstart = pos + 1; state = BEFORE_NONE; break; } break; default: assert(0); } } if (state==DURING_NONE || state==DURING_INVALID) { data_[levelend] = '\0'; } } void LevelCollection::loadPrefs() { if (id_ >= 0) { KSharedConfigPtr cfg=KSharedConfig::openConfig(); KConfigGroup settingsGroup(cfg, "settings"); - QString key; - key.sprintf("level%d", id_); + QString key = QString::asprintf("level%d", id_); level_ = settingsGroup.readEntry(key, QStringLiteral("0")).toInt(); - key.sprintf("status%d", id_); + key = QString::asprintf("status%d", id_); unsigned long x = settingsGroup.readEntry(key, QStringLiteral("0")).toULong(); x = backward(x, 0xc1136a15ul, 0x12ul, 0x80ff0b94ul); x = backward(x, 0xd38fd2ddul, 0x01ul, 0xd4d657b4ul); x = backward(x, 0x59004eeful, 0x1eul, 0xf6c75e2cul); x = backward(x, 0x366c3e25ul, 0x0aul, 0x61ebc208ul); x = backward(x, 0x20a784c9ul, 0x15ul, 0x207d488bul); x = backward(x, 0xc02864abul, 0x09ul, 0x709e62a3ul); x = backward(x, 0xe2a60f19ul, 0x0eul, 0x8bb02c07ul); x = backward(x, 0x3b0e11f3ul, 0x13ul, 0x608aef3ful); completedLevels_ = x>>16 & 0x3ff; if (!settingsGroup.hasKey(key)) completedLevels_ = 0; if (((x>>26) & 0x3ful) != (unsigned long) id_) completedLevels_ = 0; if ((x & 0xfffful) != (unsigned long) GETUID()) completedLevels_ = 0; if (completedLevels_ > noOfLevels_) completedLevels_ = 0; if (level_ > completedLevels_) level_ = completedLevels_; if (level_ >= noOfLevels_) level_ = noOfLevels_-1; if (level_ < 0) level_ = 0; } else { level_ = 0; completedLevels_ = noOfLevels_; } } void LevelCollection::addLevel(const char* _level) { index_.append(_level); } void LevelCollection::addData(const char* _data, unsigned _len) { unsigned pos = data_.size(); data_.resize(pos + _len); memcpy(data_.data() + pos, _data, _len); } void LevelCollection::addSeparator() { unsigned pos = data_.size(); data_.resize(pos + 1); data_[pos] = '\0'; } LevelCollection::LevelCollection(const char *_def, int _len, const QString &_name, int _id) : level_(0), completedLevels_(0), noOfLevels_(0), name_(_name), id_(_id) { addData(_def, _len); addSeparator(); indexTextCollection(); noOfLevels_ = index_.size(); loadPrefs(); } LevelCollection::LevelCollection(const QString &_path, const QString &_name, int _id) : level_(0), completedLevels_(0), noOfLevels_(0), name_(_name), path_(_path), id_(_id) { char buf[1024]; int len; QFile file(path_); if (file.open(QIODevice::ReadOnly)) { while ((len = file.read(buf, 1024)) > 0) { addData((const char *) buf, len); } file.close(); addSeparator(); } indexTextCollection(); noOfLevels_ = index_.size(); loadPrefs(); } LevelCollection::~LevelCollection() { if (id_ >= 0) { KSharedConfigPtr cfg=KSharedConfig::openConfig(); KConfigGroup settingsGroup(cfg,"settings"); - QString key; - key.sprintf("level%d", id_); + const QString key = QString::asprintf("level%d", id_); settingsGroup.writeEntry(key, QStringLiteral("%1").arg(level_)); } } void LevelCollection::levelCompleted() { if (completedLevels_ < (level_+1)) completedLevels_ = level_+1; if (id_ >= 0) { unsigned long x=(((unsigned long) GETUID()) & 0xfffful); x |= ((unsigned long) id_)<<26; x |= ((unsigned long) completedLevels_)<<16; x = forward(x, 0x608aef3ful, 0x0dul, 0xfb00ef3bul); x = forward(x, 0x8bb02c07ul, 0x12ul, 0x2a37dd29ul); x = forward(x, 0x709e62a3ul, 0x17ul, 0x23607603ul); x = forward(x, 0x207d488bul, 0x0bul, 0xc31fd579ul); x = forward(x, 0x61ebc208ul, 0x16ul, 0xbcffadadul); x = forward(x, 0xf6c75e2cul, 0x02ul, 0xa2baa00ful); x = forward(x, 0xd4d657b4ul, 0x1ful, 0x7e129575ul); x = forward(x, 0x80ff0b94ul, 0x0eul, 0x92fc153dul); - QString key; - key.sprintf("status%d", id_); + const QString key = QString::asprintf("status%d", id_); KSharedConfigPtr cfg=KSharedConfig::openConfig(); KConfigGroup settingsGroup(cfg, "settings"); settingsGroup.writeEntry(key, QStringLiteral("%1").arg(x)); cfg->sync(); } } void LevelCollection::level(int _level) { assert(_level >= 0 && _level < noOfLevels_); level_ = _level; if (level_ > completedLevels_) level_ = completedLevels_; if (level_ >= noOfLevels_) level_ = noOfLevels_ - 1; if (level_ < 0) level_ = 0; } static int minX(const char *def) { int min_x = 10000; int x=0; for (int pos=0; def[pos]; pos++) { switch(def[pos]) { case '\n': x = 0; break; case ' ': x++; break; case '\t': x = (x+8) & ~7; break; case '\r': break; default: if (x < min_x) min_x = x; break; } } return min_x == 10000 ? -1 : min_x; } bool LevelCollection::loadLevel(Map *_map) { _map->clearMap(); const char *def = index_[level_]; bool goodMap = true; int x=0, y=0, goalsLeft=0; int min_x = minX(def); if (min_x < 0) { min_x = 0; goodMap = false; } _map->xpos_ = -1; _map->ypos_ = -1; for (int pos=0; def[pos]; pos++) { switch(def[pos]) { case '\n': y++; x = 0; break; case ' ': x++; break; case '\t': x = (x+8) & ~7; break; case '@': if (x-min_x > MAX_X || y > MAX_Y) goodMap = false; else { _map->xpos_ = x-min_x; _map->ypos_ = y; } x++; break; case '$': if (x-min_x > MAX_X || y > MAX_Y) goodMap = false; else _map->map(x-min_x, y, OBJECT); x++; break; case '.': if (x-min_x > MAX_X || y > MAX_Y) goodMap = false; else { _map->map(x-min_x, y, GOAL); goalsLeft++; } x++; break; case '#': if (x-min_x > MAX_X || y > MAX_Y) goodMap = false; else _map->map(x-min_x, y, WALL); x++; break; case '+': if (x-min_x > MAX_X || y > MAX_Y) goodMap = false; else { _map->xpos_ = x-min_x; _map->ypos_ = y; _map->map(x-min_x, y, GOAL); goalsLeft++; } x++; break; case '*': if (x-min_x > MAX_X || y > MAX_Y) goodMap = false; else _map->map(x-min_x, y, OBJECT|GOAL); x++; break; case '\r': break; default: goodMap = false; break; } } if (_map->objectsLeft() != goalsLeft) goodMap = false; if (_map->completed()) goodMap = false; if (_map->badCoords(_map->xpos_, _map->ypos_)) goodMap = false; else { if (!_map->empty(_map->xpos_, _map->ypos_)) goodMap = false; else if (!_map->fillFloor(_map->xpos_, _map->ypos_)) goodMap = false; } return goodMap; } diff --git a/ModalLabel.h b/ModalLabel.h index feedd27..52ac956 100644 --- a/ModalLabel.h +++ b/ModalLabel.h @@ -1,39 +1,39 @@ /* * 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 *) override; bool eventFilter (QObject *, QEvent *) override; bool completed_; protected: - ModalLabel (const QString &text, QWidget *parent, Qt::WindowFlags f=0); + ModalLabel (const QString &text, QWidget *parent, Qt::WindowFlags f={}); }; #endif /* MODALLABEL_H */ diff --git a/PlayField.cpp b/PlayField.cpp index 452c9e6..b7e8495 100644 --- a/PlayField.cpp +++ b/PlayField.cpp @@ -1,991 +1,988 @@ /* * 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" 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_(nullptr), ptxtXpm_(nullptr), snumXpm_(nullptr), stxtXpm_(nullptr), lnumXpm_(nullptr), ltxtXpm_(nullptr), collXpm_(nullptr), 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", QStringLiteral("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", QStringLiteral("%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 == nullptr) unsetCursor(); else setCursor(*c); } int PlayField::level() const { if (levelMap_ == nullptr) return 0; return levelMap_->level(); } const QString & PlayField::collectionName() { static QString error = QStringLiteral("????"); if (levelMap_ == nullptr) return error; return levelMap_->collectionName(); } int PlayField::totalMoves() const { if (levelMap_ == nullptr) return 0; return levelMap_->totalMoves(); } int PlayField::totalPushes() const{ if (levelMap_ == nullptr) 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_ = nullptr; 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_ == nullptr) { 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; } } 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 != nullptr) { 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->angleDelta().y(); 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(QStringLiteral("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)); + Qt::AlignLeft, QString::asprintf("%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())); + Qt::AlignLeft, QString::asprintf("%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())); + Qt::AlignLeft, QString::asprintf("%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(); }