summaryrefslogtreecommitdiffstats
path: root/kgoldrunner/src/kgrcanvas.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kgoldrunner/src/kgrcanvas.cpp')
-rw-r--r--kgoldrunner/src/kgrcanvas.cpp561
1 files changed, 561 insertions, 0 deletions
diff --git a/kgoldrunner/src/kgrcanvas.cpp b/kgoldrunner/src/kgrcanvas.cpp
new file mode 100644
index 00000000..6104939e
--- /dev/null
+++ b/kgoldrunner/src/kgrcanvas.cpp
@@ -0,0 +1,561 @@
+/***************************************************************************
+ kgrcanvas.cpp - description
+ -------------------
+ begin : Wed Jan 23 2002
+ copyright : (C) 2002 by Marco Krüger and Ian Wadham
+ email : See menu "Help, About KGoldrunner"
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifdef KGR_PORTABLE
+// If compiling for portability, redefine KDE's i18n.
+#define i18n tr
+#endif
+
+#include "kgrconsts.h"
+
+#include "kgrdialog.h"
+#include "kgrcanvas.h"
+#include "kgrgame.h"
+
+// Graphics files for moving figures and background.
+#include "hero.xpm"
+#include "enemy1.xpm"
+#include "enemy2.xpm"
+#include "kgraphics.h"
+
+class KGoldrunner;
+
+KGrCanvas::KGrCanvas (QWidget * parent, const char *name)
+ : QCanvasView (0, parent, name)
+{
+ setBackgroundMode (NoBackground);
+ m = new QCursor (); // For handling the mouse.
+
+ scaleStep = STEP; // Initial scale is 1:1.
+ baseScale = scaleStep;
+ baseFontSize = fontInfo().pointSize();
+
+ border = 4; // Allow 2 tile-widths on each side for border.
+ cw = 4*STEP; // Playfield cell width (= four steps).
+ bw = border*cw/2; // Total border width (= two cells).
+ lw = cw/8; // Line width (for edge of border).
+ mw = bw - lw; // Border main-part width.
+
+ initView(); // Set up the graphics, etc.
+}
+
+KGrCanvas::~KGrCanvas()
+{
+}
+
+void KGrCanvas::changeLandscape (const QString & name)
+{
+ for (int i = 0; strcmp (colourScheme [i], "") != 0; i++) {
+ if (colourScheme [i] == name) {
+
+ // Change XPM colours and re-draw the tile-pictures used by QCanvas.
+ changeColours (& colourScheme [i]);
+ makeTiles();
+
+ // Set all cells to same tile-numbers as before, but new colours.
+ int tileNo [FIELDWIDTH] [FIELDHEIGHT];
+ int offset = border / 2;
+
+ for (int x = 0; x < FIELDWIDTH; x++) {
+ for (int y = 0; y < FIELDHEIGHT; y++) {
+ tileNo[x][y] = field->tile (x + offset, y + offset);
+ }
+ }
+
+ field->setTiles (bgPix, (FIELDWIDTH+border), (FIELDHEIGHT+border),
+ bgw, bgh); // Sets all tile-numbers to 0.
+
+ for (int x = 0; x < FIELDWIDTH; x++) {
+ for (int y = 0; y < FIELDHEIGHT; y++) {
+ field->setTile (x + offset, y + offset, tileNo[x][y]);
+ }
+ }
+
+ borderB->setBrush (QBrush (borderColor));
+ borderL->setBrush (QBrush (borderColor));
+ borderR->setBrush (QBrush (borderColor));
+
+ QString t = title->text();
+ makeTitle ();
+ setTitle (t);
+
+ // Repaint the playing area.
+ updateCanvas();
+ return;
+ }
+ }
+}
+
+bool KGrCanvas::changeSize (int d)
+{
+#ifdef QT3
+ if ((d < 0) && (scaleStep <= STEP)) {
+ // Note: Smaller scales lose detail (e.g. the joints in brickwork).
+ KGrMessage::information (this, i18n("Change Size"),
+ i18n("Sorry, you cannot make the play area any smaller."));
+ return FALSE;
+ }
+
+ if ((d >= 0) && (scaleStep >= 2 * STEP)) {
+ // Note: Larger scales go off the edge of the monitor.
+ KGrMessage::information (this, i18n("Change Size"),
+ i18n("Sorry, you cannot make the play area any larger."));
+ return FALSE;
+ }
+
+ QWMatrix wm = worldMatrix();
+ double wmScale = 1.0;
+
+ // Set the scale back to 1:1 and calculate the new scale factor.
+ wm.reset();
+ scaleStep = (d < 0) ? (scaleStep - 1) : (scaleStep + 1);
+
+ // If scale > 1:1, scale up to the new factor (e.g. 1.25:1, 1.5:1, etc.)
+ if (scaleStep > STEP) {
+ wmScale = (wmScale * scaleStep) / STEP;
+ wm.scale (wmScale, wmScale);
+ }
+ setWorldMatrix (wm);
+
+ // Force the title size and position to be re-calculated.
+ QString t = title->text();
+ makeTitle ();
+ setTitle (t);
+
+ // Fit the QCanvasView and its frame to the canvas.
+ int frame = frameWidth()*2;
+ setFixedSize ((FIELDWIDTH + 4) * 4 * scaleStep + frame,
+ (FIELDHEIGHT + 4) * 4 * scaleStep + frame);
+ return TRUE;
+
+#else
+ KGrMessage::information (this, i18n( "Change Size" ),
+ i18n( "Sorry, you cannot change the size of the playing area. "
+ "That function requires Qt Library version 3 or later." ));
+ return FALSE;
+#endif
+}
+
+void KGrCanvas::updateCanvas()
+{
+ field->update();
+}
+
+void KGrCanvas::paintCell (int x, int y, char type, int offset)
+{
+ int tileNumber = 0;
+
+ switch (type) {
+ case FREE: tileNumber = freebg; break; // Free space.
+ case NUGGET: tileNumber = nuggetbg; break; // Nugget.
+ case POLE: tileNumber = polebg; break; // Pole or bar.
+ case LADDER: tileNumber = ladderbg; break; // Ladder.
+ case HLADDER: tileNumber = hladderbg; break;// Hidden ladder (for editing).
+ case HERO: tileNumber = edherobg; break; // Static hero (for editing).
+ case ENEMY: tileNumber = edenemybg; break;// Static enemy (for editing).
+ case BETON: tileNumber = betonbg; break; // Concrete.
+ case BRICK: tileNumber = brickbg; break; // Solid brick.
+ case FBRICK: tileNumber = fbrickbg; break; // False brick (for editing).
+ default: tileNumber = freebg; break;
+ }
+
+ tileNumber = tileNumber + offset; // Offsets 1-9 are for digging sequence.
+
+ // In KGoldrunner, the top-left visible cell is [1,1] --- in QCanvas [2,2].
+ x++; y++;
+ field->setTile (x, y, tileNumber); // Paint cell with required pixmap.
+}
+
+void KGrCanvas::setBaseScale ()
+{
+ // Synchronise the desktop font size with the initial canvas scale.
+ baseScale = scaleStep;
+ QString t = title->text();
+ makeTitle ();
+ setTitle (t);
+}
+
+void KGrCanvas::setTitle (QString newTitle)
+{
+ title->setText (newTitle);
+}
+
+void KGrCanvas::makeTitle ()
+{
+ // This uses a calculated QLabel and QFont size because a QCanvasText
+ // object does not always display scaled-up fonts cleanly (in Qt 3.1.1).
+
+ if (title != 0)
+ title->close (TRUE); // Close and delete previous title.
+
+ title = new QLabel ("", this);
+ title->setFixedWidth (((FIELDWIDTH * cw + 2 * bw) * scaleStep) / STEP);
+ title->setFixedHeight ((mw * scaleStep) / STEP);
+ title->move (0, 0);
+ title->setPaletteBackgroundColor (borderColor);
+ title->setPaletteForegroundColor (textColor);
+ title->setFont (QFont (fontInfo().family(),
+ (baseFontSize * scaleStep) / baseScale, QFont::Bold));
+ title->setAlignment (Qt::AlignCenter);
+ title->raise();
+ title->show();
+}
+
+void KGrCanvas::contentsMousePressEvent (QMouseEvent * m) {
+ emit mouseClick (m->button ());
+}
+
+void KGrCanvas::contentsMouseReleaseEvent (QMouseEvent * m) {
+ emit mouseLetGo (m->button ());
+}
+
+QPoint KGrCanvas::getMousePos ()
+{
+ int i, j;
+ int fw = frameWidth();
+ int cell = 4 * scaleStep;
+ QPoint p = mapFromGlobal (m->pos());
+
+ // In KGoldrunner, the top-left visible cell is [1,1] --- in QCanvas [2,2].
+ i = ((p.x() - fw) / cell) - 1; j = ((p.y() - fw) / cell) - 1;
+
+ return (QPoint (i, j));
+}
+
+void KGrCanvas::setMousePos (int i, int j)
+{
+ int fw = frameWidth();
+ int cell = 4 * scaleStep;
+
+ // In KGoldrunner, the top-left visible cell is [1,1] --- in QCanvas [2,2].
+ i++; j++;
+ //m->setPos (mapToGlobal (QPoint (i * 4 * STEP + 8, j * 4 * STEP + 8)));
+ //m->setPos (mapToGlobal (QPoint (i * 5 * STEP + 10, j * 5 * STEP + 10)));
+ m->setPos (mapToGlobal (
+ QPoint (i * cell + fw + cell / 2, j * cell + fw + cell / 2)));
+}
+
+void KGrCanvas::makeHeroSprite (int i, int j, int startFrame)
+{
+ heroSprite = new QCanvasSprite (heroArray, field);
+
+ // In KGoldrunner, the top-left visible cell is [1,1] --- in QCanvas [2,2].
+ i++; j++;
+ heroSprite->move (i * 4 * STEP, j * 4 * STEP, startFrame);
+ heroSprite->setZ (1);
+ heroSprite->setVisible (TRUE);
+}
+
+void KGrCanvas::setHeroVisible (bool newState)
+{
+ heroSprite->setVisible (newState); // Show or hide the hero.
+}
+
+void KGrCanvas::makeEnemySprite (int i, int j, int startFrame)
+{
+ QCanvasSprite * enemySprite = new QCanvasSprite (enemyArray, field);
+
+ enemySprites->append (enemySprite);
+
+ // In KGoldrunner, the top-left visible cell is [1,1] --- in QCanvas [2,2].
+ i++; j++;
+ enemySprite->move (i * 4 * STEP, j * 4 * STEP, startFrame);
+ enemySprite->setZ (2);
+ enemySprite->show();
+}
+
+void KGrCanvas::moveHero (int x, int y, int frame)
+{
+ // In KGoldrunner, the top-left visible cell is [1,1] --- in QCanvas [2,2].
+ heroSprite->move (x + 4 * STEP, y + 4 * STEP, frame);
+ updateCanvas();
+}
+
+void KGrCanvas::moveEnemy (int id, int x, int y, int frame, int nuggets)
+{
+ if (nuggets != 0) { // If enemy is carrying gold,
+ frame = frame + goldEnemy; // show him with gold outline.
+ }
+
+ // In KGoldrunner, the top-left visible cell is [1,1] --- in QCanvas [2,2].
+ enemySprites->at(id)->move (x + 4 * STEP, y + 4 * STEP, frame);
+ updateCanvas();
+}
+
+void KGrCanvas::deleteEnemySprites()
+{
+ enemySprites->clear();
+}
+
+QPixmap KGrCanvas::getPixmap (char type)
+{
+ QPixmap pic (bgw, bgh, bgd);
+ QPainter p (& pic);
+ int tileNumber;
+
+ // Get a pixmap from the tile-array for use on an edit-button.
+ switch (type) {
+ case FREE: tileNumber = freebg; break; // Free space.
+ case NUGGET: tileNumber = nuggetbg; break; // Nugget.
+ case POLE: tileNumber = polebg; break; // Pole or bar.
+ case LADDER: tileNumber = ladderbg; break; // Ladder.
+ case HLADDER: tileNumber = hladderbg; break;// Hidden ladder (for editing).
+ case HERO: tileNumber = edherobg; break; // Static hero (for editing).
+ case ENEMY: tileNumber = edenemybg; break;// Static enemy (for editing).
+ case BETON: tileNumber = betonbg; break; // Concrete.
+ case BRICK: tileNumber = brickbg; break; // Solid brick.
+ case FBRICK: tileNumber = fbrickbg; break; // False brick (for editing).
+ default: tileNumber = freebg; break;
+ }
+
+ // Copy a tile of width bgw and height bgh from the tile-array.
+ p.drawPixmap (0, 0, bgPix, tileNumber * bgw, 0, bgw, bgh);
+ p.end();
+
+ return (pic);
+}
+
+void KGrCanvas::initView()
+{
+ changeColours (& colourScheme [0]); // Set "KGoldrunner" landscape.
+
+ // Set up the pixmaps for the editable objects.
+ freebg = 0; // Free space.
+ nuggetbg = 1; // Nugget.
+ polebg = 2; // Pole or bar.
+ ladderbg = 3; // Ladder.
+ hladderbg = 4; // Hidden ladder (for editing).
+ edherobg = 5; // Static hero (for editing).
+ edenemybg = 6; // Static enemy (for editing).
+ betonbg = 7; // Concrete.
+
+ // The bricks have 10 pixmaps (showing various stages of digging).
+ brickbg = 8; // Solid brick - 1st pixmap.
+ fbrickbg = 15; // False brick - 8th pixmap (for editing).
+
+ QPixmap pixmap;
+ QImage image;
+
+ pixmap = QPixmap (hgbrick_xpm);
+
+ bgw = pixmap.width(); // Save dimensions for "getPixmap".
+ bgh = pixmap.height();
+ bgd = pixmap.depth();
+
+ // Assemble the background and editing pixmaps into a strip (18 pixmaps).
+ bgPix = QPixmap ((brickbg + 10) * bgw, bgh, bgd);
+
+ makeTiles(); // Fill the strip with 18 tiles.
+
+ // Define the canvas as an array of tiles. Default tile is 0 (free space).
+ int frame = frameWidth()*2;
+ field = new QCanvas ((FIELDWIDTH+border) * bgw, (FIELDHEIGHT+border) * bgh);
+ field->setTiles (bgPix, (FIELDWIDTH+border), (FIELDHEIGHT+border),
+ bgw, bgh);
+
+ // Embed the canvas in the view and make it occupy the whole of the view.
+ setCanvas (field);
+ setVScrollBarMode (QScrollView::AlwaysOff);
+ setHScrollBarMode (QScrollView::AlwaysOff);
+ setFixedSize (field->width() + frame, field->height() + frame);
+
+ //////////////////////////////////////////////////////////////////////////
+ // The pixmaps for hero and enemies are arranged in strips of 20: walk //
+ // right (4), walk left (4), climb right along bar (4), climb left (4), //
+ // climb up ladder (2) and fall (2) --- total 20. //
+ //////////////////////////////////////////////////////////////////////////
+
+ // Convert the pixmap strip for hero animation into a QCanvasPixmapArray.
+ pixmap = QPixmap (hero_xpm);
+ image = pixmap.convertToImage ();
+
+#ifdef QT3
+ QPixmap pm;
+ QValueList<QPixmap> pmList;
+
+ for (int i = 0; i < 20; i++) {
+ pm.convertFromImage (image.copy (i * 16, 0, 16, 16));
+ pmList.append (pm);
+ }
+
+ heroArray = new QCanvasPixmapArray (pmList); // Hot spots all (0,0).
+#else
+ QPixmap * pm;
+ QPoint * pt;
+ QList<QPixmap> pmList;
+ QList<QPoint> ptList;
+
+ pt = new QPoint (0, 0); // "Hot spot" not used in KGoldrunner.
+
+ for (int i = 0; i < 20; i++) {
+ pm = new QPixmap ();
+ pm->convertFromImage (image.copy (i * 16, 0, 16, 16));
+ pmList.append (pm);
+ ptList.append (pt);
+ }
+
+ heroArray = new QCanvasPixmapArray (pmList, ptList);
+#endif
+
+ // Convert pixmap strips for enemy animations into a QCanvasPixmapArray.
+ // First convert the pixmaps for enemies with no gold ...
+ pixmap = QPixmap (enemy1_xpm);
+ image = pixmap.convertToImage ();
+
+ pmList.clear();
+
+#ifdef QT3
+ for (int i = 0; i < 20; i++) {
+ pm.convertFromImage (image.copy (i * 16, 0, 16, 16));
+ pmList.append (pm);
+ }
+#else
+ ptList.clear();
+
+ for (int i = 0; i < 20; i++) {
+ pm = new QPixmap ();
+ pm->convertFromImage (image.copy (i * 16, 0, 16, 16));
+ pmList.append (pm);
+ ptList.append (pt);
+ }
+#endif
+
+ // ... then convert the gold-carrying enemies.
+ pixmap = QPixmap (enemy2_xpm);
+ image = pixmap.convertToImage ();
+
+#ifdef QT3
+ for (int i = 0; i < 20; i++) {
+ pm.convertFromImage (image.copy (i * 16, 0, 16, 16));
+ pmList.append (pm);
+ }
+
+ enemyArray = new QCanvasPixmapArray (pmList); // Hot spots all (0,0).
+#else
+ for (int i = 0; i < 20; i++) {
+ pm = new QPixmap ();
+ pm->convertFromImage (image.copy (i * 16, 0, 16, 16));
+ pmList.append (pm);
+ ptList.append (pt);
+ }
+
+ enemyArray = new QCanvasPixmapArray (pmList, ptList);
+#endif
+
+ goldEnemy = 20; // Offset of gold-carrying frames.
+
+ // Draw the border around the playing area (z = 0).
+ makeBorder();
+
+ // Create a title item, in off-white colour, on top of the border.
+ title = 0;
+ makeTitle();
+
+ // Create an empty list of enemy sprites.
+#ifdef QT3
+ enemySprites = new QPtrList<QCanvasSprite> ();
+#else
+ enemySprites = new QList<QCanvasSprite> ();
+#endif
+ enemySprites->setAutoDelete(TRUE);
+}
+
+void KGrCanvas::makeTiles ()
+{
+ QPainter p (& bgPix);
+
+ // First draw the single pixmaps (8 tiles) ...
+ p.drawPixmap (freebg * bgw, 0, QPixmap (hgbrick_xpm)); // Free space.
+ p.drawPixmap (nuggetbg * bgw, 0, QPixmap (nugget_xpm)); // Nugget.
+ p.drawPixmap (polebg * bgw, 0, QPixmap (pole_xpm)); // Pole or bar.
+ p.drawPixmap (ladderbg * bgw, 0, QPixmap (ladder_xpm)); // Ladder.
+ p.drawPixmap (hladderbg * bgw, 0, QPixmap (hladder_xpm)); // Hidden laddr.
+ p.drawPixmap (edherobg * bgw, 0, QPixmap (edithero_xpm)); // Static hero.
+ p.drawPixmap (edenemybg * bgw, 0, QPixmap (editenemy_xpm)); // Static enemy.
+ p.drawPixmap (betonbg * bgw, 0, QPixmap (beton_xpm)); // Concrete.
+
+ // ... then add the 10 brick pixmaps.
+ p.drawPixmap (brickbg * bgw, 0, QPixmap (bricks_xpm)); // Bricks.
+
+ p.end();
+}
+
+void KGrCanvas::makeBorder ()
+{
+ // Draw main part of border, in the order: top, bottom, left, right.
+ // Allow some overlap to prevent slits appearing when using "changeSize".
+ colour = borderColor;
+
+ // The first rectangle is actually a QLabel drawn by "makeTitle()".
+ // borderT = drawRectangle (11, 0, 0, FIELDWIDTH*cw + 2*bw, mw);
+ borderB = drawRectangle (11, 0, FIELDHEIGHT*cw + bw + lw,
+ FIELDWIDTH*cw + 2*bw, mw);
+ borderL = drawRectangle (12, 0, bw - lw - 1, mw, FIELDHEIGHT*cw + 2*lw + 2);
+ borderR = drawRectangle (12, FIELDWIDTH*cw + bw + lw, bw - lw - 1,
+ mw, FIELDHEIGHT*cw + 2*lw + 2);
+
+ // Draw inside edges of border, in the same way.
+ colour = QColor (black);
+ drawRectangle (10, bw-lw, bw-lw-1, FIELDWIDTH*cw + 2*lw, lw+1);
+ drawRectangle (10, bw-lw, FIELDHEIGHT*cw + bw, FIELDWIDTH*cw + 2*lw, lw+1);
+ drawRectangle (10, bw - lw, bw, lw, FIELDHEIGHT*cw);
+ drawRectangle (10, FIELDWIDTH*cw + bw, bw, lw, FIELDHEIGHT*cw);
+}
+
+QCanvasRectangle * KGrCanvas::drawRectangle (int z, int x, int y, int w, int h)
+{
+ QCanvasRectangle * r = new QCanvasRectangle (x, y, w, h, field);
+
+ r->setBrush (QBrush (colour));
+ r->setPen (QPen (NoPen));
+ r->setZ (z);
+ r->show();
+
+ return (r);
+}
+
+void KGrCanvas::changeColours (const char * colours [])
+{
+ recolourObject (hgbrick_xpm, colours);
+ recolourObject (nugget_xpm, colours);
+ recolourObject (pole_xpm, colours);
+ recolourObject (ladder_xpm, colours);
+ recolourObject (hladder_xpm, colours);
+ recolourObject (edithero_xpm, colours);
+ recolourObject (edithero_xpm, colours);
+ recolourObject (editenemy_xpm, colours);
+ recolourObject (beton_xpm, colours);
+ recolourObject (bricks_xpm, colours);
+
+ borderColor = QColor (colours [1]);
+ textColor = QColor (colours [2]);
+
+ KGrThumbNail::backgroundColor = QColor (QString(colours [3]).right(7));
+ KGrThumbNail::brickColor = QColor (QString(colours [6]).right(7));
+ KGrThumbNail::ladderColor = QColor (QString(colours [9]).right(7));
+ KGrThumbNail::poleColor = QColor (QString(colours [11]).right(7));
+}
+
+void KGrCanvas::recolourObject (const char * object [], const char * colours [])
+{
+ int i;
+ for (i = 0; i < 9; i++) {
+ object [i+1] = colours [i+3];
+ }
+}
+
+#include "kgrcanvas.moc"