summaryrefslogtreecommitdiffstats
path: root/ksmiletris/gamewidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ksmiletris/gamewidget.cpp')
-rw-r--r--ksmiletris/gamewidget.cpp518
1 files changed, 518 insertions, 0 deletions
diff --git a/ksmiletris/gamewidget.cpp b/ksmiletris/gamewidget.cpp
new file mode 100644
index 00000000..7bead2f7
--- /dev/null
+++ b/ksmiletris/gamewidget.cpp
@@ -0,0 +1,518 @@
+/****************************************************************
+Copyright (c) 1998 Sandro Sigala <ssigala@globalnet.it>.
+All rights reserved.
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of the author not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+The author disclaim all warranties with regard to this
+software, including all implied warranties of merchantability
+and fitness. In no event shall the author be liable for any
+special, indirect or consequential damages or any damages
+whatsoever resulting from loss of use, data or profits, whether
+in an action of contract, negligence or other tortious action,
+arising out of or in connection with the use or performance of
+this software.
+****************************************************************/
+
+#include "config.h"
+
+#include <kaudioplayer.h>
+#include <kapplication.h>
+#include <kstandarddirs.h>
+#include <qbitmap.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qtimer.h>
+#ifdef HAVE_USLEEP
+#include <unistd.h>
+#endif
+
+#include "ksmiletris.h"
+#include "gamewidget.h"
+#include "screenwidget.h"
+#include "mirrorwidget.h"
+#include "npiecewidget.h"
+
+#include <kmessagebox.h>
+#include <klocale.h>
+
+GameWidget::GameWidget(QWidget *parent, const char *name)
+ : QWidget(parent, name)
+{
+ in_game = false;
+ in_pause = false;
+
+ random.setSeed(0);
+
+ loadSprites();
+ setPieces(Pieces_Smiles);
+
+ map = new Sprite[scr_width * scr_height];
+ mirror_sprites = new Sprite[scr_width];
+
+ screen = new ScreenWidget(sprites, &in_game, &in_pause, this);
+ screen->move(10, 10);
+ screen->setScreenSprites(map);
+
+ mirror = new MirrorWidget(sprites, &in_game, &in_pause, this);
+ mirror->move(10, 407);
+ mirror->setMirrorSprites(mirror_sprites);
+
+ next = new NextPieceWidget(sprites, &in_game, &in_pause, this);
+ next->move(278, 10);
+ next->setNextPieceSprites(next_piece);
+
+ timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), this, SLOT(timeout()));
+}
+
+GameWidget::~GameWidget()
+{
+ delete [] sprites;
+ delete [] map;
+ delete [] mirror_sprites;
+}
+
+void GameWidget::playSound(Sound s)
+{
+ if (!do_sounds)
+ return;
+
+ QString name;
+ switch (s) {
+ case Sound_Break:
+ name = "break.wav";
+ break;
+ case Sound_Clear:
+ name = "clear.wav";
+ break;
+ }
+
+ KAudioPlayer::play(locate("data", QString("ksmiletris/sounds/") + name));
+}
+
+void GameWidget::setPieces(PiecesType type)
+{
+ QString prefix;
+
+ switch (type) {
+ case Pieces_Smiles:
+ prefix = "block-a";
+ loadSprite(Sprite_Cleared, "cleared-a.bmp");
+ break;
+ case Pieces_Symbols:
+ prefix = "block-b";
+ loadSprite(Sprite_Cleared, "cleared-b.bmp");
+ break;
+ case Pieces_Icons:
+ prefix = "block-c";
+ loadSprite(Sprite_Cleared, "cleared-c.bmp");
+ }
+
+ for (int i = 0; i < num_blocks; ++i) {
+ QString n;
+ n.setNum(i + 1);
+ loadSprite((Sprite)(Sprite_Block1 + i), prefix + n + ".bmp");
+ }
+ QPixmap pm(32, 32);
+ for (int i = 0; i < num_blocks; ++i) {
+ QPainter p;
+ p.begin(&pm);
+ p.drawPixmap(0, 0, sprites[Sprite_Block1 + i]);
+ p.drawPixmap(0, 0, sprites[Sprite_Broken]);
+ p.end();
+ sprites[Sprite_Broken1 + i] = pm;
+ }
+
+ if (in_game) repaintChilds();
+}
+
+void GameWidget::loadSprites()
+{
+ sprites = new QPixmap[num_sprites];
+ loadSprite(Sprite_Bg1, "bg1.bmp");
+ loadSprite(Sprite_Bg2, "bg2.bmp");
+ loadSprite(Sprite_Bg3, "bg3.bmp");
+ loadSprite(Sprite_Bg4, "bg4.bmp");
+ loadSprite(Sprite_Bg5, "bg5.bmp");
+ loadSprite(Sprite_Bg6, "bg6.bmp");
+ loadSprite(Sprite_Bg7, "bg7.bmp");
+ loadSprite(Sprite_Bg8, "bg8.bmp");
+ loadSprite(Sprite_Bg9, "bg9.bmp");
+ loadSprite(Sprite_Bg10, "bg10.bmp");
+ loadSprite(Sprite_Bg11, "bg11.bmp");
+ loadSprite(Sprite_Bg12, "bg12.bmp");
+ loadSprite(Sprite_Bg13, "bg13.bmp");
+ loadSprite(Sprite_Bg14, "bg14.bmp");
+ loadSprite(Sprite_Bg15, "bg15.bmp");
+ loadSprite(Sprite_Bg16, "bg16.bmp");
+ loadMaskedSprite(Sprite_Broken, "broken.bmp", "broken-mask.bmp");
+}
+
+void GameWidget::loadSprite(Sprite spr, const QString & path)
+{
+ if (!sprites[spr].load(locate("appdata", QString("data/") + path)))
+ qFatal("Cannot open data files.\nHave you correctly installed KSmiletris?");
+}
+
+void GameWidget::loadMaskedSprite(Sprite spr, const QString & path1, const QString & path2)
+{
+ QBitmap bmp;
+ if (!sprites[spr].load(locate("appdata", QString("data/") + path1)))
+ qFatal("Cannot open data files.\nHave you correctly installed KSmiletris?");
+ if (!bmp.load(locate("appdata", QString("data/") + path2)))
+ qFatal("Cannot open data files.\nHave you correctly installed KSmiletris?");
+ sprites[spr].setMask(bmp);
+}
+
+void GameWidget::newGame()
+{
+ in_pause = false;
+ fast_mode = false;
+
+ num_level = 1;
+ num_pieces_level = 2;
+ num_points = 0;
+
+ bg_sprite = (Sprite)(Sprite_Bg1 + random.getLong(num_bgs));
+ screen->setBackgroundSprite(bg_sprite);
+ mirror->setBackgroundSprite(bg_sprite);
+ next->setBackgroundSprite(bg_sprite);
+ for (int i = 0; i < scr_width; ++i)
+ mirror_sprites[i] = bg_sprite;
+ for (int i = 0; i < 4; ++i)
+ next_piece[i] = bg_sprite;
+ for (int y = 0; y < scr_height; ++y)
+ for (int x = 0; x < scr_width; ++x)
+ ref(x, y) = bg_sprite;
+
+ newPiece();
+ nextPiece();
+ updateMirror();
+
+ in_game = true;
+ repaintChilds();
+ emit changedStats(num_level, num_points);
+ timer_interval = 700;
+ timer->start(timer_interval);
+}
+
+void GameWidget::repaintChilds()
+{
+ screen->repaint(false);
+ mirror->repaint(false);
+ next->repaint(false);
+}
+
+void GameWidget::putPiece()
+{
+ if (piece[0] != bg_sprite) ref(xpos + 0, ypos + 0) = piece[0];
+ if (piece[1] != bg_sprite) ref(xpos + 1, ypos + 0) = piece[1];
+ if (piece[2] != bg_sprite) ref(xpos + 0, ypos + 1) = piece[2];
+ if (piece[3] != bg_sprite) ref(xpos + 1, ypos + 1) = piece[3];
+ updateMirror();
+ screen->repaint(false);
+}
+
+void GameWidget::getPiece()
+{
+ if (piece[0] != bg_sprite) ref(xpos + 0, ypos + 0) = bg_sprite;
+ if (piece[1] != bg_sprite) ref(xpos + 1, ypos + 0) = bg_sprite;
+ if (piece[2] != bg_sprite) ref(xpos + 0, ypos + 1) = bg_sprite;
+ if (piece[3] != bg_sprite) ref(xpos + 1, ypos + 1) = bg_sprite;
+}
+
+void GameWidget::newPiece()
+{
+ static int pieces[][4] = {{1, 0, 1, 1},
+ {1, 1, 1, 0},
+ {1, 1, 0, 1},
+ {0, 1, 1, 1}};
+ int p = random.getLong(4);
+ for (int i = 0; i < 4; ++i)
+ if (pieces[p][i])
+ next_piece[i] = (Sprite)(Sprite_Block1 + random.getLong(num_pieces_level));
+ else
+ next_piece[i] = bg_sprite;
+ next->repaint(false);
+}
+
+void GameWidget::nextPiece()
+{
+ piece[0] = next_piece[0];
+ piece[1] = next_piece[1];
+ piece[2] = next_piece[2];
+ piece[3] = next_piece[3];
+ newPiece();
+ xpos = (scr_width - 2) / 2;
+ ypos = 0;
+ if ((piece[0] != bg_sprite && ref(xpos + 0, ypos + 0) != bg_sprite)
+ || (piece[1] != bg_sprite && ref(xpos + 1, ypos + 0) != bg_sprite)
+ || (piece[2] != bg_sprite && ref(xpos + 0, ypos + 1) != bg_sprite)
+ || (piece[3] != bg_sprite && ref(xpos + 1, ypos + 1) != bg_sprite)) {
+ in_game = false;
+ repaintChilds();
+ KMessageBox::sorry(this, i18n("Game Over"));
+ emit gameOver();
+ }
+
+ putPiece();
+}
+
+void GameWidget::updateMirror()
+{
+ for (int x = 0; x < scr_width; ++x)
+ mirror_sprites[x] = bg_sprite;
+ mirror_sprites[xpos] = piece[2] == bg_sprite ? piece[0] : piece[2];
+ mirror_sprites[xpos+1] = piece[3] == bg_sprite ? piece[1] : piece[3];
+ mirror->repaint(false);
+}
+
+void GameWidget::keyUp()
+{
+ if (!in_game || in_pause) return;
+
+ getPiece();
+ if ((piece[0] == bg_sprite && ref(xpos + 0, ypos + 0) != bg_sprite)
+ || (piece[1] == bg_sprite && ref(xpos + 1, ypos + 0) != bg_sprite)
+ || (piece[2] == bg_sprite && ref(xpos + 0, ypos + 1) != bg_sprite)
+ || (piece[3] == bg_sprite && ref(xpos + 1, ypos + 1) != bg_sprite)) {
+ putPiece();
+ return;
+ }
+
+ Sprite npiece[4];
+ npiece[2] = piece[0];
+ npiece[0] = piece[1];
+ npiece[3] = piece[2];
+ npiece[1] = piece[3];
+ for (int i = 0; i < 4; ++i)
+ piece[i] = npiece[i];
+ putPiece();
+}
+
+void GameWidget::keyDown()
+{
+ if (!in_game || in_pause) return;
+
+ getPiece();
+ if ((piece[0] == bg_sprite && ref(xpos + 0, ypos + 0) != bg_sprite)
+ || (piece[1] == bg_sprite && ref(xpos + 1, ypos + 0) != bg_sprite)
+ || (piece[2] == bg_sprite && ref(xpos + 0, ypos + 1) != bg_sprite)
+ || (piece[3] == bg_sprite && ref(xpos + 1, ypos + 1) != bg_sprite)) {
+ putPiece();
+ return;
+ }
+
+ Sprite npiece[4];
+ npiece[0] = piece[2];
+ npiece[1] = piece[0];
+ npiece[2] = piece[3];
+ npiece[3] = piece[1];
+ for (int i = 0; i < 4; ++i)
+ piece[i] = npiece[i];
+ putPiece();
+}
+
+void GameWidget::keyLeft()
+{
+ if (!in_game || in_pause || xpos == 0) return;
+
+ getPiece();
+ if ((piece[0] != bg_sprite && ref(xpos - 1, ypos + 0) != bg_sprite)
+ || (piece[1] != bg_sprite && ref(xpos + 0, ypos + 0) != bg_sprite)
+ || (piece[2] != bg_sprite && ref(xpos - 1, ypos + 1) != bg_sprite)
+ || (piece[3] != bg_sprite && ref(xpos + 0, ypos + 1) != bg_sprite)) {
+ putPiece();
+ return;
+ }
+
+ --xpos;
+ putPiece();
+}
+
+void GameWidget::keyRight()
+{
+ if (!in_game || in_pause || xpos == scr_width - 2) return;
+
+ getPiece();
+ if ((piece[0] != bg_sprite && ref(xpos + 1, ypos + 0) != bg_sprite)
+ || (piece[1] != bg_sprite && ref(xpos + 2, ypos + 0) != bg_sprite)
+ || (piece[2] != bg_sprite && ref(xpos + 1, ypos + 1) != bg_sprite)
+ || (piece[3] != bg_sprite && ref(xpos + 2, ypos + 1) != bg_sprite)) {
+ putPiece();
+ return;
+ }
+
+ ++xpos;
+ putPiece();
+}
+
+void GameWidget::keySpace()
+{
+ if (!in_game || in_pause || fast_mode) return;
+ fast_mode = true;
+ timer->changeInterval(50);
+}
+
+void GameWidget::broke(int x, int y, bool *xmap)
+{
+ xmap[y*scr_width + x] = true;
+ if (ref(x, y) >= Sprite_Broken1) {
+ // Clear the piece
+ playSound(Sound_Clear);
+ ref(x, y) = Sprite_Cleared;
+ num_points += 20;
+ } else {
+ // Break the piece
+ playSound(Sound_Break);
+ ref(x, y) = (Sprite)(Sprite_Broken1 + ref(x, y) - Sprite_Block1);
+ num_points += 10;
+ }
+ int level = num_points / 1000 + 1;
+ if (level > num_level) {
+ num_level = level;
+ num_pieces_level = (num_level/2 + 2) > num_blocks ?
+ num_blocks : num_level/2 + 2;
+ timer_interval = timer_interval - 25;
+ if (timer_interval < 50)
+ timer_interval = 50;
+ timer->changeInterval(timer_interval);
+ }
+
+ emit changedStats(num_level, num_points);
+
+#ifdef HAVE_USLEEP
+ screen->repaint(false);
+ usleep(75 * 1000);
+#endif
+}
+
+void GameWidget::recBroke(int x, int y, bool *xmap)
+{
+ int t = type(ref(x, y));
+
+ broke(x, y, xmap);
+ // X-1, Y
+ if (x > 0 && !xmap[y*scr_width + x - 1] && type(ref(x-1, y)) == t)
+ recBroke(x-1, y, xmap);
+ // X+1, Y
+ if (x < scr_width-1 && !xmap[y*scr_width + x + 1] && type(ref(x+1, y)) == t)
+ recBroke(x+1, y, xmap);
+ // X, Y-1
+ if (y > 0 && !xmap[(y-1)*scr_width + x] && type(ref(x, y-1)) == t)
+ recBroke(x, y-1, xmap);
+ // X, Y+1
+ if (y < scr_height-1 && !xmap[(y+1)*scr_width + x] && type(ref(x, y+1)) == t)
+ recBroke(x, y+1, xmap);
+
+ // X-1, Y+1
+ if (x > 0 && y < scr_height-1 && !xmap[(y+1)*scr_width + x - 1] && type(ref(x-1, y+1)) == t)
+ recBroke(x-1, y+1, xmap);
+ // X+1, Y+1
+ if (x < scr_width-1 && y < scr_height-1 && !xmap[(y+1)*scr_width + x + 1] && type(ref(x+1, y+1)) == t)
+ recBroke(x+1, y+1, xmap);
+ // X-1, Y-1
+ if (x > 0 && y > 0 && !xmap[(y-1)*scr_width + x - 1] && type(ref(x-1, y-1)) == t)
+ recBroke(x-1, y-1, xmap);
+ // X+1, Y-1
+ if (x < scr_width-1 && y > 0 && !xmap[(y-1)*scr_width + x + 1] && type(ref(x+1, y-1)) == t)
+ recBroke(x+1, y-1, xmap);
+}
+
+void GameWidget::checkSolePiece(int x, int y, bool *xmap)
+{
+ if (y < scr_height-1 && type(ref(x, y+1)) == type(ref(x, y)))
+ recBroke(x, y, xmap);
+}
+
+void GameWidget::checkPiece(int x, int y)
+{
+ bool xmap[scr_width * scr_height];
+ for (int yy = 0; yy < scr_height; ++yy)
+ for (int x = 0; x < scr_width; ++x)
+ xmap[yy*scr_width + x] = false;
+ checkSolePiece(x, y, xmap);
+}
+
+void GameWidget::compact()
+{
+ recheck:
+ bool moved = true;
+ while (moved) {
+ moved = false;
+ for (int x = 0; x < scr_width; ++x)
+ for (int y = scr_height - 1; y > 0; --y)
+ if (ref(x, y) == bg_sprite
+ || ref(x, y) == Sprite_Cleared) {
+ int i;
+ for (i = y-1; i >= 0; --i)
+ if (ref(x, i) != bg_sprite
+ && ref(x, i) != Sprite_Cleared) {
+ ref(x, y) = ref(x, i);
+ ref(x, i) = bg_sprite;
+ moved = true;
+ checkPiece(x, y);
+ goto recheck;
+ break;
+ }
+ if (i < 0)
+ ref(x, y) = bg_sprite;
+ }
+ }
+}
+
+void GameWidget::blockPiece()
+{
+ if (fast_mode) {
+ timer->changeInterval(timer_interval);
+ fast_mode = false;
+ }
+ putPiece();
+ bool xmap[scr_width * scr_height];
+ for (int yy = 0; yy < scr_height; ++yy)
+ for (int x = 0; x < scr_width; ++x)
+ xmap[yy*scr_width + x] = false;
+ if (piece[2] != bg_sprite)
+ checkSolePiece(xpos, ypos+1, xmap);
+ if (piece[3] != bg_sprite)
+ checkSolePiece(xpos+1, ypos+1, xmap);
+ if (piece[2] == bg_sprite)
+ checkSolePiece(xpos, ypos, xmap);
+ if (piece[3] == bg_sprite)
+ checkSolePiece(xpos+1, ypos, xmap);
+ compact();
+ nextPiece();
+}
+
+void GameWidget::timeout()
+{
+ if (!in_game || in_pause)
+ return;
+
+ getPiece();
+ if (ypos == scr_height - 2) {
+ blockPiece();
+ return;
+ }
+
+ if ((piece[0] != bg_sprite && ref(xpos + 0, ypos + 1) != bg_sprite)
+ || (piece[1] != bg_sprite && ref(xpos + 1, ypos + 1) != bg_sprite)
+ || (piece[2] != bg_sprite && ref(xpos + 0, ypos + 2) != bg_sprite)
+ || (piece[3] != bg_sprite && ref(xpos + 1, ypos + 2) != bg_sprite))
+ blockPiece();
+ else {
+ ++ypos;
+ putPiece();
+ }
+
+}
+
+#include "gamewidget.moc"