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/kgoldrunner/src/kgrcanvas.cpp

562 lines
18 KiB

/***************************************************************************
kgrcanvas.cpp - description
-------------------
begin : Wed Jan 23 2002
copyright : (C) 2002 by Marco Kr<EFBFBD>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 (TQWidget * parent, const char *name)
: TQCanvasView (0, parent, name)
{
setBackgroundMode (NoBackground);
m = new TQCursor (); // 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 TQString & 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 TQCanvas.
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 (TQBrush (borderColor));
borderL->setBrush (TQBrush (borderColor));
borderR->setBrush (TQBrush (borderColor));
TQString 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;
}
TQWMatrix 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.
TQString t = title->text();
makeTitle ();
setTitle (t);
// Fit the TQCanvasView 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 TQt 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 TQCanvas [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;
TQString t = title->text();
makeTitle ();
setTitle (t);
}
void KGrCanvas::setTitle (TQString newTitle)
{
title->setText (newTitle);
}
void KGrCanvas::makeTitle ()
{
// This uses a calculated TQLabel and TQFont size because a TQCanvasText
// object does not always display scaled-up fonts cleanly (in TQt 3.1.1).
if (title != 0)
title->close (TRUE); // Close and delete previous title.
title = new TQLabel ("", 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 (TQFont (fontInfo().family(),
(baseFontSize * scaleStep) / baseScale, TQFont::Bold));
title->setAlignment (TQt::AlignCenter);
title->raise();
title->show();
}
void KGrCanvas::contentsMousePressEvent (TQMouseEvent * m) {
emit mouseClick (m->button ());
}
void KGrCanvas::contentsMouseReleaseEvent (TQMouseEvent * m) {
emit mouseLetGo (m->button ());
}
TQPoint KGrCanvas::getMousePos ()
{
int i, j;
int fw = frameWidth();
int cell = 4 * scaleStep;
TQPoint p = mapFromGlobal (m->pos());
// In KGoldrunner, the top-left visible cell is [1,1] --- in TQCanvas [2,2].
i = ((p.x() - fw) / cell) - 1; j = ((p.y() - fw) / cell) - 1;
return (TQPoint (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 TQCanvas [2,2].
i++; j++;
//m->setPos (mapToGlobal (TQPoint (i * 4 * STEP + 8, j * 4 * STEP + 8)));
//m->setPos (mapToGlobal (TQPoint (i * 5 * STEP + 10, j * 5 * STEP + 10)));
m->setPos (mapToGlobal (
TQPoint (i * cell + fw + cell / 2, j * cell + fw + cell / 2)));
}
void KGrCanvas::makeHeroSprite (int i, int j, int startFrame)
{
heroSprite = new TQCanvasSprite (heroArray, field);
// In KGoldrunner, the top-left visible cell is [1,1] --- in TQCanvas [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)
{
TQCanvasSprite * enemySprite = new TQCanvasSprite (enemyArray, field);
enemySprites->append (enemySprite);
// In KGoldrunner, the top-left visible cell is [1,1] --- in TQCanvas [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 TQCanvas [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 TQCanvas [2,2].
enemySprites->at(id)->move (x + 4 * STEP, y + 4 * STEP, frame);
updateCanvas();
}
void KGrCanvas::deleteEnemySprites()
{
enemySprites->clear();
}
TQPixmap KGrCanvas::getPixmap (char type)
{
TQPixmap pic (bgw, bgh, bgd);
TQPainter 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).
TQPixmap pixmap;
TQImage image;
pixmap = TQPixmap (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 = TQPixmap ((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 TQCanvas ((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 (TQScrollView::AlwaysOff);
setHScrollBarMode (TQScrollView::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 TQCanvasPixmapArray.
pixmap = TQPixmap (hero_xpm);
image = pixmap.convertToImage ();
#ifdef QT3
TQPixmap pm;
TQValueList<TQPixmap> pmList;
for (int i = 0; i < 20; i++) {
pm.convertFromImage (image.copy (i * 16, 0, 16, 16));
pmList.append (pm);
}
heroArray = new TQCanvasPixmapArray (pmList); // Hot spots all (0,0).
#else
TQPixmap * pm;
TQPoint * pt;
TQPtrList<TQPixmap> pmList;
TQPtrList<TQPoint> ptList;
pt = new TQPoint (0, 0); // "Hot spot" not used in KGoldrunner.
for (int i = 0; i < 20; i++) {
pm = new TQPixmap ();
pm->convertFromImage (image.copy (i * 16, 0, 16, 16));
pmList.append (pm);
ptList.append (pt);
}
heroArray = new TQCanvasPixmapArray (pmList, ptList);
#endif
// Convert pixmap strips for enemy animations into a TQCanvasPixmapArray.
// First convert the pixmaps for enemies with no gold ...
pixmap = TQPixmap (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 TQPixmap ();
pm->convertFromImage (image.copy (i * 16, 0, 16, 16));
pmList.append (pm);
ptList.append (pt);
}
#endif
// ... then convert the gold-carrying enemies.
pixmap = TQPixmap (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 TQCanvasPixmapArray (pmList); // Hot spots all (0,0).
#else
for (int i = 0; i < 20; i++) {
pm = new TQPixmap ();
pm->convertFromImage (image.copy (i * 16, 0, 16, 16));
pmList.append (pm);
ptList.append (pt);
}
enemyArray = new TQCanvasPixmapArray (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 TQPtrList<TQCanvasSprite> ();
#else
enemySprites = new TQPtrList<TQCanvasSprite> ();
#endif
enemySprites->setAutoDelete(TRUE);
}
void KGrCanvas::makeTiles ()
{
TQPainter p (& bgPix);
// First draw the single pixmaps (8 tiles) ...
p.drawPixmap (freebg * bgw, 0, TQPixmap (hgbrick_xpm)); // Free space.
p.drawPixmap (nuggetbg * bgw, 0, TQPixmap (nugget_xpm)); // Nugget.
p.drawPixmap (polebg * bgw, 0, TQPixmap (pole_xpm)); // Pole or bar.
p.drawPixmap (ladderbg * bgw, 0, TQPixmap (ladder_xpm)); // Ladder.
p.drawPixmap (hladderbg * bgw, 0, TQPixmap (hladder_xpm)); // Hidden laddr.
p.drawPixmap (edherobg * bgw, 0, TQPixmap (edithero_xpm)); // Static hero.
p.drawPixmap (edenemybg * bgw, 0, TQPixmap (editenemy_xpm)); // Static enemy.
p.drawPixmap (betonbg * bgw, 0, TQPixmap (beton_xpm)); // Concrete.
// ... then add the 10 brick pixmaps.
p.drawPixmap (brickbg * bgw, 0, TQPixmap (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 TQLabel 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 = TQColor (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);
}
TQCanvasRectangle * KGrCanvas::drawRectangle (int z, int x, int y, int w, int h)
{
TQCanvasRectangle * r = new TQCanvasRectangle (x, y, w, h, field);
r->setBrush (TQBrush (colour));
r->setPen (TQPen (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 = TQColor (colours [1]);
textColor = TQColor (colours [2]);
KGrThumbNail::backgroundColor = TQColor (TQString(colours [3]).right(7));
KGrThumbNail::brickColor = TQColor (TQString(colours [6]).right(7));
KGrThumbNail::ladderColor = TQColor (TQString(colours [9]).right(7));
KGrThumbNail::poleColor = TQColor (TQString(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"