You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegames/ksokoban/PlayField.cpp

1045 lines
25 KiB

/*
* ksokoban - a Sokoban game for TDE
* Copyright (C) 1998 Anders Widell <d95-awi@nada.kth.se>
*
* 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 <stdio.h>
#include <assert.h>
#include <tqwidget.h>
#include <tqpixmap.h>
#include <tqkeycode.h>
#include <tdeconfig.h>
#include <kapplication.h>
#include <klocale.h>
#include <tqpainter.h>
#include <kmessagebox.h>
#include <kglobalsettings.h>
#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(TQWidget *parent, const char *name, WFlags f)
: TQWidget(parent, name, f|WResizeNoErase), imageData_(0), lastLevel_(-1),
moveSequence_(0), moveInProgress_(false), dragInProgress_(false),
xOffs_(0), yOffs_(0),
wheelDelta_(0),
levelText_(i18n("Level:")), stepsText_(i18n("Steps:")),
pushesText_(i18n("Pushes:")),
statusFont_(TDEGlobalSettings::generalFont().family(), 18, TQFont::Bold), statusMetrics_(statusFont_) {
setFocusPolicy(TQ_StrongFocus);
setFocus();
setBackgroundMode(TQt::NoBackground);
setMouseTracking(true);
highlightX_ = highlightY_ = 0;
TDEConfig *cfg = (TDEApplication::kApplication())->config();
cfg->setGroup("settings");
imageData_ = new StaticImage;
animDelay_ = cfg->readNumEntry("animDelay", 2);
if (animDelay_ < 0 || animDelay_ > 3) animDelay_ = 2;
history_ = new History;
background_.setPixmap(imageData_->background());
floor_ = TQBrush(TQColor(0x66,0x66,0x66));
levelMap_ = new LevelMap;
mapDelta_ = new MapDelta(levelMap_);
mapDelta_->end();
levelChange();
}
PlayField::~PlayField() {
TDEConfig *cfg = (TDEApplication::kApplication())->config();
cfg->setGroup("settings");
cfg->writeEntry("animDelay", animDelay_, true, false, false);
delete mapDelta_;
delete history_;
delete levelMap_;
delete imageData_;
}
void
PlayField::changeCursor(const TQCursor* 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 TQString &
PlayField::collectionName() {
static TQString 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, TQPainter &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));
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_);
} 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() {
TQPainter paint(this);
// the following line is a workaround for a bug in TQt 2.0.1
// (and possibly earlier versions)
paint.setBrushOrigin(0, 0);
for (int y=0; y<levelMap_->height(); y++) {
for (int x=0; x<levelMap_->width(); x++) {
if (mapDelta_->hasChanged(x, y)) paintSquare(x, y, paint);
}
}
}
void
PlayField::paintEvent(TQPaintEvent *e) {
TQPainter paint(this);
// the following line is a workaround for a bug in TQt 2.0.1
// (and possibly earlier versions)
paint.setBrushOrigin(0, 0);
paint.setClipRegion(e->region());
paint.setClipping(true);
paintPainter(paint, e->rect());
}
void
PlayField::paintPainterClip(TQPainter &paint, int x, int y, int w, int h) {
TQRect rect(x, y, w, h);
paint.setClipRect(rect);
paint.setClipping(true);
paintPainter(paint, rect);
}
void
PlayField::paintPainter(TQPainter &paint, const TQRect &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)) paint.drawPixmap(collRect_.x(), collRect_.y(), collXpm_);
if (ltxtRect_.intersects(rect)) paint.drawPixmap(ltxtRect_.x(), ltxtRect_.y(), ltxtXpm_);
if (lnumRect_.intersects(rect)) paint.drawPixmap(lnumRect_.x(), lnumRect_.y(), lnumXpm_);
if (stxtRect_.intersects(rect)) paint.drawPixmap(stxtRect_.x(), stxtRect_.y(), stxtXpm_);
if (snumRect_.intersects(rect)) paint.drawPixmap(snumRect_.x(), snumRect_.y(), snumXpm_);
if (ptxtRect_.intersects(rect)) paint.drawPixmap(ptxtRect_.x(), ptxtRect_.y(), ptxtXpm_);
if (pnumRect_.intersects(rect)) paint.drawPixmap(pnumRect_.x(), pnumRect_.y(), pnumXpm_);
}
void
PlayField::resizeEvent(TQResizeEvent *e) {
setSize(e->size().width(), e->size().height());
}
void
PlayField::mouseMoveEvent(TQMouseEvent *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;
TQRect rect(dragX_, dragY_, size_, size_);
dragXpm_.resize(size_, size_);
TQPainter paint;
paint.begin(&dragXpm_);
paint.setBackgroundColor(backgroundColor());
paint.setBrushOrigin(- dragX_, - dragY_);
paint.translate((double) (- dragX_), (double) (- dragY_));
paintPainter(paint, rect);
paint.end();
dragImage_ = dragXpm_;
for (int yy=0; yy<size_; yy++) {
for (int xx=0; xx<size_; xx++) {
TQRgb rgb1 = imageData_->objectImg().pixel(xx, yy);
int r1 = tqRed(rgb1);
int g1 = tqGreen(rgb1);
int b1 = tqBlue(rgb1);
if (r1 != g1 || r1 != b1 || r1 == 255) {
TQRgb rgb2 = dragImage_.pixel(xx, yy);
int r2 = tqRed(rgb2);
int g2 = tqGreen(rgb2);
int b2 = tqBlue(rgb2);
r2 = (int) (0.75 * r1 + 0.25 * r2 + 0.5);
g2 = (int) (0.75 * g1 + 0.25 * g2 + 0.5);
b2 = (int) (0.75 * b1 + 0.25 * b2 + 0.5);
dragImage_.setPixel(xx, yy, tqRgb(r2, g2, b2));
}
}
}
paint.begin(this);
// the following line is a workaround for a bug in TQt 2.0.1
// (and possibly earlier versions)
paint.setBrushOrigin(0, 0);
dragXpm_.convertFromImage(dragImage_,
OrderedDither|OrderedAlphaDither|
ColorOnly|AvoidDither);
paint.drawPixmap(dragX_, dragY_, dragXpm_);
{
int dx = dragX_ - old_x;
int dy = dragY_ - old_y;
int y2 = old_y;
if (dy > 0) {
paintPainterClip(paint, old_x, old_y, size_, dy);
// NOTE: clipping is now activated in the TQPainter paint
y2 += dy;
} else if (dy < 0) {
paintPainterClip(paint, old_x, old_y+size_+dy, size_, -dy);
// NOTE: clipping is now activated in the TQPainter paint
dy = -dy;
}
if (dx > 0) {
paintPainterClip(paint, old_x, y2, dx, size_-dy);
// NOTE: clipping is now activated in the TQPainter paint
} else if (dx < 0) {
paintPainterClip(paint, old_x+size_+dx, y2, -dx, size_-dy);
// NOTE: clipping is now activated in the TQPainter paint
}
}
paint.end();
}
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)) {
TQPainter paint(this);
if (highlightX_ >= 0) {
int x = highlightX_, y = highlightY_;
highlightX_ = -1;
paintSquare(x, y, paint);
} else
changeCursor(&sizeAllCursor);
if (levelMap_->goal(x, y))
imageData_->brightTreasure(paint, x2pixel(x), y2pixel(y));
else
imageData_->brightObject(paint, x2pixel(x), y2pixel(y));
highlightX_ = x;
highlightY_ = y;
} else {
if (pathFinder_.canWalkTo(x, y)) changeCursor(&crossCursor);
else changeCursor(0);
if (highlightX_ >= 0) {
TQPainter paint(this);
int x = highlightX_, y = highlightY_;
highlightX_ = -1;
paintSquare(x, y, paint);
}
}
}
void
PlayField::stopMoving() {
TQT_TQOBJECT(this)->killTimers();
delete moveSequence_;
moveSequence_ = 0;
moveInProgress_ = false;
updateStepsXpm();
updatePushesXpm();
TQPainter paint(this);
paint.drawPixmap(snumRect_.x(), snumRect_.y(), snumXpm_);
paint.drawPixmap(pnumRect_.x(), pnumRect_.y(), pnumXpm_);
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_) startTimer(delay[animDelay_]);
timerEvent(0);
}
void
PlayField::timerEvent(TQTimerEvent *) {
assert(moveInProgress_);
if (moveSequence_ == 0) {
TQT_TQOBJECT(this)->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 (_x<oldX) dx=-1;
if (_y>oldY) dy=1;
if (_y<oldY) dy=-1;
while (!(x==_x && y==_y) && levelMap_->step(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 (_x<oldX) dx=-1;
if (_y>oldY) dy=1;
if (_y<oldY) dy=-1;
while (!(x==_x && y==_y) && levelMap_->step(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(TQKeyEvent * e) {
int x=levelMap_->xpos();
int y=levelMap_->ypos();
switch (e->key()) {
case Key_Up:
if (e->state() & ControlButton) step(x, 0);
else if (e->state() & ShiftButton) push(x, 0);
else push(x, y-1);
break;
case Key_Down:
if (e->state() & ControlButton) step(x, MAX_Y);
else if (e->state() & ShiftButton) push(x, MAX_Y);
else push(x, y+1);
break;
case Key_Left:
if (e->state() & ControlButton) step(0, y);
else if (e->state() & ShiftButton) push(0, y);
else push(x-1, y);
break;
case Key_Right:
if (e->state() & ControlButton) step(MAX_X, y);
else if (e->state() & ShiftButton) push(MAX_X, y);
else push(x+1, y);
break;
case Key_Q:
TDEApplication::kApplication()->closeAllWindows();
break;
case Key_Backspace:
case Key_Delete:
if (e->state() & ControlButton) redo();
else undo();
break;
#if 0
case Key_X:
levelMap_->random();
levelChange();
repaint(false);
break;
case Key_R:
level(levelMap_->level());
return;
break;
case Key_N:
nextLevel();
return;
break;
case Key_P:
previousLevel();
return;
break;
case Key_U:
undo();
return;
break;
case Key_I:
history_->redo(levelMap_);
repaint(false);
return;
break;
case Key_S:
{
TQString buf;
history_->save(buf);
printf("%s\n", (char *) buf);
}
return;
break;
case 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 Key_Print:
HtmlPrinter::printHtml(levelMap_);
break;
default:
e->ignore();
return;
break;
}
}
void
PlayField::stopDrag() {
if (!dragInProgress_) return;
changeCursor(0);
TQPainter paint(this);
// the following line is a workaround for a bug in TQt 2.0.1
// (and possibly earlier versions)
paint.setBrushOrigin(0, 0);
int x = highlightX_, y = highlightY_;
paintSquare(x, y, paint);
paintPainterClip(paint, dragX_, dragY_, size_, size_);
// NOTE: clipping is now activated in the TQPainter paint
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(TQMouseEvent *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)) {
TQPainter paint(this);
changeCursor(&sizeAllCursor);
if (levelMap_->goal(x, y))
imageData_->brightTreasure(paint, x2pixel(x), y2pixel(y));
else
imageData_->brightObject(paint, x2pixel(x), y2pixel(y));
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(TQWheelEvent *e) {
wheelDelta_ += e->delta();
if (wheelDelta_ >= 120) {
wheelDelta_ %= 120;
redo();
} else if (wheelDelta_ <= -120) {
wheelDelta_ = -(-wheelDelta_ % 120);
undo();
}
}
void
PlayField::mouseReleaseEvent(TQMouseEvent *e) {
if (dragInProgress_) dragObject(e->x(), e->y());
}
void
PlayField::focusInEvent(TQFocusEvent *) {
//printf("PlayField::focusInEvent\n");
}
void
PlayField::focusOutEvent(TQFocusEvent *) {
//printf("PlayField::focusOutEvent\n");
}
void
PlayField::leaveEvent(TQEvent *) {
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);
collXpm_.resize(collRect_.size());
ltxtXpm_.resize(ltxtRect_.size());
lnumXpm_.resize(lnumRect_.size());
stxtXpm_.resize(stxtRect_.size());
snumXpm_.resize(snumRect_.size());
ptxtXpm_.resize(ptxtRect_.size());
pnumXpm_.resize(pnumRect_.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(false);
}
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(false);
}
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(false);
}
void
PlayField::changeCollection(LevelCollection *collection) {
if (levelMap_->collection() == collection) return;
levelMap_->changeCollection(collection);
levelChange();
//erase(collRect_);
repaint(false);
}
void
PlayField::updateCollectionXpm() {
if (collXpm_.isNull()) return;
TQPainter paint(&collXpm_);
paint.setBrushOrigin(- collRect_.x(), - collRect_.y());
paint.fillRect(0, 0, collRect_.width(), collRect_.height(), background_);
paint.setFont(statusFont_);
paint.setPen(TQColor(0,255,0));
paint.drawText(0, 0, collRect_.width(), collRect_.height(),
AlignLeft, collectionName());
}
void
PlayField::updateTextXpm() {
if (ltxtXpm_.isNull()) return;
TQPainter paint;
paint.begin(&ltxtXpm_);
paint.setBrushOrigin(- ltxtRect_.x(), - ltxtRect_.y());
paint.fillRect(0, 0, ltxtRect_.width(), ltxtRect_.height(), background_);
paint.setFont(statusFont_);
paint.setPen(TQColor(128,128,128));
paint.drawText(0, 0, ltxtRect_.width(), ltxtRect_.height(), 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(TQColor(128,128,128));
paint.drawText(0, 0, stxtRect_.width(), stxtRect_.height(), 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(TQColor(128,128,128));
paint.drawText(0, 0, ptxtRect_.width(), ptxtRect_.height(), AlignLeft, pushesText_);
paint.end();
}
void
PlayField::updateLevelXpm() {
if (lnumXpm_.isNull()) return;
TQPainter paint(&lnumXpm_);
paint.setBrushOrigin(- lnumRect_.x(), - lnumRect_.y());
paint.fillRect(0, 0, lnumRect_.width(), lnumRect_.height(), background_);
TQString str;
paint.setFont(statusFont_);
paint.setPen(TQColor(255,0,0));
paint.drawText(0, 0, lnumRect_.width(), lnumRect_.height(),
AlignLeft, str.sprintf("%05d", level()+1));
}
void
PlayField::updateStepsXpm() {
if (snumXpm_.isNull()) return;
TQPainter paint(&snumXpm_);
paint.setBrushOrigin(- snumRect_.x(), - snumRect_.y());
paint.fillRect(0, 0, snumRect_.width(), snumRect_.height(), background_);
TQString str;
paint.setFont(statusFont_);
paint.setPen(TQColor(255,0,0));
paint.drawText(0, 0, snumRect_.width(), snumRect_.height(),
AlignLeft, str.sprintf("%05d", totalMoves()));
}
void
PlayField::updatePushesXpm() {
if (pnumXpm_.isNull()) return;
TQPainter paint(&pnumXpm_);
paint.setBrushOrigin(- pnumRect_.x(), - pnumRect_.y());
paint.fillRect(0, 0, pnumRect_.width(), pnumRect_.height(), background_);
TQString str;
paint.setFont(statusFont_);
paint.setPen(TQColor(255,0,0));
paint.drawText(0, 0, pnumRect_.width(), pnumRect_.height(),
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(false);
}
bool
PlayField::canMoveNow() {
if (moveInProgress_) return false;
if (!levelMap_->goodLevel()) {
ModalLabel::message(i18n("This level is broken"), this);
return false;
}
return true;
}