author | leseb <leseb> | 2002-04-15 22:40:28 (UTC) |
---|---|---|
committer | leseb <leseb> | 2002-04-15 22:40:28 (UTC) |
commit | a91544d04ed391bbdc0c6f95ff8a80d35190788c (patch) (side-by-side diff) | |
tree | 85dea85fd8a1cdb6d2d18fef57753d0b5e4bd143 /noncore/games | |
parent | 6396d8b9fca7f3f50010a13a26e4ee9569abefb3 (diff) | |
download | opie-a91544d04ed391bbdc0c6f95ff8a80d35190788c.zip opie-a91544d04ed391bbdc0c6f95ff8a80d35190788c.tar.gz opie-a91544d04ed391bbdc0c6f95ff8a80d35190788c.tar.bz2 |
New directory structure
36 files changed, 7169 insertions, 0 deletions
diff --git a/noncore/games/kpacman/bitfont.cpp b/noncore/games/kpacman/bitfont.cpp new file mode 100644 index 0000000..40581c8 --- a/dev/null +++ b/noncore/games/kpacman/bitfont.cpp @@ -0,0 +1,71 @@ +#include "bitfont.h" + +Bitfont::Bitfont(QString fontname, uchar firstChar, uchar lastChar) +{ + if (!fontname.isEmpty()) + font.load(fontname); + if (font.width() == font.height()) { + fontWidth = fontHeight = font.width() / 16; + fontFirstChar = 1; + fontLastChar = 255; + } else { + fontWidth = font.width()/(lastChar-firstChar+1); + fontHeight = font.height(); + fontFirstChar = firstChar; + fontLastChar = lastChar; + } +} + +QRect Bitfont::rect(QString str) +{ + return QRect(0, 0, str.length()*fontWidth, fontHeight); +} + +QPixmap Bitfont::text(QString str, QColor fg, QColor bg) +{ + QPixmap FG(str.length()*fontWidth, fontHeight); + QBitmap MASK(str.length()*fontWidth, fontHeight, TRUE); + + const uchar *s = (const uchar *) str.data(); + for (uint i = 0; i < str.length(); i++) { + if (font.width() == font.height()) + bitBlt(&MASK, i*fontWidth, 0, &font, + (*s%16)*fontWidth, (*s/16)*fontWidth, fontWidth, fontHeight); + else + if (*s >= fontFirstChar && *s <= fontLastChar) + bitBlt(&MASK, i*fontWidth, 0, &font, + (*s-fontFirstChar)*fontWidth, 0, fontWidth, fontHeight); + s++; + } + + FG.fill(fg); + FG.setMask(MASK); + + if (bg.isValid()) { + QPixmap BG(str.length()*fontWidth, fontHeight); + BG.fill(bg); + bitBlt(&BG, 0, 0, &FG); + return BG; + } else + return FG; +} + +uchar Bitfont::firstChar() +{ + return fontFirstChar; +} + +uchar Bitfont::lastChar() +{ + return fontLastChar; +} + +int Bitfont::width() +{ + return fontWidth; +} + +int Bitfont::height() +{ + return fontHeight; +} diff --git a/noncore/games/kpacman/bitfont.h b/noncore/games/kpacman/bitfont.h new file mode 100644 index 0000000..c12aa0f --- a/dev/null +++ b/noncore/games/kpacman/bitfont.h @@ -0,0 +1,31 @@ +#ifndef BITFONT_H +#define BITFONT_H + +#include <qstring.h> +#include <qbitmap.h> +#include <qpixmap.h> +#include <qrect.h> + +#include "colors.h" + +class Bitfont +{ +public: + Bitfont(QString fontname, uchar firstChar, uchar lastChar); + + QPixmap text(QString str, QColor fg = BLACK, QColor bg = QColor()); + QRect rect(QString str); + int width(); + int height(); + uchar firstChar(); + uchar lastChar(); +private: + QBitmap font; + int fontWidth; + int fontHeight; + uchar fontFirstChar; + uchar fontLastChar; +}; + +#endif // BITFONT_H + diff --git a/noncore/games/kpacman/bitmaps.h b/noncore/games/kpacman/bitmaps.h new file mode 100644 index 0000000..f430384 --- a/dev/null +++ b/noncore/games/kpacman/bitmaps.h @@ -0,0 +1,67 @@ +static unsigned char demo_bits[] = { + "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" + "++*******************************************************++" + "+*********************************************************+" + "+** *** **+" + "+** . . . . . . . . . . . . *** . . . . . . . . . . . . **+" + "+** *** **+" + "+** . ******* . ********* . *** . ********* . ******* . **+" + "+** ******* ********* *** ********* ******* **+" + "+** o ******* . ********* . *** . ********* . ******* o **+" + "+** ******* ********* *** ********* ******* **+" + "+** . ******* . ********* . *** . ********* . ******* . **+" + "+** **+" + "+** . . . . . . . . . . . . . . . . . . . . . . . . . . **+" + "+** **+" + "+** . ******* . *** . *************** . *** . ******* . **+" + "+** ******* *** *************** *** ******* **+" + "+** . ******* . *** . *************** . *** . ******* . **+" + "+** *** *** *** **+" + "+** . . . . . . *** . . . . *** . . . . *** . . . . . . **+" + "+** *** *** *** **+" + "+************ . ********* *** ********* . ************+" + "++*********** ********* *** ********* ***********++" + "+++++++++++** . ********* *** ********* . **+++++++++++" + "+++++++++++** *** *** **+++++++++++" + "+++++++++++** . *** 0 *** . **+++++++++++" + "+++++++++++** *** *** **+++++++++++" + "+++++++++++** . *** ######---###### *** . **+++++++++++" + "+************ *** ######---###### *** ************+" + "+************ . *** ## ## *** . ************+" + " ## ## " + " . ## 2 1 3 ## . " + " ## ## " + "+************ . *** ## ## *** . ************+" + "+************ *** ############### *** ************+" + "+++++++++++** . *** ############### *** . **+++++++++++" + "+++++++++++** *** *** **+++++++++++" + "+++++++++++** . *** F *** . **+++++++++++" + "+++++++++++** *** *** **+++++++++++" + "+++++++++++** . *** *************** *** . **+++++++++++" + "++*********** *** *************** *** ***********++" + "+************ . *** *************** *** . ************+" + "+** *** **+" + "+** . . . . . . . . . . . . *** . . . . . . . . . . . . **+" + "+** *** **+" + "+** . ******* . ********* . *** . ********* . ******* . **+" + "+** ******* ********* *** ********* ******* **+" + "+** . ******* . ********* . *** . ********* . ******* . **+" + "+** *** *** **+" + "+** o . . *** . . . . . . . P . . . . . . . *** . . o **+" + "+** *** *** **+" + "+****** . *** . *** . *************** . *** . *** . ******+" + "+****** *** *** *************** *** *** ******+" + "+****** . *** . *** . *************** . *** . *** . ******+" + "+** *** *** *** **+" + "+** . . . . . . *** . . . . *** . . . . *** . . . . . . **+" + "+** *** *** *** **+" + "+** . ******************* . *** . ******************* . **+" + "+** ******************* *** ******************* **+" + "+** . ******************* . *** . ******************* . **+" + "+** **+" + "+** . . . . . . . . . . . . . . . . . . . . . . . . . . **+" + "+** **+" + "+*********************************************************+" + "++*******************************************************++" + "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" +}; diff --git a/noncore/games/kpacman/board.cpp b/noncore/games/kpacman/board.cpp new file mode 100644 index 0000000..849e75b --- a/dev/null +++ b/noncore/games/kpacman/board.cpp @@ -0,0 +1,425 @@ + +#include "portable.h" + +#if defined( KDE2_PORT ) +#include <kapp.h> +#include <klocale.h> +#endif + +#include <qrect.h> +#include <qregexp.h> +#include <qmessagebox.h> +#include <qfile.h> +#include <qtextstream.h> + +#include "board.h" +#include "bitmaps.h" + +Board::Board(int size) : QArray<int> (size) +{ + sz = size; // set size of board + + map = ""; + mapName = ""; // no map loaded so far + + init(None); // initialize varibales +} + +void Board::init(Image image, QString levelName) +{ + prisonEntry = OUT; + prisonExit = OUT; + fruitHome = OUT; + fruitPosition = OUT; + pacmanHome = OUT; + pacmanPosition = OUT; + for (int m = 0; m < 8; m++) { + monsterHome[m] = OUT; + monsterPosition[m] = OUT; + } + for (int e = 0; e < 8; e++) { + energizerPosition[e] = OUT; + } + for (int e = 0; e < 8; e++) { + tunnelPosition[e] = OUT; + } + + fill(0); + numPoints = 0; + numEnergizers = 0; + numMonsters = 0; + numTunnels = 0; + + if (!levelName.isNull() && !levelName.isEmpty()) + if (mapName == levelName) + image = File; + else { + QFile levelFile(levelName); + if (!levelFile.open(IO_ReadOnly)) { + + QString msg = i18n("The levelmap could not be constructed.\n\n" + "The file '@LEVELNAME@' does not exist,\n" + "or could not be opened for reading."); + msg.replace(QRegExp("@LEVELNAME@"), levelName); + // QMessageBox::information(0, i18n("Initialization Error"), msg); + printf("%s\n", msg.data()); + } else { + map.fill(' ', BoardHeight*BoardWidth); + int height = 0; + + QTextStream levelStream(&levelFile); + while (!levelStream.eof() && height < BoardHeight) { + QString line = levelStream.readLine(); + + if (line.find(QRegExp("^ *;")) == -1) { + + line.replace(QRegExp(";.*"), ""); // strip off comments + line.replace(QRegExp("\" *$"), ""); // strip off trailing " + line.replace(QRegExp("^ *\""), ""); // strip off leading " + + map.replace(height*BoardWidth, + (line.length() > BoardWidth) ? BoardWidth : line.length(), + line.data()); + + height++; + } + } + mapName = levelName; + levelFile.close(); + image = File; + } + } + + switch (image) { + case Intro : // setup(demo_bits); + break; + case Demo : setup(demo_bits); + break; + case Level : setup(demo_bits); + break; + case File : setup((uchar *) map.data()); + break; + default : break; + } +} + +void Board::setup(const uchar *buf) +{ + for ( int index = 0; buf[index] != 0 && index < BoardWidth*BoardHeight; index++ ) { + switch (buf[index]) { + case '*' : set(index, brick); break; + case '+' : set(index, out); break; + case '#' : set(index, prison); break; + case '-' : set(index, gate); break; + case 'E' : set(index, tunnel); break; + case '.' : set(index, Point); break; + case 'o' : set(index, energizer); break; + case 'I' : set(index, prisonentry); break; + case 'O' : set(index, prisonexit); break; + case 'F' : set(index, fruithome); break; + case 'P' : set(index, pacmanhome); break; + default : if (buf[index] >= '0' && buf[index] <= '7') { + set(index, monsterhome, buf[index]-(uchar)'0'); + } + } + } +} + +bool Board::inBounds(int pos) +{ + return ( pos < 0 || pos > sz-1 ? FALSE : TRUE); +} + +void Board::set(int pos, Square sq, int m) +{ + if (inBounds(pos)) + switch (sq) { + case out : at(pos) = OUT; break; + case Point : at(pos) |= pointBit; numPoints++; break; + case tunnel : at(pos) = sq; + for (int e = 0; e < numTunnels; e++) { // if tunnel is already on board + if (tunnelPosition[e] == pos) // don't do it again. + pos = OUT; + } + if (pos != OUT) { + tunnelPosition[numTunnels] = pos; + numTunnels++; + } + break; + case energizer : at(pos) |= energizerBit; + for (int e = 0; e < numEnergizers; e++) { + if (energizerPosition[e] == pos) + pos = OUT; + } + if (pos != OUT) { + energizerPosition[numEnergizers] = pos; + numEnergizers++; + } + break; + case fruit : at(pos) |= fruitBit; fruitPosition = pos; break; + case pacman : at(pos) |= pacmanBit; pacmanPosition = pos; break; + case monster : at(pos) |= (monsterBit << m); + monsterPosition[m] = pos; break; + case prisonentry : prisonEntry = pos; at(pos) = empty; break; + case prisonexit : prisonExit = pos; at(pos) = empty; break; + case fruithome : fruitHome = pos; at(pos) = empty; break; + case pacmanhome : pacmanHome = pos; at(pos) = empty; break; + case monsterhome : monsterHome[m] = pos; at(pos) = empty; + if (m == 0 && prisonExit == OUT) + prisonExit = pos; + if (m == 1 && prisonEntry == OUT) + prisonEntry = pos; + numMonsters++; + break; + default : at(pos) = sq; + } +} + +void Board::reset(int pos, Square sq, int m) +{ + bool found = FALSE; + if (inBounds(pos)) + switch (sq) { + case out : at(pos) = empty; break; + case Point : at(pos) &= ~ pointBit; numPoints--; break; + case energizer : at(pos) &= ~ energizerBit; + for (int e = 0; e < numEnergizers; e++) { // delete the position of the eaten + if (found) // energizer in the position array + energizerPosition[e-1] = energizerPosition[e]; + if (energizerPosition[e] == pos) + found = TRUE; + } + energizerPosition[numEnergizers--] = OUT; + break; + case fruit : at(pos) &= ~ fruitBit; fruitPosition = OUT; break; + case pacman : at(pos) &= ~ pacmanBit; pacmanPosition = OUT; break; + case monster : at(pos) &= ~ (monsterBit << m); + monsterPosition[m] = OUT; break; + default : at(pos) = at(pos) & varBits; + } +} + +int Board::position(Square sq, int m) +{ + switch(sq) { + case prisonentry : return prisonEntry; + case prisonexit : return prisonExit; + case fruit : return fruitPosition; + case fruithome : return fruitHome; + case pacman : return pacmanPosition; + case pacmanhome : return pacmanHome; + case monster : return monsterPosition[m]; + case monsterhome : return monsterHome[m]; + case energizer : return energizerPosition[m]; + case tunnel : return tunnelPosition[m]; + default : return OUT; + } +} + +bool Board::isOut(int pos) +{ + if (inBounds(pos)) + return (at(pos) == OUT ? TRUE : FALSE); + return TRUE; +} + +bool Board::isEmpty(int pos) +{ + if (inBounds(pos)) + return ((at(pos) & fixBits) == empty ? TRUE : FALSE); + return TRUE; +} + +bool Board::isBrick(int pos) +{ + if (inBounds(pos)) + return ((at(pos) & fixBits) == brick ? TRUE : FALSE); + return FALSE; +} + +bool Board::isPrison(int pos) +{ + if (inBounds(pos)) + return ((at(pos) & fixBits) == prison ? TRUE : FALSE); + return FALSE; +} + +bool Board::isGate(int pos) +{ + if (inBounds(pos)) + return ((at(pos) & fixBits) == gate ? TRUE : FALSE); + return FALSE; +} + +bool Board::isTunnel(int pos) +{ + if (inBounds(pos)) + return ((at(pos) & fixBits) == tunnel ? TRUE : FALSE); + return FALSE; +} + +bool Board::isPoint(int pos) +{ + if (inBounds(pos) && at(pos) != OUT) + return ((at(pos) & pointBit) != 0 ? TRUE : FALSE); + return FALSE; +} + +bool Board::isEnergizer(int pos) +{ + if (inBounds(pos) && at(pos) != OUT) + return ((at(pos) & energizerBit) != 0 ? TRUE : FALSE); + return FALSE; +} + +bool Board::isFruit(int pos) +{ + if (inBounds(pos) && at(pos) != OUT) + return ((at(pos) & fruitBit) != 0 ? TRUE : FALSE); + return FALSE; +} + +bool Board::isPacman(int pos) +{ + if (inBounds(pos) && at(pos) != OUT) + return ((at(pos) & pacmanBit) != 0 ? TRUE : FALSE); + return FALSE; +} + +bool Board::isMonster(int pos) +{ + if (inBounds(pos) && at(pos) != OUT) + return ((at(pos) & monsterBits) != 0 ? TRUE : FALSE); + return FALSE; +} + +bool Board::isWay(int pos, int dir, Square sq) { + int p1 = move(pos, dir, 2); + if (p1 == OUT) + return (sq == out ? TRUE : FALSE); + int p2, p3; + if (dir == N || dir == S) { + p2 = move(p1, E); + p3 = move(p1, W); + } else { + p2 = move(p1, N); + p3 = move(p1, S); + } + switch (sq) { + case out : return isOut(p1) | isOut(p2) | isOut(p3); + case empty : return isEmpty(p1) & isEmpty(p2) & isEmpty(p3); + case brick : return isBrick(p1) | isBrick(p2) | isBrick(p3); + case prison : return isPrison(p1) | isPrison(p2) | isPrison(p3); + case gate : return isGate(p1) & isGate(p2) & isGate(p3); + case tunnel : return isTunnel(p1) & + (isTunnel(p2) || isEmpty(p2)) & + (isTunnel(p3) || isEmpty(p3)); + default : return FALSE; + } +} + +bool Board::isJump(int pos, int dir) { + switch (dir) { + case NW: return pos < BoardWidth || x(pos) == 0; + case N: return pos < BoardWidth; + case NE: return pos < BoardWidth || x(pos) == BoardWidth-1; + case W: return x(pos) == 0; + case E: return x(pos) == BoardWidth-1; + case SW: return pos >= sz-BoardWidth || x(pos) == 0; + case S: return pos >= sz-BoardWidth; + case SE: return pos >= sz-BoardWidth || x(pos) == BoardWidth-1; + } + return FALSE; +} + +int Board::move(int pos, int dir, int steps) +{ + if (steps < 0) { // move backwards + dir = turn(dir); // turn around and do your steps + steps *= -1; + } + + while (steps-- != 0) { // until all steps are gone + switch (dir) { + case NW: pos = pos >= BoardWidth && x(pos) > 0 ? (pos-BoardWidth)-1 : sz-1; + break; + case N: pos = pos >= BoardWidth ? pos-BoardWidth : (sz-BoardWidth)+x(pos); + break; + case NE: pos = pos >= BoardWidth && x(pos) < BoardWidth-1 ? + (pos-BoardWidth)+1 : sz-BoardWidth; + break; + case W: pos = x(pos) > 0 ? pos-1 : pos+(BoardWidth-1); + break; + case E: pos = x(pos) < BoardWidth-1 ? pos+1 : pos-(BoardWidth-1); + break; + case SW: pos = pos < sz-BoardWidth && x(pos) > 0 ? (pos+BoardWidth)-1 : BoardWidth-1; + break; + case S: pos = pos < sz-BoardWidth ? pos+BoardWidth : x(pos); + break; + case SE: pos = pos < sz-BoardWidth && x(pos) < BoardWidth-1 ? (pos+BoardWidth)+1 : 0; + break; + } + } + return pos; // here we are +} + +int Board::closeup(int pos, int dir, int target) +{ + if (dir == N || dir == S) { + if (x(target) < x(pos)) + return W; + if (x(target) > x(pos)) + return E; + } else { + if (y(target) < y(pos)) + return N; + if (y(target) > y(pos)) + return S; + } + return dir; +} + +int Board::x(int pos) +{ + return pos % BoardWidth; +} + +int Board::y(int pos) +{ + return pos/BoardWidth; +} + +int Board::turn(int dir) +{ + switch (dir) { + case N : return S; + case NE : return SW; + case E : return W; + case SE : return NW; + case S : return N; + case SW : return NE; + case W : return E; + case NW : return SE; + default : return dir; + } +} + +int Board::points() +{ + return numPoints; +} + +int Board::energizers() +{ + return numEnergizers; +} + +int Board::monsters() +{ + return numMonsters; +} + +int Board::tunnels() +{ + return numTunnels; +} diff --git a/noncore/games/kpacman/board.h b/noncore/games/kpacman/board.h new file mode 100644 index 0000000..fffde95 --- a/dev/null +++ b/noncore/games/kpacman/board.h @@ -0,0 +1,102 @@ +#ifndef BOARD_H +#define BOARD_H + +#include <qarray.h> +#include <qstring.h> +#include <qlist.h> +#include <qrect.h> + +#define OUT -1 + +enum Square {out = OUT, empty, brick, prison, gate, tunnel, prisonentry, prisonexit, + Point, energizer, fruit, pacman, monster, + fruithome, pacmanhome, monsterhome}; + +enum Image { None, Intro, Demo, Level, File }; + +#define X -1 +#define N 0 +#define S 1 +#define E 2 +#define W 3 +#define NE 4 +#define SE 5 +#define NW 6 +#define SW 7 + +#define BoardWidth 59 +#define BoardHeight 65 + +#define fixBits 0x0007 +#define varBits 0xFFF8 +#define monsterBits 0xFF00 + +#define pointBit 0x0008 +#define energizerBit 0x0010 +#define fruitBit 0x0020 +#define pacmanBit 0x0040 +#define monsterBit 0x0100 + +class Board : public QArray<int> +{ +public: + Board (int size); + ~Board() {}; + void init(Image image, QString levelName=0); + void setup(const uchar *buf); + + void set(int pos, Square sq, int m = 0); + void reset(int pos, Square sq, int m = 0); + int position(Square sq, int m = 0); + + bool isOut(int pos); + bool isEmpty(int pos); + bool isBrick(int pos); + bool isPrison(int pos); + bool isGate(int pos); + bool isTunnel(int pos); + bool isPoint(int pos); + bool isEnergizer(int pos); + bool isFruit(int pos); + bool isPacman(int pos); + bool isMonster(int pos); + bool isWay(int pos, int dir, Square sq); + bool isJump(int pos, int dir); + + int move(int pos, int dir, int steps = 1); + int closeup(int pos, int dir, int target); + int x(int pos); + int y(int pos); + int turn(int dir); + + int points(); + int energizers(); + int monsters(); + int tunnels(); + +private: + bool inBounds(int pos); + int sz; // size of board + + QString map; + QString mapName; // Filename of the latest loaded map + + int prisonEntry; // position of prisonentry + int prisonExit; // position of prisonexit + int pacmanHome; // startposition of pacman + int monsterHome[8]; // startposition of monsters + int fruitHome; // startposition of fruit + + int pacmanPosition; // actual position of pacman + int monsterPosition[8]; // actual position of monsters + int fruitPosition; // actual position of fruit + int energizerPosition[8]; // actual position of energizers + int tunnelPosition[8]; // position of tunnels + + int numMonsters; // number of monsters on the board + int numPoints; // number of points (left) on the board + int numEnergizers; // number of energizers (left) + int numTunnels; // number of tunnels on the board +}; + +#endif // BOARD_H diff --git a/noncore/games/kpacman/colors.h b/noncore/games/kpacman/colors.h new file mode 100644 index 0000000..6abf385 --- a/dev/null +++ b/noncore/games/kpacman/colors.h @@ -0,0 +1,21 @@ +#ifndef COLORS_H +#define COLORS_H + +#include <qcolor.h> + +#define BLACK QColor(Qt::black) +#define RED QColor(Qt::red) +#define BROWN QColor(0xde, 0x95, 0x41) +#define PINK QColor(0xff, 0xba, 0xde) +#define CYAN QColor(0x00, 0xff, 0xde) +#define LIGHTBLUE QColor(0x41, 0xba, 0xde) +#define ORANGE QColor(0xff, 0xba, 0x41) +#define YELLOW QColor(Qt::yellow) +#define BLUE QColor(0x20, 0x20, 0xde) +#define GREEN QColor(Qt::green) +#define LIGHTGREEN QColor(0x41, 0xba, 0x94) +#define FLESH QColor(0xff, 0xba, 0x94) +#define WHITE QColor(0xd8, 0xdc, 0xd8) + +#endif // COLORS_H + diff --git a/noncore/games/kpacman/config.cpp b/noncore/games/kpacman/config.cpp new file mode 100644 index 0000000..b9e3607 --- a/dev/null +++ b/noncore/games/kpacman/config.cpp @@ -0,0 +1,394 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qt Palmtop Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +** $Id$ +** +**********************************************************************/ + +#include "config.h" + +#include <qfile.h> +#include <qdir.h> +#include <qfileinfo.h> +#include <qtextstream.h> +#if QT_VERSION <= 230 && defined(QT_NO_CODECS) +#include <qtextcodec.h> +#endif +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> + +/*! + \internal +*/ +QString Config::configFilename(const QString& name, Domain d) +{ + switch (d) { + case File: + return name; + case User: { + QDir dir = (QString(getenv("HOME")) + "/Settings"); + if ( !dir.exists() ) + mkdir(dir.path().local8Bit(),0700); + return dir.path() + "/" + name + ".conf"; + } + } + return name; +} + +/*! + \class Config config.h + \brief The Config class provides for saving application cofniguration state. + + You should keep a Config in existence only while you do not want others + to be able to change the state. There is no locking currently, but there + may be in the future. +*/ + +/*! + \enum Config::ConfigGroup + \internal +*/ + +/*! + \enum Config::Domain + + \value File + \value User + + See Config for details. +*/ + +/*! + Constructs a config that will load or create a configuration with the + given \a name in the given \a domain. + + You must call setGroup() before doing much else with the Config. + + In the default Domain, \e User, + the configuration is user-specific. \a name should not contain "/" in + this case, and in general should be the name of the C++ class that is + primarily responsible for maintaining the configuration. + + In the File Domain, \a name is an absolute filename. +*/ +Config::Config( const QString &name, Domain domain ) + : filename( configFilename(name,domain) ) +{ + git = groups.end(); + read(); + + lang = getenv("LANG"); + int i = lang.find("."); + if ( i > 0 ) + lang = lang.left( i ); + i = lang.find( "_" ); + if ( i > 0 ) + glang = lang.left(i); +} + +/*! + Writes any changes to disk and destroys the in-memory object. +*/ +Config::~Config() +{ + if ( changed ) + write(); +} + +/*! + Returns whether the current group has an entry called \a key. +*/ +bool Config::hasKey( const QString &key ) const +{ + if ( groups.end() == git ) + return FALSE; + ConfigGroup::ConstIterator it = ( *git ).find( key ); + return it != ( *git ).end(); +} + +/*! + Sets the current group for subsequent reading and writing of + entries to \a gname. Grouping allows the application to partition the namespace. + + This function must be called prior to any reading or writing + of entries. + + The \a gname must not be empty. +*/ +void Config::setGroup( const QString &gname ) +{ + QMap< QString, ConfigGroup>::Iterator it = groups.find( gname ); + if ( it == groups.end() ) { + ConfigGroup *grp = new ConfigGroup; + git = groups.insert( gname, *grp ); + changed = TRUE; + return; + } + git = it; +} + +/*! + Writes a (\a key, \a value) entry to the current group. + + \sa readEntry() +*/ +void Config::writeEntry( const QString &key, const QString &value ) +{ + if ( git == groups.end() ) { + qWarning( "no group set" ); + return; + } + if ( (*git)[key] != value ) { + ( *git ).insert( key, value ); + changed = TRUE; + } +} + +/*! + Writes a (\a key, \a num) entry to the current group. + + \sa readNumEntry() +*/ +void Config::writeEntry( const QString &key, int num ) +{ + QString s; + s.setNum( num ); + writeEntry( key, s ); +} + +#ifdef Q_HAS_BOOL_TYPE +/*! + Writes a (\a key, \a b) entry to the current group. + + \sa readBoolEntry() +*/ +void Config::writeEntry( const QString &key, bool b ) +{ + QString s; + s.setNum( ( int )b ); + writeEntry( key, s ); +} +#endif + +/*! + Writes a (\a key, \a lst) entry to the current group. The list + is separated by \a sep, so the strings must not contain that character. + + \sa readListEntry() +*/ +void Config::writeEntry( const QString &key, const QStringList &lst, const QChar &sep ) +{ + QString s; + QStringList::ConstIterator it = lst.begin(); + for ( ; it != lst.end(); ++it ) + s += *it + sep; + writeEntry( key, s ); +} + + + +/*! + Reads a string entry stored with \a key, defaulting to \a deflt if there is no entry. +*/ +QString Config::readEntry( const QString &key, const QString &deflt ) +{ + QString res = readEntryDirect( key+"["+lang+"]" ); + if ( !res.isNull() ) + return res; + if ( !glang.isEmpty() ) { + res = readEntryDirect( key+"["+glang+"]" ); + if ( !res.isNull() ) + return res; + } + return readEntryDirect( key, deflt ); +} + +/*! + \internal +*/ +QString Config::readEntryDirect( const QString &key, const QString &deflt ) +{ + if ( git == groups.end() ) { + //qWarning( "no group set" ); + return deflt; + } + ConfigGroup::Iterator it = ( *git ).find( key ); + if ( it != ( *git ).end() ) + return *it; + else + return deflt; +} + +/*! + Reads a numeric entry stored with \a key, defaulting to \a deflt if there is no entry. +*/ +int Config::readNumEntry( const QString &key, int deflt ) +{ + QString s = readEntry( key ); + if ( s.isEmpty() ) + return deflt; + else + return s.toInt(); +} + +/*! + Reads a bool entry stored with \a key, defaulting to \a deflt if there is no entry. +*/ +bool Config::readBoolEntry( const QString &key, bool deflt ) +{ + QString s = readEntry( key ); + if ( s.isEmpty() ) + return deflt; + else + return (bool)s.toInt(); +} + +/*! + Reads a string list entry stored with \a key, and with \a sep as the separator. +*/ +QStringList Config::readListEntry( const QString &key, const QChar &sep ) +{ + QString s = readEntry( key ); + if ( s.isEmpty() ) + return QStringList(); + else + return QStringList::split( sep, s ); +} + +/*! + Removes all entries from the current group. +*/ +void Config::clearGroup() +{ + if ( git == groups.end() ) { + qWarning( "no group set" ); + return; + } + if ( !(*git).isEmpty() ) { + ( *git ).clear(); + changed = TRUE; + } +} + +/*! + \internal +*/ +void Config::write( const QString &fn ) +{ + if ( !fn.isEmpty() ) + filename = fn; + + QFile f( filename ); + if ( !f.open( IO_WriteOnly ) ) { + qWarning( "could not open for writing `%s'", filename.latin1() ); + git = groups.end(); + return; + } + + QTextStream s( &f ); +#if QT_VERSION <= 230 && defined(QT_NO_CODECS) + // The below should work, but doesn't in Qt 2.3.0 + s.setCodec( QTextCodec::codecForMib( 106 ) ); +#else + s.setEncoding( QTextStream::UnicodeUTF8 ); +#endif + QMap< QString, ConfigGroup >::Iterator g_it = groups.begin(); + for ( ; g_it != groups.end(); ++g_it ) { + s << "[" << g_it.key() << "]" << "\n"; + ConfigGroup::Iterator e_it = ( *g_it ).begin(); + for ( ; e_it != ( *g_it ).end(); ++e_it ) + s << e_it.key() << " = " << *e_it << "\n"; + } + + f.close(); +} + +/*! + Returns whether the Config is in a valid state. +*/ +bool Config::isValid() const +{ + return groups.end() != git; +} + +/*! + \internal +*/ +void Config::read() +{ + changed = FALSE; + + if ( !QFileInfo( filename ).exists() ) { + git = groups.end(); + return; + } + + QFile f( filename ); + if ( !f.open( IO_ReadOnly ) ) { + git = groups.end(); + return; + } + + QTextStream s( &f ); +#if QT_VERSION <= 230 && defined(QT_NO_CODECS) + // The below should work, but doesn't in Qt 2.3.0 + s.setCodec( QTextCodec::codecForMib( 106 ) ); +#else + s.setEncoding( QTextStream::UnicodeUTF8 ); +#endif + + QString line; + while ( !s.atEnd() ) { + line = s.readLine(); + if ( !parse( line ) ) { + git = groups.end(); + return; + } + } + + f.close(); +} + +/*! + \internal +*/ +bool Config::parse( const QString &l ) +{ + QString line = l.stripWhiteSpace(); + if ( line[ 0 ] == QChar( '[' ) ) { + QString gname = line; + gname = gname.remove( 0, 1 ); + if ( gname[ (int)gname.length() - 1 ] == QChar( ']' ) ) + gname = gname.remove( gname.length() - 1, 1 ); + ConfigGroup *grp = new ConfigGroup; + git = groups.insert( gname, *grp ); + } else if ( !line.isEmpty() ) { + if ( git == groups.end() ) + return FALSE; + int eq = line.find( '=' ); + if ( eq == -1 ) + return FALSE; + QString key = line.left(eq).stripWhiteSpace(); + QString value = line.mid(eq+1).stripWhiteSpace(); + ( *git ).insert( key, value ); + } + return TRUE; +} diff --git a/noncore/games/kpacman/config.h b/noncore/games/kpacman/config.h new file mode 100644 index 0000000..3c26b5d --- a/dev/null +++ b/noncore/games/kpacman/config.h @@ -0,0 +1,74 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qt Designer. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef CONFIG_H +#define CONFIG_H + +// ##### could use QSettings with Qt 3.0 + +#include <qmap.h> +#include <qstringlist.h> + +class ConfigPrivate; +class Config +{ +public: + typedef QMap< QString, QString > ConfigGroup; + + enum Domain { File, User }; + Config( const QString &name, Domain domain=User ); + ~Config(); + + bool isValid() const; + bool hasKey( const QString &key ) const; + + void setGroup( const QString &gname ); + void writeEntry( const QString &key, const QString &value ); + void writeEntry( const QString &key, int num ); +#ifdef Q_HAS_BOOL_TYPE + void writeEntry( const QString &key, bool b ); +#endif + void writeEntry( const QString &key, const QStringList &lst, const QChar &sep ); + + QString readEntry( const QString &key, const QString &deflt = QString::null ); + QString readEntryDirect( const QString &key, const QString &deflt = QString::null ); + int readNumEntry( const QString &key, int deflt = -1 ); + bool readBoolEntry( const QString &key, bool deflt = FALSE ); + QStringList readListEntry( const QString &key, const QChar &sep ); + + void clearGroup(); + + void write( const QString &fn = QString::null ); + +protected: + void read(); + bool parse( const QString &line ); + + QMap< QString, ConfigGroup > groups; + QMap< QString, ConfigGroup >::Iterator git; + QString filename; + QString lang; + QString glang; + bool changed; + ConfigPrivate *d; + static QString configFilename(const QString& name, Domain); +}; + +#endif diff --git a/noncore/games/kpacman/energizer.cpp b/noncore/games/kpacman/energizer.cpp new file mode 100644 index 0000000..ca08f3b --- a/dev/null +++ b/noncore/games/kpacman/energizer.cpp @@ -0,0 +1,61 @@ +#include "energizer.h" + +Energizer::Energizer(Board *b) +{ + board = b; + setOn(); + actualPosition = OUT; + maxPixmaps = 0; +} + +void Energizer::setMaxPixmaps(int max) +{ + maxPixmaps = max; +} + +void Energizer::setOff() +{ + actualState = off; +} + +void Energizer::setOn() +{ + actualState = on; + actualPix = 0; +} + +void Energizer::setPosition(int pos) +{ + board->reset(actualPosition, energizer); + actualPosition = pos; + board->set(actualPosition, energizer); +} + +energizerState Energizer::state() +{ + return actualState; +} + +int Energizer::position() +{ + return actualPosition; +} + +bool Energizer::move() +{ + if (actualPosition == OUT) + return FALSE; + + if (++actualPix >= maxPixmaps) + actualPix = 0; + + return TRUE; +} + +int Energizer::pix() +{ + if (actualPosition == OUT || actualState == off) + return -1; + + return actualPix; +} diff --git a/noncore/games/kpacman/energizer.h b/noncore/games/kpacman/energizer.h new file mode 100644 index 0000000..377cd02 --- a/dev/null +++ b/noncore/games/kpacman/energizer.h @@ -0,0 +1,30 @@ +#ifndef ENERGIZER_H +#define ENERGIZER_H + +#include "board.h" + +enum energizerState { on, off }; + +class Energizer { +public: + Energizer(Board *b); + void setMaxPixmaps(int max); + void setOff(); + void setOn(); + void setPosition(int pos); + energizerState state(); + int position(); + bool move(); + int pix(); + +private: + Board *board; + + energizerState actualState; // the state of energizer + + int actualPix; // last Pixmap-index + int maxPixmaps; // Number of Pixmaps (1..) + int actualPosition; // actual position on board +}; + +#endif // ENERGIZER_H diff --git a/noncore/games/kpacman/fruit.cpp b/noncore/games/kpacman/fruit.cpp new file mode 100644 index 0000000..e6ad2d5 --- a/dev/null +++ b/noncore/games/kpacman/fruit.cpp @@ -0,0 +1,176 @@ +#include <stdlib.h> + +#include "fruit.h" + +Fruit::Fruit(Board *b) +{ + board = b; + maxPixmaps = 0; + setLevel(0, 0, 0, 0); +} + +void Fruit::setEaten(int duration) +{ + actualState = eaten; + timeLeft = duration; + actualDirection = X; +} + +void Fruit::setLevel(int level, int wDuration, int fDuration, int ticks) +{ + actualLevel = level; + waitDuration = wDuration; + fruitDuration = fDuration; + pauseDuration = ticks; + pause = 0; + actualState = inactive; + timeLeft = waitDuration; + lastPosition = OUT; + setPosition(OUT); + setMovement(OUT, OUT, 0); + actualDirection = X; + setMaxPixmaps(maxPixmaps); +} + +void Fruit::setMaxPixmaps(int max) +{ + maxPixmaps = max; + if (actualLevel-1 < maxPixmaps) + actualPix = actualLevel == 0 ? 0 : actualLevel-1; + else if (maxPixmaps > 0) + actualPix = rand() % maxPixmaps; + else + actualPix = -1; +} + +void Fruit::setMovement(int entry, int tunnel, int iq) +{ + homePosition = board->position(fruithome); + entryPosition = entry; + tunnelPosition = tunnel; + IQ = iq; +} + +void Fruit::setPosition(int pos) +{ + board->reset(lastPosition, fruit); + actualPosition = lastPosition = pos; + board->set(actualPosition, fruit); +} + +void Fruit::setDirection(int dir) +{ + actualDirection = dir; +} + +fruitState Fruit::state() +{ + return actualState; +} + +int Fruit::position() +{ + return actualPosition; +} + +int Fruit::direction() +{ + return actualDirection; +} + +bool Fruit::move(bool activate) +{ + if (timeLeft > 0) { + timeLeft--; + } + + if (actualDirection == X || actualState == inactive) { + if (timeLeft == 0 || (activate && actualState == inactive)) { + if (actualState == inactive) { + if (entryPosition == OUT || tunnelPosition == OUT) { + setPosition(board->position(fruithome)); + } else { + setPosition(entryPosition); + actualDirection = 0; + while (!board->isWay(actualPosition, actualDirection, empty) || + board->isJump(actualPosition, actualDirection)) + actualDirection++; + } + timeLeft = fruitDuration; + setMaxPixmaps(maxPixmaps); + actualState = active; + } else { + actualState = inactive; + setPosition(OUT); + timeLeft = waitDuration; + actualDirection = X; + } + return TRUE; + } + return FALSE; + } + + if (pause-- > 0) + return FALSE; + else + pause = pauseDuration; + + if (actualPosition == OUT) + return FALSE; + + if (actualDirection == X) + return TRUE; + + int d = actualDirection; + + if (rand() % (int) ((190-IQ)/10) == 0) + if (timeLeft > 0) // coming home or leaving again + d = board->closeup(actualPosition, d, homePosition); + else + d = board->closeup(actualPosition, d, tunnelPosition); + else + do // try new direction, but not the opposite + d = rand() % 4; // direction, to prevent hectic movement. + while (d == board->turn(actualDirection)); + + while ((!board->isWay(actualPosition, d, empty) && + !board->isWay(actualPosition, d, tunnel)) || + d == board->turn(actualDirection)) { + if (d != actualDirection) // if new direction is not possible, + d = actualDirection; // try current direction first. + else + d = rand() % 4; + } + + actualDirection = d; + actualPosition = board->move(actualPosition, actualDirection); + + if (actualPosition == homePosition) { + timeLeft = 0; + } + + if (board->isTunnel(actualPosition)) { + setPosition(OUT); + timeLeft = waitDuration; + actualState = inactive; + actualDirection = X; + if (board->tunnels() > 0) { + entryPosition = board->position(tunnel, rand() % board->tunnels()); + tunnelPosition = board->position(tunnel, rand() % board->tunnels()); + } + } + + if (actualPosition != lastPosition) { + setPosition(actualPosition); + } + + return TRUE; +} + +int Fruit::pix() +{ + if (actualPosition == OUT || actualState == inactive) + return -1; + else + return actualPix; +} diff --git a/noncore/games/kpacman/fruit.h b/noncore/games/kpacman/fruit.h new file mode 100644 index 0000000..fbbd9c0 --- a/dev/null +++ b/noncore/games/kpacman/fruit.h @@ -0,0 +1,53 @@ +#ifndef FRUIT_H +#define FRUIT_H + +#include <stdlib.h> + +#include "board.h" + +enum fruitState { inactive, active, eaten }; + +class Fruit { +public: + Fruit(Board *b); + void setEaten(int duration); + void setLevel(int level, int wDuration, int fDuration, int ticks = -1); + void setMaxPixmaps(int max); + void setMovement(int entry, int tunnel, int iq); + void setPosition(int pos); + void setDirection(int dir); + fruitState state(); + int position(); + int direction(); + bool move(bool activate=FALSE); + int pix(); + +private: + Board *board; + + int IQ; // Intelligence of movement (0 = dumb..180=smart) + + fruitState actualState; // the state of fruit + + int pauseDuration; // number of ticks before next movement + int pause; // actual ticks before movement (0 = move) + + int timeLeft; // Ticks remaining of current state + + int waitDuration; // Time before fruit appears + int fruitDuration; // Length of active-time in ticks + + int actualDirection; // actual direction of the fruit + int actualPosition; // actual position on board + int lastPosition; // the last position of the fruit + int actualLevel; // level for kind of fruit and score + int actualPix; + int maxPixmaps; // Number of Pixmaps (1..) + + int entryPosition; // where to come in + int homePosition; // where to go, on the way in + int tunnelPosition; // where to exit +}; + +#endif // FRUIT_H + diff --git a/noncore/games/kpacman/keys.cpp b/noncore/games/kpacman/keys.cpp new file mode 100644 index 0000000..c609373 --- a/dev/null +++ b/noncore/games/kpacman/keys.cpp @@ -0,0 +1,203 @@ + +#include "portable.h" + +#if defined( KDE2_PORT ) +#include <kapp.h> +#include <kconfig.h> +#include <klocale.h> +#include <kstddirs.h> +#include <kaccel.h> + +#include <keys.h> +#include <keys.moc> +#elif defined( QPE_PORT ) +#include <qaccel.h> +#include <qpe/qpeapplication.h> +#include "config.h" +#include "keys.h" +#endif + +#include <qpushbt.h> +#include <qlabel.h> +#include <qframe.h> +#include <qkeycode.h> +#include <qpixmap.h> +#include <qstring.h> + +Keys::Keys( QWidget *parent, const char *name) + : QDialog( parent, name, TRUE ) +{ + //KStandardDirs *dirs = KGlobal::dirs(); + + QPushButton *okButton = new QPushButton(this); + okButton->setText(i18n("Ok")); + okButton->setFixedSize(okButton->size()); + connect( okButton, SIGNAL(clicked()),this, SLOT(ok()) ); + okButton->move(20,210); + + QPushButton *defaultButton = new QPushButton(this); + defaultButton->setText(i18n("Defaults")); + defaultButton->setFixedSize(defaultButton->size()); + connect( defaultButton, SIGNAL(clicked()),this, SLOT(defaults()) ); + defaultButton->move(140,210); + + QPushButton *cancelButton = new QPushButton(this); + cancelButton->setText(i18n("Cancel")); + cancelButton->setFixedSize(cancelButton->size()); + connect( cancelButton, SIGNAL(clicked()),this, SLOT(reject()) ); + cancelButton->move(260,210); + + QFrame *separator = new QFrame(this); + separator->setFrameStyle( QFrame::HLine | QFrame::Sunken ); + separator->setGeometry( 20, 190, 340, 4 ); + + for ( int x = 0; x < 4; x++) { + QLabel *l = new QLabel(this); + l->setAlignment(AlignCenter); + labels[x] = l; + } + + labels[0]->setGeometry(120, 20, 140, 20 ); + labels[1]->setGeometry(120,160, 140, 20 ); + labels[2]->setGeometry( 20, 92, 100, 20 ); + labels[3]->setGeometry(265, 92, 100, 20 ); + + QString pixPath; + + QPushButton *up = new QPushButton(this); + pixPath = FIND_APP_DATA( "pics/up.xpm" ); + up->setPixmap( QPixmap(pixPath)); + up->setFixedSize(up->pixmap()->size()); + connect( up, SIGNAL(clicked()),this, SLOT(butUp()) ); + up->move(180, 50); + + QPushButton *down = new QPushButton(this); + pixPath = FIND_APP_DATA( "pics/down.xpm"); + down->setPixmap( QPixmap(pixPath)); + down->setFixedSize(down->pixmap()->size()); + connect( down, SIGNAL(clicked()),this, SLOT(butDown()) ); + down->move(180, 130); + + QPushButton *left = new QPushButton(this); + pixPath = FIND_APP_DATA( "pics/left.xpm"); + left->setPixmap( QPixmap(pixPath)); + left->setFixedSize(left->pixmap()->size()); + connect( left, SIGNAL(clicked()),this, SLOT(butLeft()) ); + left->move(140, 90); + + QPushButton *right = new QPushButton(this); + pixPath = FIND_APP_DATA( "pics/right.xpm"); + right->setPixmap( QPixmap(pixPath)); + right->setFixedSize(right->pixmap()->size()); + connect( right, SIGNAL(clicked()),this, SLOT(butRight()) ); + right->move(220, 90); + + + setCaption(i18n("Change Direction Keys")); + setFixedSize(380, 260); + lab = 0; + init(); +} + +void Keys::keyPressEvent( QKeyEvent *e ) +{ + uint kCode = e->key() & ~(SHIFT | CTRL | ALT); + QString string = KAccel::keyToString(kCode); + + if (lab != 0) { + if ( string.isNull() ) + lab->setText(i18n("Undefined key")); + else + lab->setText(string); + } + else if ( lab == 0 && e->key() == Key_Escape) + reject(); +} + +void Keys::butUp() +{ + getKey(0); +} + +void Keys::butDown() +{ + getKey(1); +} + +void Keys::butLeft() +{ + getKey(2); +} + +void Keys::butRight() +{ + getKey(3); +} + +void Keys::getKey(int i) +{ + if ( lab != 0) + focusOut(lab); + + focusIn(labels[i]); +} + +void Keys::focusOut(QLabel *l) +{ + l->setFrameStyle( QFrame::NoFrame ); + l->setBackgroundColor(backgroundColor()); + l->repaint(); +} + +void Keys::focusIn(QLabel *l) +{ + lab = l; + lab->setFrameStyle( QFrame::Panel | QFrame::Sunken ); + lab->setBackgroundColor(white); + lab->repaint(); +} + +void Keys::defaults() +{ + if ( lab != 0) + focusOut(lab); + + lab = 0; + + labels[0]->setText("Up"); + labels[1]->setText("Down"); + labels[2]->setText("Left"); + labels[3]->setText("Right"); +} + +void Keys::init() +{ + APP_CONFIG_BEGIN( cfg ); + QString up("Up"); + up = cfg->readEntry("upKey", (const char*) up); + labels[0]->setText(up); + + QString down("Down"); + down = cfg->readEntry("downKey", (const char*) down); + labels[1]->setText(down); + + QString left("Left"); + left = cfg->readEntry("leftKey", (const char*) left); + labels[2]->setText(left); + + QString right("Right"); + right = cfg->readEntry("rightKey", (const char*) right); + labels[3]->setText(right); + APP_CONFIG_END( cfg ); +} + +void Keys::ok() +{ + APP_CONFIG_BEGIN( cfg ); + cfg->writeEntry("upKey", (const char*) labels[0]->text() ); + cfg->writeEntry("downKey", (const char*) labels[1]->text() ); + cfg->writeEntry("leftKey", (const char*) labels[2]->text() ); + cfg->writeEntry("rightKey",(const char*) labels[3]->text() ); + APP_CONFIG_END( cfg ); + accept(); +} diff --git a/noncore/games/kpacman/keys.h b/noncore/games/kpacman/keys.h new file mode 100644 index 0000000..c0c9d82 --- a/dev/null +++ b/noncore/games/kpacman/keys.h @@ -0,0 +1,48 @@ +#ifndef KEYS_H +#define KEYS_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "portable.h" + +#if defined( KDE2_PORT ) +#include <kapp.h> +#include <kaccel.h> +#endif + +#include <qdialog.h> +#include <qlabel.h> +#include <qstring.h> + +class Keys : public QDialog +{ + Q_OBJECT +public: + Keys( QWidget *parent=0, const char *name=0 ); + +private slots: + void butRight(); + void butLeft(); + void butUp(); + void butDown(); + + void getKey(int); + void defaults(); + void focusIn(QLabel *); + void focusOut(QLabel *); + + void ok(); + +protected: + void keyPressEvent( QKeyEvent * ); + +private: + void init(); + + QLabel *labels[4]; + QLabel *lab; +}; + +#endif // KEYS_H diff --git a/noncore/games/kpacman/kpacman.cpp b/noncore/games/kpacman/kpacman.cpp new file mode 100644 index 0000000..4077085 --- a/dev/null +++ b/noncore/games/kpacman/kpacman.cpp @@ -0,0 +1,369 @@ + +#include "portable.h" + +#if defined( KDE2_PORT ) +#include <kpacman.h> +#include <kpacman.moc> +#include <kcolordlg.h> +#elif defined( QPE_PORT ) +#include <qmenubar.h> +#include "config.h" +#include <qapplication.h> +#include "kpacman.h" +#endif + +#include <qkeycode.h> +#include <qcolor.h> +#include <qstring.h> +#include <qpopmenu.h> +#include <qmsgbox.h> + +Kpacman::Kpacman(QWidget *parent, const char *name) + : KTMainWindow(parent, name) +{ + schemesPopup = new QList<QPopupMenu>; + schemesPopup->setAutoDelete(TRUE); + + menu(); + + view = new KpacmanWidget( this, QString(name)+"widget"); + +#ifndef QWS + setFixedSize(view->width(), view->height()); +#else + setCaption( "Kpacman" ); +#endif + + view->referee->setFocus(); + + connect(view->referee, SIGNAL(setScore(int, int)), + view->score, SLOT(setScore(int, int))); + connect(view->referee, SIGNAL(setPoints(int)), + view->score, SLOT(set(int))); + connect(view->referee, SIGNAL(setLifes(int)), + view->status, SLOT(setLifes(int))); + connect(view->referee, SIGNAL(setLevel(int)), + view->status, SLOT(setLevel(int))); + connect(view->referee, SIGNAL(forcedHallOfFame(bool)), + this, SLOT(forcedHallOfFame(bool))); + connect(view->referee, SIGNAL(togglePaused()), this, SLOT(togglePaused())); + connect(view->referee, SIGNAL(toggleNew()), this, SLOT(toggleNew())); + + connect(view->score, SIGNAL(toggleNew()), this, SLOT(toggleNew())); + connect(view->score, SIGNAL(forcedHallOfFame(bool)), + this, SLOT(forcedHallOfFame(bool))); + + APP_CONFIG_BEGIN( cfg ); + focusOutPause = !cfg->readBoolEntry("FocusOutPause", TRUE); + focusInContinue = !cfg->readBoolEntry("FocusInContinue", TRUE); + hideMouseCursor = !cfg->readBoolEntry("HideMouseCursor", TRUE); + APP_CONFIG_END( cfg ); + + toggleFocusOutPause(); + toggleFocusInContinue(); + toggleHideMouseCursor(); + +#ifndef QWS + menuBar->show(); + view->show(); + setMenu(menuBar); + setView(view); +#else + setCentralWidget( view ); +#endif +} + +Kpacman::~Kpacman() +{ + APP_CONFIG_BEGIN( cfg ); + cfg->writeEntry("FocusOutPause", focusOutPause); + cfg->writeEntry("FocusInContinue", focusInContinue); + cfg->writeEntry("HideMouseCursor", hideMouseCursor); + APP_CONFIG_END( cfg ); + delete _menuBar; +} + +void Kpacman::menu() +{ + gamePopup = new QPopupMenu(); + CHECK_PTR( gamePopup ); + newID = gamePopup->insertItem(i18n("&New"), this, SLOT(newKpacman()),Key_F2); + pauseID = gamePopup->insertItem(i18n("&Pause"), + this, SLOT(pauseKpacman()), Key_F3); + hofID = gamePopup->insertItem(i18n("&Hall of fame"), + this, SLOT(toggleHallOfFame()), Key_F4); + gamePopup->insertSeparator(); + gamePopup->insertItem(i18n("&Quit"), this, SLOT(quitKpacman()), CTRL+Key_Q); + gamePopup->setCheckable(TRUE); + + optionsPopup = new QPopupMenu(); + CHECK_PTR(optionsPopup); + + modesPopup = new QPopupMenu(); + CHECK_PTR(modesPopup); + + hideMouseCursorID = optionsPopup->insertItem(i18n("&Hide Mousecursor"), + this, SLOT(toggleHideMouseCursor()), + CTRL+Key_H); + optionsPopup->insertSeparator(); + + if (lookupSchemes() > 0) { + optionsPopup->insertItem(i18n("&Select graphic scheme"), modesPopup); + optionsPopup->insertSeparator(); + } + + focusOutPauseID = optionsPopup->insertItem(i18n("&Pause in Background"), + this, SLOT(toggleFocusOutPause())); + focusInContinueID = optionsPopup->insertItem(i18n("&Continue in Foreground"), + this, SLOT(toggleFocusInContinue())); + optionsPopup->insertSeparator(); + + optionsPopup->insertItem(i18n("Change &keys..."), this, SLOT(confKeys())); + +#ifndef QWS + QString aboutText = i18n("@PACKAGE@ - @VERSION@\n\n" + "Joerg Thoennissen (joe@dsite.de)\n\n" + "A pacman game for the KDE Desktop\n\n" + "The program based on the source of ksnake\n" + "by Michel Filippi (mfilippi@sade.rhein-main.de).\n" + "The design was strongly influenced by the pacman\n" + "(c) 1980 MIDWAY MFG.CO.\n\n" + "I like to thank my girlfriend Elke Krueers for\n" + "the last 10 years of her friendship.\n"); + aboutText.replace(QRegExp("@PACKAGE@"), PACKAGE); + aboutText.replace(QRegExp("@VERSION@"), VERSION); + QPopupMenu *helpPopup = helpMenu(aboutText, FALSE); +#endif + + //_menuBar = new KMenuBar(this); + //CHECK_PTR( _menuBar ); + //_menuBar->insertItem(i18n("&Game"), gamePopup); + //_menuBar->insertItem(i18n("&Options"), optionsPopup); + //_menuBar->insertSeparator(); +#ifndef QWS + _menuBar->insertItem(i18n("&Help"), helpPopup); +#endif +} + +int Kpacman::lookupSchemes() +{ + APP_CONFIG_BEGIN( cfg ); + int ModeCount = cfg->readNumEntry("ModeCount", -1); + int Mode = cfg->readNumEntry("Mode", -1); + int SchemeCount = cfg->readNumEntry("SchemeCount"); + int Scheme = cfg->readNumEntry("Scheme", -1); + + if (SchemeCount == 0 || Scheme == -1) { + QMessageBox::warning(this, i18n("Configuration Error"), + i18n("There are no schemes defined,\n" + "or no scheme is selected.")); + APP_CONFIG_END( cfg ); + return 0; + } + + connect(modesPopup, SIGNAL(activated(int)), this, SLOT(schemeChecked(int))); + modeID.resize(ModeCount > 0 ? ModeCount : 0); + + if (!schemesPopup->isEmpty()) + schemesPopup->clear(); + + SAVE_CONFIG_GROUP( cfg, oldgroup ); + + QString ModeGroup; + QString ModeName; + + for (int m = 0; m < ModeCount; m++) { + ModeGroup.sprintf("Mode %d", m); + cfg->setGroup(ModeGroup); + + ModeName = cfg->readEntry("Description", ModeGroup); + + QPopupMenu *p = new QPopupMenu; + p->setCheckable(TRUE); + connect(p, SIGNAL(activated(int)), this, SLOT(schemeChecked(int))); + schemesPopup->append(p); + + modeID[m] = modesPopup->insertItem(ModeName, schemesPopup->at(m)); + modesPopup->setItemEnabled(modeID[m], FALSE); + modesPopup->setItemChecked(modeID[m], m == Mode); + } + + schemeID.resize(SchemeCount); + schemeMode.resize(SchemeCount); + + QString SchemeGroup; + QString SchemeName; + int SchemeMode; + + for (int i = 0; i < SchemeCount; i++) { + SchemeGroup.sprintf("Scheme %d", i); + cfg->setGroup(SchemeGroup); + + SchemeName = cfg->readEntry("Description", SchemeGroup); + SchemeMode = cfg->readNumEntry("Mode", -1); + + schemeMode[i] = SchemeMode; + if (SchemeMode == -1) { + schemeID[i] = modesPopup->insertItem(SchemeName); + modesPopup->setItemChecked(schemeID[i], i == Scheme); + } else { + schemeID[i] = schemesPopup->at(SchemeMode)->insertItem(SchemeName); + schemesPopup->at(SchemeMode)-> + setItemChecked(schemeID[i], i == Scheme); + modesPopup->setItemEnabled(modeID[SchemeMode], TRUE); + } + } + + RESTORE_CONFIG_GROUP( cfg, oldgroup ); + + APP_CONFIG_END( cfg ); + return SchemeCount; +} + +void Kpacman::quitKpacman() +{ + APP_QUIT(); +} + +void Kpacman::newKpacman() +{ + if (!gamePopup->isItemEnabled(hofID)) + gamePopup->setItemEnabled(hofID, TRUE); + + if (gamePopup->isItemChecked(hofID)) + toggleHallOfFame(); + + if (gamePopup->isItemChecked(pauseID)) + pauseKpacman(); + + view->referee->play(); +} + +void Kpacman::pauseKpacman() +{ + view->referee->pause(); + view->score->setPause(gamePopup->isItemChecked(pauseID)); +} + +void Kpacman::toggleHallOfFame() +{ + gamePopup->setItemChecked(hofID, !gamePopup->isItemChecked(hofID)); + view->referee->toggleHallOfFame(); + + if (gamePopup->isItemChecked(hofID)) { + view->referee->lower(); + view->status->lower(); + } else { + view->status->raise(); + view->referee->raise(); + view->referee->setFocus(); + } +} + +/* + * Disable or enable the "Hall of fame"-menuitem if the referee says so. + * This is done, to disable turning off the "hall of fame"-display, in the automated + * sequence of displaying the introduction, the demonstration (or playing) and the + * hall of fame. + * If on == TRUE then also lower the referee and the status widgets. + */ +void Kpacman::forcedHallOfFame(bool on) +{ + if (!on && !gamePopup->isItemChecked(hofID)) + return; + + gamePopup->setItemEnabled(hofID, !on); + gamePopup->setItemChecked(hofID, on); + + view->referee->toggleHallOfFame(); + if (on) { + view->referee->lower(); + view->status->lower(); + } else { + view->status->raise(); + view->referee->raise(); + view->referee->setFocus(); + view->referee->intro(); + } +} + +void Kpacman::togglePaused() +{ + static bool checked = FALSE; + checked = !checked; + gamePopup->setItemChecked( pauseID, checked ); + view->score->setPause(gamePopup->isItemChecked(pauseID)); +} + +/* + * This disables the "New Game" menuitem to prevent interruptions of the current + * play. + */ +void Kpacman::toggleNew() +{ + gamePopup->setItemEnabled(newID, !gamePopup->isItemEnabled(newID)); +} + +void Kpacman::toggleHideMouseCursor() +{ + hideMouseCursor = !hideMouseCursor; + optionsPopup->setItemChecked(hideMouseCursorID, hideMouseCursor); + if (hideMouseCursor) + view->setCursor(blankCursor); + else + view->setCursor(arrowCursor); +} + +void Kpacman::toggleFocusOutPause() +{ + focusOutPause = !focusOutPause; + optionsPopup->setItemChecked(focusOutPauseID, focusOutPause); + view->referee->setFocusOutPause(focusOutPause); +} + +void Kpacman::toggleFocusInContinue() +{ + focusInContinue = !focusInContinue; + optionsPopup->setItemChecked(focusInContinueID, focusInContinue); + view->referee->setFocusInContinue(focusInContinue); +} + +void Kpacman::confKeys() +{ + Keys *keys = new Keys(); + if (keys->exec() == QDialog::Accepted) { + view->referee->initKeys(); + view->score->initKeys(); + } + delete keys; +} + +void Kpacman::schemeChecked(int id) +{ + int mode = 0, scheme = -1; + + for (uint s = 0; s < schemeID.size(); s++) { + if (schemeID[s] == id) { + scheme = s; + mode = schemeMode[s]; + } + if (schemeMode[s] == -1) { + modesPopup->setItemChecked(schemeID[s], schemeID[s] == id); + } else { + modesPopup->setItemChecked(modeID[schemeMode[s]], schemeMode[s] == mode); + schemesPopup->at(schemeMode[s])->setItemChecked(schemeID[s], schemeID[s] == id); + } + } + + APP_CONFIG_BEGIN( cfg ); + cfg->writeEntry("Scheme", scheme); + cfg->writeEntry("Mode", mode); + APP_CONFIG_END( cfg ); + + view->setScheme(scheme, mode); + view->updateGeometry(); + updateGeometry(); + update(); + repaint(TRUE); + show(); +} diff --git a/noncore/games/kpacman/kpacman.h b/noncore/games/kpacman/kpacman.h new file mode 100644 index 0000000..d7de9de --- a/dev/null +++ b/noncore/games/kpacman/kpacman.h @@ -0,0 +1,95 @@ +#ifndef KPACMAN_H +#define KPACMAN_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "portable.h" + +#if defined( KDE2_PORT ) +#include <kapp.h> +#include <klocale.h> +#include <ktmainwindow.h> +#include <kmenubar.h> +#elif defined( QPE_PORT ) +#include <qmainwindow.h> +class QMenuBar; +#endif + +#include <qregexp.h> + +#include "kpacmanwidget.h" + +#include <qpopmenu.h> + +#include <qlist.h> +#include <qfileinf.h> + +#if defined( KDE2_PORT ) +#include <referee.h> +#include <status.h> +#include <score.h> +#include <keys.h> +#elif defined( QPE_PORT ) +#include "referee.h" +#include "status.h" +#include "score.h" +#include "keys.h" +#endif + +class Kpacman : public KTMainWindow +{ + Q_OBJECT +public: + Kpacman(QWidget *parent = 0, const char *name = 0); + virtual ~Kpacman(); + +public slots: + void forcedHallOfFame(bool); + +private slots: + void newKpacman(); + void pauseKpacman(); + void toggleHallOfFame(); + void toggleNew(); + void togglePaused(); + void quitKpacman(); + + void schemeChecked(int); + void toggleFocusOutPause(); + void toggleFocusInContinue(); + void toggleHideMouseCursor(); + void confKeys(); + +protected: + +private: + KpacmanWidget *view; + + void menu(); + + int lookupSchemes(); + + KMenuBar *_menuBar; + QPopupMenu *gamePopup; + QPopupMenu *optionsPopup; + QPopupMenu *modesPopup; + QList<QPopupMenu> *schemesPopup; + + int newID; + int pauseID; + int hofID; + QArray<int> modeID; + QArray<int> schemeID; + QArray<int> schemeMode; + int focusOutPauseID; + int focusInContinueID; + int hideMouseCursorID; + + bool focusOutPause; + bool focusInContinue; + bool hideMouseCursor; +}; + +#endif // KPACMAN_H diff --git a/noncore/games/kpacman/kpacman.moc.cpp b/noncore/games/kpacman/kpacman.moc.cpp new file mode 100644 index 0000000..804e8c8 --- a/dev/null +++ b/noncore/games/kpacman/kpacman.moc.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** Kpacman meta object code from reading C++ file 'kpacman.h' +** +** Created: Sat Jan 19 13:52:36 2002 +** by: The Qt MOC ($Id$) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#if !defined(Q_MOC_OUTPUT_REVISION) +#define Q_MOC_OUTPUT_REVISION 9 +#elif Q_MOC_OUTPUT_REVISION != 9 +#error "Moc format conflict - please regenerate all moc files" +#endif + +#include "kpacman.h" +#include <qmetaobject.h> +#include <qapplication.h> + + + +const char *Kpacman::className() const +{ + return "Kpacman"; +} + +QMetaObject *Kpacman::metaObj = 0; + +void Kpacman::initMetaObject() +{ + if ( metaObj ) + return; + if ( qstrcmp(QWidget::className(), "QWidget") != 0 ) + badSuperclassWarning("Kpacman","QWidget"); + (void) staticMetaObject(); +} + +#ifndef QT_NO_TRANSLATION + +QString Kpacman::tr(const char* s) +{ + return qApp->translate( "Kpacman", s, 0 ); +} + +QString Kpacman::tr(const char* s, const char * c) +{ + return qApp->translate( "Kpacman", s, c ); +} + +#endif // QT_NO_TRANSLATION + +QMetaObject* Kpacman::staticMetaObject() +{ + if ( metaObj ) + return metaObj; + (void) QWidget::staticMetaObject(); +#ifndef QT_NO_PROPERTIES +#endif // QT_NO_PROPERTIES + QMetaData::Access *slot_tbl_access = 0; + metaObj = QMetaObject::new_metaobject( + "Kpacman", "QWidget", + 0, 0, + 0, 0, +#ifndef QT_NO_PROPERTIES + 0, 0, + 0, 0, +#endif // QT_NO_PROPERTIES + 0, 0 ); + metaObj->set_slot_access( slot_tbl_access ); +#ifndef QT_NO_PROPERTIES +#endif // QT_NO_PROPERTIES + return metaObj; +} diff --git a/noncore/games/kpacman/kpacman.pro b/noncore/games/kpacman/kpacman.pro new file mode 100644 index 0000000..6577e5b --- a/dev/null +++ b/noncore/games/kpacman/kpacman.pro @@ -0,0 +1,42 @@ +TEMPLATE = app +#CONFIG = qt warn_on debug +CONFIG = qt warn_on release +#TMAKE_CXXFLAGS += +HEADERS = kpacmanwidget.h \ + referee.h \ + status.h \ + painter.h \ + score.h \ + pacman.h \ + monster.h \ + keys.h \ + fruit.h \ + energizer.h \ + board.h \ + bitfont.h \ + kpacman.h \ + bitmaps.h \ + colors.h \ + config.h \ + portable.h +SOURCES = kpacmanwidget.cpp \ + referee.cpp \ + status.cpp \ + painter.cpp \ + score.cpp \ + pacman.cpp \ + monster.cpp \ + keys.cpp \ + fruit.cpp \ + energizer.cpp \ + board.cpp \ + bitfont.cpp \ + kpacman.cpp \ + config.cpp \ + main.cpp + +#INCLUDEPATH += +#DEPENDPATH += +LIBS += -lqpe -ljpeg +DESTDIR = $(OPIEDIR)/bin +TARGET = kpacman diff --git a/noncore/games/kpacman/kpacmanwidget.cpp b/noncore/games/kpacman/kpacmanwidget.cpp new file mode 100644 index 0000000..330c88e --- a/dev/null +++ b/noncore/games/kpacman/kpacmanwidget.cpp @@ -0,0 +1,162 @@ + +#include "portable.h" + +#if defined( KDE2_PORT ) +#include <kapp.h> +#include <kconfig.h> +#include <kstddirs.h> +#include <kpacmanwidget.h> +#include <kpacmanwidget.moc> +#elif defined( QPE_PORT ) +#include <qpe/qpeapplication.h> +#include "config.h" +#include "kpacmanwidget.h" +#endif + +#include <qmessagebox.h> + +#include "bitfont.h" +#include "score.h" +#include "referee.h" +#include "status.h" + +KpacmanWidget::KpacmanWidget( QWidget *parent, const char *name) + : QWidget( parent, name ) +{ + bitfont = NULL; + fontName = ""; + + scheme = mode = -1; + confScheme(); + + score = new Score(this, name, scheme, mode, bitfont); + referee = new Referee( this, name, scheme, mode, bitfont); + status = new Status(this, name, scheme, mode); + +#ifndef QWS + setFixedSize(referee->width(), bitfont->height()*3 + referee->height() + status->height()); +#else + setBackgroundColor( black ); +#endif +} + +KpacmanWidget::~KpacmanWidget() +{ +} + +void KpacmanWidget::confMisc(bool defGroup) +{ + APP_CONFIG_BEGIN( cfg ); + //KStandardDirs *dirs = KGlobal::dirs(); + QString findPath; + + if (defGroup || cfg->hasKey("Font")) { + fontName = cfg->readEntry("Font"); + + if (fontName.left(1) != "/" && fontName.left(1) != "~") + fontName.insert(0, "fonts/"); + if (fontName.right(1) == "/") + fontName.append("font.xbm"); + + //findPath = dirs->findResource("appdata", fontName); + findPath = FIND_APP_DATA( fontName ); + if (!findPath.isEmpty()) + fontName = findPath; + + bitfontFirstChar = cfg->readNumEntry("FontFirstChar", 0x0e); + bitfontLastChar = cfg->readNumEntry("FontLastChar", 0x5f); + } + APP_CONFIG_END( cfg ); +} + +void KpacmanWidget::confScheme() +{ + APP_CONFIG_BEGIN( cfg ); + QString lastFontName = fontName; + SAVE_CONFIG_GROUP( cfg, oldgroup ); + QString newgroup; + + // if not set, read mode and scheme from the configfile + if (mode == -1 && scheme == -1) { + scheme = cfg->readNumEntry("Scheme", -1); + mode = cfg->readNumEntry("Mode", -1); + + // if mode is not set in the defGroup-group, lookup the scheme group + if (scheme != -1 || mode == -1) { + newgroup.sprintf("Scheme %d", scheme); + cfg->setGroup(newgroup); + + mode = cfg->readNumEntry("Mode", -1); + RESTORE_CONFIG_GROUP( cfg, oldgroup ); + } + } + + confMisc(); + + if (mode != -1) { + newgroup.sprintf("Mode %d", mode); + cfg->setGroup(newgroup); + + confMisc(FALSE); + } + + if (scheme != -1) { + newgroup.sprintf("Scheme %d", scheme); + cfg->setGroup(newgroup); + + confMisc(FALSE); + } + + if (lastFontName != fontName) { + + if (bitfont != 0) + delete bitfont; + + bitfont = new Bitfont(fontName, bitfontFirstChar, bitfontLastChar); + if (bitfont->width() == 0 || bitfont->height() == 0) { + QString msg = i18n("The bitfont could not be contructed.\n\n" + "The file '@FONTNAME@' does not exist,\n" + "or is of an unknown format."); + msg.replace(QRegExp("@FONTNAME@"), fontName); + // QMessageBox::critical(this, i18n("Initialization Error"), msg); + printf("%s\n", msg.data()); + } + } + + RESTORE_CONFIG_GROUP( cfg, oldgroup ); + APP_CONFIG_END( cfg ); +} + +void KpacmanWidget::setScheme(int Scheme, int Mode) +{ + mode = Mode; + scheme = Scheme; + + confScheme(); + + score->setScheme(Scheme, Mode, bitfont); + referee->setScheme(Scheme, Mode, bitfont); + status->setScheme(Scheme, Mode); + +#ifndef QWS + setFixedSize(referee->width(), + bitfont->height()*3 + referee->height() + status->height()); +#endif + + score->repaint(FALSE); + referee->repaint(FALSE); + status->repaint(FALSE); +} + +void KpacmanWidget::resizeEvent( QResizeEvent * ) +{ + referee->setGeometry(0, bitfont->height()*3, referee->width(), referee->height()); + referee->setBackgroundColor(BLACK); + + status->setGeometry(0, bitfont->height()*3+referee->height(), referee->width(), + status->height()); + status->setBackgroundColor(BLACK); + + score->setGeometry(0, 0, referee->width(), bitfont->height()*3+referee->height()+status->height()); + score->setBackgroundColor(BLACK); +} diff --git a/noncore/games/kpacman/kpacmanwidget.h b/noncore/games/kpacman/kpacmanwidget.h new file mode 100644 index 0000000..13b4a15 --- a/dev/null +++ b/noncore/games/kpacman/kpacmanwidget.h @@ -0,0 +1,50 @@ +#ifndef KPACMANWIDGET_H +#define KPACMANWIDGET_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "portable.h" + +#if defined( KDE2_PORT ) +#include <kapp.h> +#endif + +#include <qwidget.h> +#include <qregexp.h> + +#include "score.h" +#include "referee.h" +#include "status.h" +#include "painter.h" + +class KpacmanWidget : public QWidget +{ + Q_OBJECT +public: + KpacmanWidget ( QWidget *parent = 0, const char *name = 0); + virtual ~KpacmanWidget(); + + void setScheme(int scheme=-1, int mode=-1); + Score *score; + Referee *referee; + Status *status; + +protected: + void confScheme(); + void confMisc(bool defGroup=TRUE); + void resizeEvent( QResizeEvent * ); + +private: + Bitfont *bitfont; + uchar bitfontFirstChar; + uchar bitfontLastChar; + + QString fontName; + + int scheme; + int mode; +}; + +#endif // KPACMANWIDGET_H diff --git a/noncore/games/kpacman/main.cpp b/noncore/games/kpacman/main.cpp new file mode 100644 index 0000000..76afb57 --- a/dev/null +++ b/noncore/games/kpacman/main.cpp @@ -0,0 +1,66 @@ +/*************************************************************************** + main.cpp - description + ------------------- + begin : Sam Jan 19 13:37:57 CET 2002 + copyright : (C) 2002 by Jörg Thönnissen + email : joe@dsite.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "portable.h" + +#if defined( KDE2_PORT ) +#include <kcmdlineargs.h> +#include <kaboutdata.h> +#include <klocale.h> +#elif defined( QPE_PORT ) +#include <qpe/qpeapplication.h> +#endif + +#include "kpacman.h" + +#ifdef KDE2_PORT +static const char *description = + I18N_NOOP("Kpacman"); +// INSERT A DESCRIPTION FOR YOUR APPLICATION HERE + + +static KCmdLineOptions options[] = +{ + { 0, 0, 0 } + // INSERT YOUR COMMANDLINE OPTIONS HERE +}; +#endif + +int main(int argc, char *argv[]) +{ +#if defined( KDE2_PORT ) + KAboutData aboutData( "kpacman", I18N_NOOP("Kpacman"), + VERSION, description, KAboutData::License_GPL, + "(c) 2002, Jörg Thönnissen", 0, 0, "joe@dsite.de"); + aboutData.addAuthor("Jörg Thönnissen",0, "joe@dsite.de"); + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); // Add our own options. + KApplication a; +#elif defined( QPE_PORT ) + QPEApplication a( argc, argv ); +#endif + Kpacman *kpacman = new Kpacman( NULL, "Kpacman" ); + a.setMainWidget(kpacman); +#if defined( KDE2_PORT ) + a.setTopWidget(kpacman); + kpacman->show(); +#elif defined( QPE_PORT ) + kpacman->showMaximized(); +#endif + + return a.exec(); +} diff --git a/noncore/games/kpacman/monster.cpp b/noncore/games/kpacman/monster.cpp new file mode 100644 index 0000000..2f402b4 --- a/dev/null +++ b/noncore/games/kpacman/monster.cpp @@ -0,0 +1,262 @@ +#include "monster.h" +#include "board.h" + +Monster::Monster(Board *b, int mid) +{ + board = b; + ID = mid; + + setREM(0); + setHarmless(0, 0, 0); + setArrested(0, 0); + setFreedom(board->position(prisonexit)); + if (mid == 0) + setPrison(board->position(prisonentry)); + else + setPrison(board->position(monsterhome, mid)); + + actualPosition = lastPosition = OUT; + feetPosition = 0; + IQ = 0; + maxBodyPixmaps = 0; + maxEyesPixmaps = 0; +} + +void Monster::setMaxPixmaps(int maxBody, int maxEyes) +{ + if (feetPosition >= (maxBody/10)) + feetPosition = 0; + maxBodyPixmaps = maxBody; + maxEyesPixmaps = maxEyes; +} + +void Monster::setArrested(int ticks, int duration) +{ + actualState = dangerous; + pauseDuration = ticks; + pause = 0; + arrestDuration = arrestLeft = duration; + arrestPause = ticks; + harmlessLeft = 0; +} + +void Monster::setDangerous(int ticks, int iq) +{ + actualState = dangerous; + pauseDuration = ticks; + pause = 0; + dangerousPause = ticks; + harmlessLeft = 0; + IQ = iq; +} + +void Monster::setHarmless(int ticks, int hDuration, int wDuration) +{ + actualState = harmless; + pauseDuration = ticks; + pause = 0; + harmlessDuration = harmlessLeft = hDuration; + warningDuration = wDuration; +} + +void Monster::setREM(int ticks) +{ + actualState = rem; + pauseDuration = ticks; + pause = 0; +} + +void Monster::setPosition(int pos) +{ + board->reset(lastPosition, monster, ID); // reset old position on the board + actualPosition = lastPosition = pos; // set position of monster + board->set(actualPosition, monster, ID); + feetPosition = 0; +} + +void Monster::setPrison(int pos) +{ + prisonPosition = pos; +} + +void Monster::setFreedom(int pos) +{ + freedomPosition = pos; +} + +void Monster::setDirection(int dir) +{ + if (dir == X) + lastDirection = actualDirection; + actualDirection = dir; +} + +monsterState Monster::state() +{ + return actualState; +} + +int Monster::position() +{ + return actualPosition; +} + +int Monster::direction() +{ + return actualDirection; +} + +int Monster::id() +{ + return ID; +} + +bool Monster::move() +{ + if (arrestLeft > 1) + arrestLeft--; + + if (harmlessLeft > 0) { + harmlessLeft--; + if (harmlessLeft == 0 && actualState == harmless) { + actualState = dangerous; + pauseDuration = dangerousPause; + } + } + + if (pause-- > 0) + return FALSE; + else + pause = pauseDuration; + + if (actualPosition == OUT) + return FALSE; + + if (actualDirection == X) { + if (++feetPosition >= (maxBodyPixmaps/10)) + feetPosition = 0; + return TRUE; + } + + lastPosition = actualPosition; + int d = actualDirection; + + if (arrestLeft > 1) { // during the arrest, only up and down + if (!board->isWay(actualPosition, d, empty) && + !board->isWay(actualPosition, d, tunnel)) + d = board->turn(actualDirection); + } + + if (arrestLeft == 1) { // going out of the prison + if (((d == W || d == E) && + board->x(actualPosition) == board->x(freedomPosition)) || + ((d == S || d == N) && + board->y(actualPosition) == board->y(freedomPosition)) || + board->isWay(actualPosition, d, brick) || + board->isWay(actualPosition, d, prison)) { + d = board->closeup(actualPosition, d, freedomPosition); + } + while (board->isWay(actualPosition, d, brick) || + board->isWay(actualPosition, d, prison)) { + if (d == actualDirection) + d = rand() % 4; + else + d = actualDirection; + } + if (actualState == dangerous) + pauseDuration = dangerousPause; + + } + + if (arrestLeft == 0) + if (actualState == rem) { // on the way to prison + + d = board->closeup(actualPosition, d, prisonPosition); + + while (board->isWay(actualPosition, d, brick) || + board->isWay(actualPosition, d, prison)) { + if (d != actualDirection) // if new direction is not possible, + d = actualDirection; // try current direction first. + else + d = rand() % 4; + } + + } else { // dangerous or harmless movement + if (rand() % (int) ((190-IQ)/10) == 0) { + d = board->closeup(actualPosition, d, board->position(pacman)); + if (actualState == harmless) + d = board->turn(d); + } else + do // try new direction, but not the opposite + d = rand() % 4; // direction, to prevent hectic movement. + while (d == board->turn(actualDirection)); + + while ((!board->isWay(actualPosition, d, empty) && + !board->isWay(actualPosition, d, tunnel)) || + d == board->turn(actualDirection)) { + if (d != actualDirection) // if new direction is not possible, + d = actualDirection; // try current direction first. + else + d = rand() % 4; + } + } + + actualDirection = d; + actualPosition = board->move(actualPosition, actualDirection); + + if (arrestLeft == 1 && actualPosition == freedomPosition) + arrestLeft = 0; + + if (actualState == rem && actualPosition == prisonPosition) { + actualState = dangerous; + pauseDuration = arrestPause; + arrestLeft = arrestDuration+1; + actualDirection = S; + } + + if (actualPosition != lastPosition) { + board->reset(lastPosition, monster, ID); + board->set(actualPosition, monster, ID); + } + + if (++feetPosition >= (maxBodyPixmaps/10)) + feetPosition = 0; + + return TRUE; +} + +int Monster::body() +{ + if (actualState == rem || actualPosition == OUT) + return -1; + else + if (actualState == harmless) + if (harmlessLeft > warningDuration || + harmlessLeft % (int) (warningDuration/4.5) > (int) (warningDuration/9)) + return ((maxBodyPixmaps/10)*8)+feetPosition; + else + return ((maxBodyPixmaps/10)*9)+feetPosition; + else + return ((maxBodyPixmaps/10)*ID)+feetPosition; +} + +int Monster::eyes() +{ + if (actualState == harmless || actualPosition == OUT) + return -1; + else + switch (actualDirection) { + case N : return 0; + case E : return 1; + case S : return 2; + case W : return 3; + case X : switch (lastDirection) { + case N : return 0; + case E : return 1; + case S : return 2; + default : return 3; + } + default : return -1; + } +} + diff --git a/noncore/games/kpacman/monster.h b/noncore/games/kpacman/monster.h new file mode 100644 index 0000000..b5d7f36 --- a/dev/null +++ b/noncore/games/kpacman/monster.h @@ -0,0 +1,62 @@ +#ifndef MONSTER_H +#define MONSTER_H + +#include <stdlib.h> +#include <qpixmap.h> +#include <qwidget.h> + +#include "board.h" + +enum monsterState { dangerous, harmless, rem, arrested }; + +class Monster { +public: + Monster(Board *b, int mid = 0); + void setMaxPixmaps(int maxBody, int maxEyes); + void setArrested(int ticks, int duration); + void setDangerous(int ticks, int IQ); + void setHarmless(int ticks, int hDuration, int wDuration); + void setREM(int ticks); + void setPosition(int pos); + void setPrison(int pos); + void setFreedom(int pos); + void setDirection(int dir); + monsterState state(); + int position(); + int direction(); + int id(); + bool move(); + int body(); + int eyes(); +private: + Board *board; + int ID; // ID of monster (0 = 1st, 1 = 2nd ... 7 = last) + int IQ; // Intelligence of movement (0 = dumb..180 = smart) + + monsterState actualState; // The state of the monster + + int pauseDuration; // Number of ticks before movement + int pause; // actual ticks before moevment (0 = move) + int dangerousPause; // pause in dangerous-state + + int harmlessDuration; // Length of harmless-time in ticks + int harmlessLeft; // rest of the time in harmless-state + int warningDuration; // warningtime before monster get dangerous again + + int arrestDuration; // Length of arrest in ticks + int arrestLeft; // time left of arrest + int arrestPause; // pause in arrest-state + + int actualDirection; // actual direction of monster + int lastDirection; // last direction, before no movement (X) + int actualPosition; // actual position on board + int lastPosition; // the last position of the monster + int feetPosition; // left, right, left, right, ... + int maxBodyPixmaps; + int maxEyesPixmaps; + int prisonPosition; // where to go, if arrested + int freedomPosition; // where to go, if released from prison +}; + +#endif // MONSTER_H + diff --git a/noncore/games/kpacman/opie-kpacman.control b/noncore/games/kpacman/opie-kpacman.control new file mode 100644 index 0000000..814604e --- a/dev/null +++ b/noncore/games/kpacman/opie-kpacman.control @@ -0,0 +1,11 @@ +Files: bin/kpacman apps/Games/kpacman.desktop pics/kpacman.png share/kpacman +Package: opie-kpacman +Version: 0.3.1 +Depends: opie-base ($QPE_VERSION) +Priority: optional +Section: opie/games +Maintainer: Catalin Climov <catalin@climov.com> +Architecture: arm +License: GPL +Description: Kpacman + A Pacman clone for Qtopia. diff --git a/noncore/games/kpacman/opie-kpacman.postinst b/noncore/games/kpacman/opie-kpacman.postinst new file mode 100755 index 0000000..ead1ef8 --- a/dev/null +++ b/noncore/games/kpacman/opie-kpacman.postinst @@ -0,0 +1,6 @@ +#!/bin/sh + +if [ ! -f $HOME/Settings/kpacman.conf ] +then + cp $QPEDIR/share/kpacman/kpacman.conf $HOME/Settings/ +fi diff --git a/noncore/games/kpacman/pacman.cpp b/noncore/games/kpacman/pacman.cpp new file mode 100644 index 0000000..40f60a8 --- a/dev/null +++ b/noncore/games/kpacman/pacman.cpp @@ -0,0 +1,147 @@ +#include "pacman.h" +#include "board.h" + +Pacman::Pacman(Board *b) +{ + board = b; + setDemo(FALSE); + setAlive(0); + actualPosition = lastPosition = OUT; + mouthPosition = 0; + lastPix = 0; + maxPixmaps = 0; +} + +void Pacman::setMaxPixmaps(int max) +{ + if (actualDirection == X && lastPix >= 0) { + actualDirection = lastPix / (maxPixmaps/4); + if (max < maxPixmaps) + mouthPosition = 0; + else + mouthPosition = lastPix % (maxPixmaps/4); + maxPixmaps = max; + + lastPix = pix(); + + actualDirection = X; + } else + maxPixmaps = max; +} + +void Pacman::setAlive(int ticks) +{ + actualState = alive; + pauseDuration = ticks; + pause = 0; +} + +void Pacman::setPosition(int pos) +{ + board->reset(lastPosition, pacman); + actualPosition = lastPosition = pos; + board->set(actualPosition, pacman); + mouthPosition = 0; +} + +void Pacman::setDirection(int dir, bool forced) +{ + if (forced || + board->isWay(actualPosition, dir, empty) || + board->isWay(actualPosition, dir, tunnel)) { + if (dir == X) + lastPix = pix(); + actualDirection = dir; + nextDirection = X; + } else + nextDirection = dir; +} + +void Pacman::setDemo(bool yes) +{ + demo = yes; +} + +pacmanState Pacman::state() +{ + return actualState; +} + +int Pacman::position() +{ + return actualPosition; +} + +int Pacman::direction() +{ + return actualDirection; +} + +bool Pacman::move() +{ + if (pause-- > 0) + return FALSE; + else + pause = pauseDuration; + + if (actualDirection == X || actualPosition == OUT) + return FALSE; + + lastPosition = actualPosition; + + if (demo) { + int d = actualDirection; + + do // try new direction, but not the opposite + d = rand() % 4; // direction, to prevent hectic movement. + while (d == board->turn(actualDirection)); + + while (!board->isWay(actualPosition, d, empty) && + !board->isWay(actualPosition, d, tunnel)) { + if (d != actualDirection) // if new actualDirection is not possible, + d = actualDirection; // try current actualDirection first. + else + d = rand() % 4; + } + + actualDirection = d; + actualPosition = board->move(actualPosition, actualDirection); + + } else { + + if (nextDirection != X) + if (board->isWay(actualPosition, nextDirection, empty) || + board->isWay(actualPosition, nextDirection, tunnel)) { + actualDirection = nextDirection; + nextDirection = X; + } + + if (board->isWay(actualPosition, actualDirection, empty) || + board->isWay(actualPosition, actualDirection, tunnel)) + actualPosition = board->move(actualPosition, actualDirection); + } + + if (actualPosition != lastPosition) { + board->reset(lastPosition, pacman); + board->set(actualPosition, pacman); + + if (++mouthPosition >= (maxPixmaps/4)) + mouthPosition = 0; + } + return TRUE; +} + +int Pacman::pix() +{ + if (actualPosition != OUT && maxPixmaps > 0) + switch (actualDirection) { + case N : return ((maxPixmaps/4)*0)+mouthPosition; + case E : return ((maxPixmaps/4)*1)+mouthPosition; + case S : return ((maxPixmaps/4)*2)+mouthPosition; + case W : return ((maxPixmaps/4)*3)+mouthPosition; + case X : return lastPix; + } + + return -1; +} + diff --git a/noncore/games/kpacman/pacman.h b/noncore/games/kpacman/pacman.h new file mode 100644 index 0000000..e81fdd2 --- a/dev/null +++ b/noncore/games/kpacman/pacman.h @@ -0,0 +1,47 @@ +#ifndef PACMAN_H +#define PACMAN_H + +#include <stdlib.h> +#include <qpixmap.h> +#include <qwidget.h> + +#include "board.h" + +enum pacmanState { alive }; + +class Pacman { +public: + Pacman(Board *b); + void init(bool Demo = FALSE); + void setMaxPixmaps(int max); + void setAlive(int ticks); + void setPosition(int pos); + void setDirection(int dir, bool forced = FALSE); + void setDemo(bool yes); + pacmanState state(); + int position(); + int direction(); + bool move(); + int pix(); + +private: + Board *board; + + pacmanState actualState; // the state of pacman + bool demo; // real life or just demo + + int pauseDuration; // number of ticks before next movement + int pause; // actual ticks before movement (0=move) + + int actualDirection; // actual direction of pacman + int nextDirection; // where he wants to go + int lastPix; // last Pixmap-index before no movement + int maxPixmaps; // Number of Pixmaps (1..) + int actualPosition; // actual position on board + int lastPosition; // the last position of pacman + int mouthPosition; // eating + +}; + +#endif // PACMAN_H + diff --git a/noncore/games/kpacman/painter.cpp b/noncore/games/kpacman/painter.cpp new file mode 100644 index 0000000..16fed55 --- a/dev/null +++ b/noncore/games/kpacman/painter.cpp @@ -0,0 +1,972 @@ + +#include "portable.h" + +#if defined( KDE2_PORT ) +#include <kapp.h> +#include <kconfig.h> +#include <kstddirs.h> +#elif defined( QPE_PORT ) +#include <qpe/qpeapplication.h> +#include "config.h" +#endif + +#include <qcolor.h> +#include <qpainter.h> +#include <qpixmap.h> +#include <qbitmap.h> +#include <qrect.h> +#include <qstring.h> + +#include <qmessagebox.h> +#include <qfileinfo.h> + +#include "painter.h" +#include "board.h" + +Painter::Painter( Board *b, QWidget *parent, int Scheme, int Mode, Bitfont *font) +{ + w = parent; + board = b; + + pointPix = NULL; + wallPix = NULL; + prisonPix = NULL; + energizerPix = NULL; + fruitPix = NULL; + pacmanPix = NULL; + dyingPix = NULL; + eyesPix = NULL; + monsterPix = NULL; + fruitScorePix = NULL; + monsterScorePix = NULL; + + lastPointPixmapName = ""; + lastWallPixmapName = ""; + lastPrisonPixmapName = ""; + lastEnergizerPixmapName = ""; + lastFruitPixmapName = ""; + lastPacmanPixmapName = ""; + lastDyingPixmapName = ""; + lastEyesPixmapName = ""; + lastMonsterPixmapName = ""; + lastFruitScorePixmapName = ""; + lastMonsterScorePixmapName = ""; + + bitfont = font; + + scheme = Scheme; + mode = Mode; + level = 0; + + confScheme(); +} + +QList<QPixmap> *Painter::loadPixmap(QWidget*, QString pixmapName, + QList<QPixmap> *pixmaps) +{ + if (pixmaps == NULL) { + pixmaps = new QList<QPixmap>; + pixmaps->setAutoDelete(TRUE); + } + + if (!pixmaps->isEmpty()) + pixmaps->clear(); + + QPixmap PIXMAP(pixmapName); + if (PIXMAP.isNull() || PIXMAP.mask() == NULL) { + QString msg = i18n("The pixmap could not be contructed.\n\n" + "The file '@PIXMAPNAME@' does not exist,\n" + "or is of an unknown format."); + msg.replace(QRegExp("@PIXMAPNAME@"), pixmapName); + // QMessageBox::critical(parent, i18n("Initialization Error"), msg); + printf("%s\n", msg.data()); + return 0; + } + + int height = PIXMAP.height(); + int width = (height == 0) ? 0 : PIXMAP.width()/(PIXMAP.width()/height); + + QBitmap BITMAP; + QBitmap MASK; + + BITMAP = *PIXMAP.mask(); + MASK.resize(width, height); + + for (int x = 0; x < PIXMAP.width()/width; x++) { + QPixmap *pixmap = new QPixmap(width, height); + pixmaps->append(pixmap); + bitBlt(pixmap, 0, 0, &PIXMAP, x*width, 0, width, height, QPixmap::CopyROP, TRUE); + bitBlt(&MASK, 0, 0, &BITMAP, x*width, 0, width, height, QPixmap::CopyROP, TRUE); + pixmap->setMask(MASK); + } + + return pixmaps; +} + +QList<QPixmap> *Painter::textPixmap(QStrList &str, QList<QPixmap> *pixmaps, + QColor fg, QColor bg) +{ + if (pixmaps == NULL) { + pixmaps = new QList<QPixmap>; + pixmaps->setAutoDelete(TRUE); + } + + if (!pixmaps->isEmpty()) + pixmaps->clear(); + + for (uint s = 0; s < str.count(); s++) { + QPixmap *pixmap = new QPixmap(bitfont->text(str.at(s), fg, bg)); + pixmaps->append(pixmap); + } + + return pixmaps; +} + +QList<QPixmap> *Painter::textPixmap(QString str, QList<QPixmap> *pixmaps, + QColor fg, QColor bg) +{ + if (pixmaps == NULL) { + pixmaps = new QList<QPixmap>; + pixmaps->setAutoDelete(TRUE); + } + + if (!pixmaps->isEmpty()) + pixmaps->clear(); + + QPixmap *pixmap = new QPixmap(bitfont->text(str, fg, bg)); + pixmaps->append(pixmap); + + return pixmaps; +} + +/* Return the point of the upperleft pixel of the block representing that position + * on the board. + */ +QPoint Painter::point(int pos) +{ + return QPoint((board->x(pos)-1)*BlockWidth, (board->y(pos)-1)*BlockHeight); +} + + +QRect Painter::rect(int pos, PixMap pix, uint i) +{ + if (pos == OUT) + return QRect(); + + QPixmap *PIXMAP = NULL; + switch (pix) { + case PacmanPix : PIXMAP = pacmanPix-> + at(checkRange(i, pacmanPix->count()-1)); + break; + case DyingPix : PIXMAP = dyingPix-> + at(checkRange(i, dyingPix->count()-1)); + break; + case MonsterPix : PIXMAP = monsterPix-> + at(checkRange(i, monsterPix->count()-1)); + break; + case EyesPix : PIXMAP = eyesPix-> + at(checkRange(i, eyesPix->count()-1)); + break; + case FruitPix : PIXMAP = fruitPix-> + at(checkRange(i, fruitPix->count()-1)); + break; + case PointPix : PIXMAP = pointPix-> + at(checkRange(i, pointPix->count()-1)); + break; + case EnergizerPix : PIXMAP = energizerPix-> + at(checkRange(i, energizerPix->count()-1)); + break; + case FruitScorePix : PIXMAP = fruitScorePix-> + at(checkRange(i, fruitScorePix->count()-1)); + break; + case MonsterScorePix : PIXMAP = monsterScorePix-> + at(checkRange(i,monsterScorePix->count()-1)); + break; + default : PIXMAP = wallPix-> + at(checkRange(i, wallPix->count()-1)); + } + if (PIXMAP == NULL) + return QRect(); + + QRect rect = PIXMAP->rect(); + QPoint point = this->point(pos); + rect.moveCenter(QPoint(point.x()-1, point.y()-1)); + + return rect; +} + +QRect Painter::rect(int pos, QString str, int align) +{ + if (pos == OUT) // return an empty rect if the position + return QRect(); // is invalid + QPoint point = this->point(pos); + QRect rect = bitfont->rect(str); + + rect.moveCenter(QPoint(point.x()-1, point.y()-1)); + + int dx = 0; + int dy = 0; + + if (align & QLabel::AlignLeft || align & QLabel::AlignRight) { + dx = (str.length()-1) * (bitfont->width()/2); + if (align & QLabel::AlignRight) + dx *= -1; + } + + if (align & QLabel::AlignTop || align & QLabel::AlignBottom) { + dy = bitfont->height()/2; + if (align & QLabel::AlignBottom) + dy *= -1; + } + + if (dx != 0 || dy != 0) + rect.moveBy(dx, dy); + + return rect; +} + +QRect Painter::rect(QRect r1, QRect r2) +{ + QRect rect; + rect.setLeft(r1.left() < r2.left() ? r1.left() : r2.left()); + rect.setTop(r1.top() < r2.top() ? r1.top() : r2.top()); + rect.setRight(r1.right() > r2.right() ? r1.right() : r2.right()); + rect.setBottom(r1.bottom() > r2.bottom() ? r1.bottom() : r2.bottom()); + + return rect; +} + +void Painter::erase(int pos, PixMap pix, uint i) +{ + if (pos == OUT) + return; + QRect rect = this->rect(pos, pix, i); + bitBlt(&roomPix, rect.x(), rect.y(), &backPix, + rect.x(), rect.y(), rect.width(), rect.height()); +} + +int Painter::maxPixmaps(PixMap pix) +{ + switch (pix) { + case WallPix : return (int) wallPix->count(); + case PrisonPix : return (int) prisonPix->count(); + case PointPix : return (int) pointPix->count(); + case EnergizerPix : return (int) energizerPix->count(); + case FruitPix : return (int) fruitPix->count(); + case PacmanPix : return (int) pacmanPix->count(); + case DyingPix : return (int) dyingPix->count(); + case EyesPix : return (int) eyesPix->count(); + case MonsterPix : return (int) monsterPix->count(); + case FruitScorePix : return (int) fruitScorePix->count(); + case MonsterScorePix : return (int) monsterScorePix->count(); + default : return 0; + } +} + +void Painter::draw(QPoint point, DrawWidget where, QPixmap pix) +{ + switch (where) { + case Widget : bitBlt(w, point.x(), point.y(), &pix); + break; + case RoomPix : bitBlt(&roomPix, point.x(), point.y(), &pix); + break; + case BackPix : bitBlt(&backPix, point.x(), point.y(), &pix); + break; + } +} + +void Painter::draw(QRect rect, DrawWidget where, QPixmap pix) +{ + draw(QPoint(rect.x(), rect.y()), where, pix); +} + +void Painter::draw(int pos, DrawWidget where, PixMap pix, uint i) +{ + QPixmap *PIXMAP = NULL; + switch (pix) { + case PacmanPix : PIXMAP = pacmanPix-> + at(checkRange(i, pacmanPix->count()-1)); + break; + case DyingPix : PIXMAP = dyingPix-> + at(checkRange(i, dyingPix->count()-1)); + break; + case MonsterPix : PIXMAP = monsterPix-> + at(checkRange(i, monsterPix->count()-1)); + break; + case EyesPix : PIXMAP = eyesPix-> + at(checkRange(i, eyesPix->count()-1)); + break; + case FruitPix : PIXMAP = fruitPix-> + at(checkRange(i, fruitPix->count()-1)); + break; + case EnergizerPix : PIXMAP = energizerPix-> + at(checkRange(i, energizerPix->count()-1)); + break; + case FruitScorePix : PIXMAP = fruitScorePix-> + at(checkRange(i, fruitScorePix->count()-1)); + break; + case MonsterScorePix : PIXMAP = monsterScorePix-> + at(checkRange(i,monsterScorePix->count()-1)); + break; + default : ; + } + + if (PIXMAP == NULL) + return; + + QRect rect = PIXMAP->rect(); + QPoint point = this->point(pos); + rect.moveCenter(QPoint(point.x()-1, point.y()-1)); + + switch (where) { + case Widget : bitBlt(w, rect.x(), rect.y(), PIXMAP); + break; + case RoomPix : bitBlt(&roomPix, rect.x(), rect.y(), PIXMAP); + break; + case BackPix : bitBlt(&backPix, rect.x(), rect.y(), PIXMAP); + break; + } +} + +QPixmap Painter::draw(int pos, DrawWidget where, + QString str, QColor fg, QColor bg, int align) +{ + QPixmap TEXT = bitfont->text(str, fg, bg); + + QRect rect = this->rect(pos, str, align); + QPixmap SAVE = QPixmap(rect.width(), rect.height()); + + switch (where) { + case Widget : bitBlt(&SAVE, 0, 0, w, rect.x(), rect.y()); + bitBlt(w, rect.x(), rect.y(), &TEXT); + break; + case RoomPix : bitBlt(&SAVE, 0, 0, &roomPix, rect.x(), rect.y()); + bitBlt(&roomPix, rect.x(), rect.y(), &TEXT); + break; + case BackPix : bitBlt(&SAVE, 0, 0, &backPix, rect.x(), rect.y()); + bitBlt(&backPix, rect.x(), rect.y(), &TEXT); + break; + } + + return SAVE; +} + +QRect Painter::draw(int col, int row, DrawWidget where, + QString str, QColor fg, QColor bg, int align) +{ + QPixmap TEXT = bitfont->text(str, fg, bg); + + QRect rect = this->rect(row*BoardWidth+col, str, align); + draw(rect, where, TEXT); + + return rect; +} + +void Painter::initPixmaps() +{ + if (lastPointPixmapName != pointPixmapName.at(level)) { + pointPix = loadPixmap(w, pointPixmapName.at(level), pointPix); + lastPointPixmapName = pointPixmapName.at(level); + } + if (lastPrisonPixmapName != prisonPixmapName.at(level)) { + prisonPix = loadPixmap(w, prisonPixmapName.at(level), prisonPix); + lastPrisonPixmapName = prisonPixmapName.at(level); + } + if (lastEnergizerPixmapName != energizerPixmapName.at(level)) { + energizerPix = loadPixmap(w, energizerPixmapName.at(level), energizerPix); + lastEnergizerPixmapName = energizerPixmapName.at(level); + } + if (lastFruitPixmapName != fruitPixmapName.at(level)) { + fruitPix = loadPixmap(w, fruitPixmapName.at(level), fruitPix); + lastFruitPixmapName = fruitPixmapName.at(level); + } + if (lastPacmanPixmapName != pacmanPixmapName.at(level)) { + pacmanPix = loadPixmap(w, pacmanPixmapName.at(level), pacmanPix); + lastPacmanPixmapName = pacmanPixmapName.at(level); + } + if (lastDyingPixmapName != dyingPixmapName.at(level)) { + dyingPix = loadPixmap(w, dyingPixmapName.at(level), dyingPix); + lastDyingPixmapName = dyingPixmapName.at(level); + } + if (lastEyesPixmapName != eyesPixmapName.at(level)) { + eyesPix = loadPixmap(w, eyesPixmapName.at(level), eyesPix); + lastEyesPixmapName = eyesPixmapName.at(level); + } + if (lastMonsterPixmapName != monsterPixmapName.at(level)) { + monsterPix = loadPixmap(w, monsterPixmapName.at(level), monsterPix); + lastMonsterPixmapName = monsterPixmapName.at(level); + } + + if (lastFruitScorePixmapName != fruitScorePixmapName.at(level) || + (const char *) *fruitScorePixmapName.at(level) == '\0') { + if ((const char *) *fruitScorePixmapName.at(level) == '\0') { + fruitScorePix = textPixmap(fruitScoreString, fruitScorePix, PINK); + } else { + fruitScorePix = loadPixmap(w, fruitScorePixmapName.at(level), + fruitScorePix); + lastFruitScorePixmapName = fruitScorePixmapName.at(level); + } + } + + if (lastMonsterScorePixmapName != monsterScorePixmapName.at(level) || + (const char *) *monsterScorePixmapName.at(level) == '\0') { + if ((const char *) *monsterScorePixmapName.at(level) == '\0') { + monsterScorePix = textPixmap(monsterScoreString, monsterScorePix, CYAN); + } else { + monsterScorePix = loadPixmap(w, monsterScorePixmapName.at(level), + monsterScorePix); + lastMonsterScorePixmapName = monsterScorePixmapName.at(level); + } + } + + if (lastWallPixmapName != wallPixmapName.at(level)) { + wallPix = loadPixmap(w, wallPixmapName.at(level), wallPix); + if (wallPix->isEmpty()) { + BlockWidth = 0; + BlockHeight = 0; + } else { + BlockWidth = wallPix->at(0)->width(); + BlockHeight = wallPix->at(0)->height(); + } + lastWallPixmapName = wallPixmapName.at(level); + } +} + +void Painter::initbackPixmaps() +{ + backgroundColor = BLACK; + + backPix.resize((BoardWidth-3)*BlockWidth, (BoardHeight-3)*BlockHeight ); + backPix.fill(backgroundColor); +} + +void Painter::initRoomPixmap() +{ + roomPix.resize((BoardWidth-3)*BlockWidth, (BoardHeight-3)*BlockHeight ); + bitBlt(&roomPix,0,0, &backPix); + + for (unsigned int x = 0; x < board->size(); x++) { + if (board->isBrick(x)) + drawBrick(x); + if (board->isPrison(x) || board->isGate(x)) + drawPrison(x); + if (board->isPoint(x)) + drawPoint(x); + } +} + +void Painter::drawBrick(int pos) +{ + int border = 0; + if (board->isBrick(board->move(pos, N ))) border |= (1 << 0); + if (board->isBrick(board->move(pos, NE))) border |= (1 << 1); + if (board->isBrick(board->move(pos, E ))) border |= (1 << 2); + if (board->isBrick(board->move(pos, SE))) border |= (1 << 3); + if (board->isBrick(board->move(pos, S ))) border |= (1 << 4); + if (board->isBrick(board->move(pos, SW))) border |= (1 << 5); + if (board->isBrick(board->move(pos, W ))) border |= (1 << 6); + if (board->isBrick(board->move(pos, NW))) border |= (1 << 7); + + if (board->isOut(board->move(pos, N ))) border |= (1 << 8); + if (board->isOut(board->move(pos, NE))) border |= (1 << 9); + if (board->isOut(board->move(pos, E ))) border |= (1 << 10); + if (board->isOut(board->move(pos, SE))) border |= (1 << 11); + if (board->isOut(board->move(pos, S ))) border |= (1 << 12); + if (board->isOut(board->move(pos, SW))) border |= (1 << 13); + if (board->isOut(board->move(pos, W ))) border |= (1 << 14); + if (board->isOut(board->move(pos, NW))) border |= (1 << 15); + + switch (border & 0xFF) { + case 31 : border = 0; break; + case 159 : border = 0; break; + case 63 : border = 0; break; + case 191 : border = 0; break; + case 241 : border = 1; break; + case 249 : border = 1; break; + case 243 : border = 1; break; + case 251 : border = 1; break; + case 124 : border = 2; break; + case 252 : border = 2; break; + case 126 : border = 2; break; + case 199 : border = 3; break; + case 231 : border = 3; break; + case 207 : border = 3; break; + case 28 : if ((border >> 8) > 0) + border = 24; + else + border = 4; + break; + case 112 : if ((border >> 8) > 0) + border = 27; + else + border = 5; + break; + case 7 : if ((border >> 8) > 0) + border = 25; + else + border = 6; + break; + case 193 : if ((border >> 8) > 0) + border = 26; + else + border = 7; + break; + case 247 : if ((border & (1 << 11)) > 0) + border = 23; + else + border = 8; + break; + case 119 : if ((border & (1 << 15)) > 0) + border = 8; + if ((border & (1 << 11)) > 0) + border = 11; + break; + case 223 : if ((border & (1 << 13)) > 0) + border = 20; + else + border = 9; + break; + case 221 : if ((border & (1 << 13)) > 0) + border = 10; + if ((border & (1 << 9)) > 0) + border = 9; + break; + case 253 : if ((border & (1 << 9)) > 0) + border = 21; + else + border = 10; + break; + case 127 : if ((border & (1 << 15)) > 0) + border = 22; + else + border = 11; + break; + case 30 : border = 12; break; + case 240 : border = 13; break; + case 15 : border = 14; break; + case 225 : border = 15; break; + case 135 : border = 16; break; + case 195 : border = 17; break; + case 60 : border = 18; break; + case 120 : border = 19; break; + case 255 : border = 28; break; + default : border = -1; + } + if (border != -1 && border < (int) wallPix->count()) { + QRect rect = this->rect(pos, WallPix); + bitBlt(&roomPix, rect.x(), rect.y(), wallPix->at((uint) border)); + } +} + +void Painter::drawPrison(int pos) +{ + int border = 0; + if (board->isPrison(board->move(pos, N ))) border |= (1 << 0); + if (board->isPrison(board->move(pos, NE))) border |= (1 << 1); + if (board->isPrison(board->move(pos, E ))) border |= (1 << 2); + if (board->isPrison(board->move(pos, SE))) border |= (1 << 3); + if (board->isPrison(board->move(pos, S ))) border |= (1 << 4); + if (board->isPrison(board->move(pos, SW))) border |= (1 << 5); + if (board->isPrison(board->move(pos, W ))) border |= (1 << 6); + if (board->isPrison(board->move(pos, NW))) border |= (1 << 7); + + if (board->isGate(board->move(pos, N ))) border |= (1 << 8); + if (board->isGate(board->move(pos, NE))) border |= (1 << 9); + if (board->isGate(board->move(pos, E ))) border |= (1 << 10); + if (board->isGate(board->move(pos, SE))) border |= (1 << 11); + if (board->isGate(board->move(pos, S ))) border |= (1 << 12); + if (board->isGate(board->move(pos, SW))) border |= (1 << 13); + if (board->isGate(board->move(pos, W ))) border |= (1 << 14); + if (board->isGate(board->move(pos, NW))) border |= (1 << 15); + + switch (border & 0xFF) { + case 31 : border = 0; break; + case 159 : border = 0; break; + case 63 : border = 0; break; + case 241 : border = 1; break; + case 249 : border = 1; break; + case 243 : border = 1; break; + case 124 : border = 2; break; + case 252 : border = 2; break; + case 126 : border = 2; break; + case 199 : border = 3; break; + case 231 : border = 3; break; + case 207 : border = 3; break; + case 28 : if ((border >> 8) != 0) + border = 12; + else + border = 4; + break; + case 112 : if ((border >> 8) != 0) + border = 13; + else + border = 5; + break; + case 7 : if ((border >> 8) != 0) + border = 14; + else + border = 6; + break; + case 193 : if ((border >> 8) != 0) + border = 15; + else + border = 7; + break; + case 247 : border = 8; break; + case 223 : border = 9; break; + case 253 : border = 10; break; + case 127 : border = 11; break; + default : border = -1; + } + if (board->isGate(pos)) { + if (board->isGate(board->move(pos, N))) + border = 17; + else + border = 16; + } + + if (border != -1 && border < (int) prisonPix->count()) { + QRect rect = this->rect(pos, PrisonPix); + bitBlt(&roomPix, rect.x(), rect.y(), prisonPix->at((uint) border)); + } +} + +void Painter::drawPoint(int pos) +{ + if (!pointPix->isEmpty()) { + QRect rect = this->rect(pos, PointPix); + bitBlt(&roomPix, rect.x(), rect.y(), pointPix->at(0)); + } +} + +QString Painter::decodeHexOctString(QString s) +{ + QString value; + QString valids; + int pos, xpos = 0, opos = 0; + int v, len, leadin; + const char *ptr; + uchar c; + + while (((xpos = s.find(QRegExp("\\\\x[0-9a-fA-F]+"), xpos)) != -1) || + ((opos = s.find(QRegExp("\\\\[0-7]+"), opos)) != -1)) { + if (xpos != -1) { + valids = "0123456789abcdef"; + leadin = 2; + pos = xpos; + } else { + valids = "01234567"; + leadin = 1; + pos = opos; + } + + c = '\0'; + len = 0; + value = s.mid(pos+leadin, 3); + ptr = (const char *) value; + + while (*ptr != '\0' && (v = valids.find(*ptr++, 0, FALSE)) != -1) { + c = (c * valids.length()) + v; + len++; + } + + value.fill(c, 1); + s.replace(pos, len+leadin, value); + } + + return s; +} + +void Painter::fillScoreString(QStrList &list, QArray<int> &values) +{ + if( !list.isEmpty()) + list.clear(); + + QString s; + + for (uint i = 0; i < values.size(); i++) { + + if (values[i] < 10 || values[i] > 10000) + s = "?"; + else if (values[i] == 1600) + s = "\x1a\x1b"; + else if (values[i] < 100) { + s = "\x0e"; + s.insert(0, char (values[i] / 10 + 0x10)); + } else if (values[i] < 1000) { + s = "\x0f"; + s.insert(0, char (values[i] / 100 + 0x10)); + } else { + s = "\x0f\x10"; + s.insert(0, char (values[i] / 1000 + 0x10)); + } + + list.append(s.data()); + } +} + +void Painter::fillArray(QArray<int> &array, QString values, int max) +{ + array.resize(max); + int last = 0; + bool ok; + QString value; + + for (uint i = 0; i < array.size(); i++) { + if (values.find(',') < 0 && values.length() > 0) { + value = values; + values = ""; + } + if (values.find(',') >= 0) { + value = values.left(values.find(',')); + values.remove(0,values.find(',')+1); + } + array[i] = value.toInt(&ok); + if (ok) + last = array[i]; + else + array[i] = last; + } +} + +void Painter::fillStrList(QStrList &list, QString values, int max) +{ + if (!list.isEmpty()) + list.clear(); + + QString last = ""; + QString value; + + for (uint i = 0; i < (uint) max; i++) { + if (values.find(',') < 0 && values.length() > 0) { + value = values; + values = ""; + } + if (values.find(',') >= 0) { + value = values.left(values.find(',')); + values.remove(0,values.find(',')+1); + } + if (!value.isEmpty()) + last = decodeHexOctString(value); + list.append(last); + } +} + +void Painter::fillPixmapName(QStrList &pixmapName) +{ + QStrList list = pixmapName; + + if (!pixmapName.isEmpty()) + pixmapName.clear(); + + QString pixmap; + + QFileInfo fileInfo; + + for (uint i = 0; i < list.count(); i++) { + pixmap = list.at(i); + + if (pixmap.left(1) != "/" && pixmap.left(1) != "~") + pixmap = FIND_APP_DATA( pixmapDirectory+pixmap ); + + fileInfo.setFile(pixmap); + if (!fileInfo.isReadable() || !fileInfo.isFile()) + pixmap = ""; + + pixmapName.append(pixmap); + } +} + +void Painter::confLevels(bool defGroup) +{ + APP_CONFIG_BEGIN( cfg ); + if (defGroup || cfg->hasKey("Levels")) + maxLevel = cfg->readNumEntry("Levels", 13); + APP_CONFIG_END( cfg ); +} + +void Painter::confMisc(bool defGroup) +{ + APP_CONFIG_BEGIN( cfg ); + if (defGroup || cfg->hasKey("PixmapDirectory")) { + pixmapDirectory = cfg->readEntry("PixmapDirectory"); + + if (pixmapDirectory.left(1) != "/" && pixmapDirectory.left(1) != "~") + pixmapDirectory.insert(0, "pics/"); + if (pixmapDirectory.right(1) != "/") + pixmapDirectory.append("/"); + } + + if (defGroup || cfg->hasKey("PointPixmapName")) + fillStrList(pointPixmapName, + cfg->readEntry("PointPixmapName", "point.xpm"), maxLevel+1); + if (defGroup || cfg->hasKey("WallPixmapName")) + fillStrList(wallPixmapName, + cfg->readEntry("WallPixmapName", "wall.xpm"), maxLevel+1); + if (defGroup || cfg->hasKey("PrisonPixmapName")) + fillStrList(prisonPixmapName, + cfg->readEntry("PrisonPixmapName", "prison.xpm"), maxLevel+1); + if (defGroup || cfg->hasKey("EnergizerPixmapName")) + fillStrList(energizerPixmapName, + cfg->readEntry("EnergizerPixmapName", "switch.xpm"),maxLevel+1); + if (defGroup || cfg->hasKey("FruitPixmapName")) + fillStrList(fruitPixmapName, + cfg->readEntry("FruitPixmapName", "fruit.xpm"), maxLevel+1); + if (defGroup || cfg->hasKey("PacmanPixmapName")) + fillStrList(pacmanPixmapName, + cfg->readEntry("PacmanPixmapName", "pacman.xpm"), maxLevel+1); + if (defGroup || cfg->hasKey("DyingPixmapName")) + fillStrList(dyingPixmapName, + cfg->readEntry("DyingPixmapName", "dying.xpm"), maxLevel+1); + if (defGroup || cfg->hasKey("EyesPixmapName")) + fillStrList(eyesPixmapName, + cfg->readEntry("EyesPixmapName", "eyes.xpm"), maxLevel+1); + if (defGroup || cfg->hasKey("MonsterPixmapName")) + fillStrList(monsterPixmapName, + cfg->readEntry("MonsterPixmapName", "monster.xpm"), maxLevel+1); + + if (defGroup || cfg->hasKey("FruitScorePixmapName")) + fillStrList(fruitScorePixmapName, + cfg->readEntry("FruitScorePixmapName"), maxLevel+1); + if (defGroup || cfg->hasKey("MonsterScorePixmapName")) + fillStrList(monsterScorePixmapName, + cfg->readEntry("MonsterScorePixmapName"), maxLevel+1); + APP_CONFIG_END( cfg ); +} + +void Painter::confScoring(bool defGroup) +{ + APP_CONFIG_BEGIN( cfg ); + if (defGroup || cfg->hasKey("FruitScore")) + fillArray(fruitScore, + cfg->readEntry("FruitScore", + "100,300,500,,700,,1000,,2000,,3000,,5000"), + maxLevel+1); + if (defGroup || cfg->hasKey("MonsterScore")) + fillArray(monsterScore, + cfg->readEntry("MonsterScore", "200,400,800,1600"), 4); + + if (defGroup || cfg->hasKey("FruitScoreString")) + fillStrList(fruitScoreString, + cfg->readEntry("FruitScoreString"), maxLevel+1); + if (defGroup || cfg->hasKey("MonsterScoreString")) + fillStrList(monsterScoreString, + cfg->readEntry("MonsterScoreString"), 4); + APP_CONFIG_END( cfg ); +} + +void Painter::confScheme() +{ + APP_CONFIG_BEGIN( cfg ); + SAVE_CONFIG_GROUP( cfg, oldgroup ); + QString newgroup; + + // if not set, read mode and scheme from the configfile + if (mode == -1 && scheme == -1) { + scheme = cfg->readNumEntry("Scheme", -1); + mode = cfg->readNumEntry("Mode", -1); + + // if mode is not set in the defGroup-group, lookup the scheme group + if (scheme != -1 || mode == -1) { + newgroup.sprintf("Scheme %d", scheme); + cfg->setGroup(newgroup); + + mode = cfg->readNumEntry("Mode", -1); + RESTORE_CONFIG_GROUP( cfg, oldgroup ); + } + } + + confLevels(); + + if (mode != -1) { + newgroup.sprintf("Mode %d", mode); + cfg->setGroup(newgroup); + + confLevels(FALSE); + } + + if (scheme != -1) { + newgroup.sprintf("Scheme %d", scheme); + cfg->setGroup(newgroup); + + confLevels(FALSE); + } + + RESTORE_CONFIG_GROUP( cfg, oldgroup ); + + confMisc(); + confScoring(); + + if (mode != -1) { + newgroup.sprintf("Mode %d", mode); + cfg->setGroup(newgroup); + + confMisc(FALSE); + confScoring(FALSE); + } + + if (scheme != -1) { + newgroup.sprintf("Scheme %d", scheme); + cfg->setGroup(newgroup); + + confMisc(FALSE); + confScoring(FALSE); + } + + if ((const char *) *fruitScoreString.at(0) == '\0') + fillScoreString(fruitScoreString, fruitScore); + if ((const char *) *monsterScoreString.at(0) == '\0') + fillScoreString(monsterScoreString, monsterScore); + + fillPixmapName(pointPixmapName); + fillPixmapName(wallPixmapName); + fillPixmapName(prisonPixmapName); + fillPixmapName(energizerPixmapName); + fillPixmapName(fruitPixmapName); + fillPixmapName(pacmanPixmapName); + fillPixmapName(dyingPixmapName); + fillPixmapName(eyesPixmapName); + fillPixmapName(monsterPixmapName); + fillPixmapName(fruitScorePixmapName); + fillPixmapName(monsterScorePixmapName); + + initPixmaps(); + initbackPixmaps(); + initRoomPixmap(); + + RESTORE_CONFIG_GROUP( cfg, oldgroup ); + APP_CONFIG_END( cfg ); +} + +void Painter::setScheme(int Scheme, int Mode, Bitfont *font) +{ + bitfont = font; + + mode = Mode; + scheme = Scheme; + + confScheme(); +} + +void Painter::setLevel(int Level) +{ + level = Level; + + initPixmaps(); + initbackPixmaps(); + initRoomPixmap(); +} + +int Painter::checkRange(int value, int max, int min) +{ + if (value < min) { + printf("Painter::checkRange (value = %d, max = %d, min = %d)\n", + value, max, min); + return min; + } else if (value > max) { + printf("Painter::checkRange (value = %d, max = %d, min = %d)\n", + value, max, min); + return max; + } else + return value; +} diff --git a/noncore/games/kpacman/painter.h b/noncore/games/kpacman/painter.h new file mode 100644 index 0000000..3a4eae2 --- a/dev/null +++ b/noncore/games/kpacman/painter.h @@ -0,0 +1,148 @@ +#ifndef PAINTER_H +#define PAINTER_H + +#include "portable.h" + +#if defined( KDE2_PORT ) +#include <kapp.h> +#include <klocale.h> +#endif + +#include <qpixmap.h> +#include <qbitmap.h> +#include <qlabel.h> +#include <qcolor.h> +#include <qlist.h> +#include <qstrlist.h> +#include <qregexp.h> + +#include "board.h" +#include "bitfont.h" +#include "colors.h" + +enum PixMap { PacmanPix, DyingPix, MonsterPix, EyesPix, FruitPix, + PointPix, EnergizerPix, WallPix, PrisonPix, + FruitScorePix, MonsterScorePix }; +enum DrawWidget { Widget, RoomPix, BackPix }; + +class Painter +{ +public: + Painter (Board *, QWidget *parent=0, int scheme=-1, int mode=-1,Bitfont *font=0); + QPixmap levelPix() { return roomPix; } + + void setScheme(int scheme=-1, int mode=-1, Bitfont *font=0); + void setLevel(int level=0); + + QRect rect(int pos, PixMap pix, uint i = 0); + QRect rect(int pos, QString str, int align = QLabel::AlignCenter ); + QRect rect(QRect r1, QRect r2); + + void draw(QPoint point, DrawWidget where, QPixmap pix); + void draw(QRect rect, DrawWidget where, QPixmap pix); + void draw(int pos, DrawWidget where, PixMap pix, uint i = 0); + QPixmap draw(int pos, DrawWidget where, QString str, + QColor fg, QColor bg = QColor(), int align = QLabel::AlignCenter); + QRect draw(int col, int row, DrawWidget where, QString str, + QColor fg, QColor bg = QColor(), int align = QLabel::AlignCenter); + + void drawBrick(int pos); + void drawPrison(int pos); + void drawPoint(int pos); + + void erase(int pos, PixMap pix, uint i = 0); + + int maxPixmaps(PixMap pix); + +protected: + QString decodeHexOctString(QString str); + + void fillScoreString(QStrList &, QArray<int> &); + void fillArray(QArray<int> &, QString, int); + void fillStrList(QStrList &, QString, int); + void fillPixmapName(QStrList &); + + void confScheme(); + void confLevels(bool defGroup=TRUE); + void confMisc(bool defGroup=TRUE); + void confScoring(bool defGroup=TRUE); + + void initPixmaps(); + void initRoomPixmap(); + void initbackPixmaps(); + +private: + QWidget *w; + Board *board; + Bitfont *bitfont; + + int BlockWidth; + int BlockHeight; + + QArray<int> fruitScore; + QStrList fruitScoreString; + QArray<int> monsterScore; + QStrList monsterScoreString; + + QString pixmapDirectory; + + QStrList pointPixmapName; + QStrList wallPixmapName; + QStrList prisonPixmapName; + QStrList energizerPixmapName; + QStrList fruitPixmapName; + QStrList pacmanPixmapName; + QStrList dyingPixmapName; + QStrList eyesPixmapName; + QStrList monsterPixmapName; + QStrList fruitScorePixmapName; + QStrList monsterScorePixmapName; + + QString lastPointPixmapName; + QString lastWallPixmapName; + QString lastPrisonPixmapName; + QString lastEnergizerPixmapName; + QString lastFruitPixmapName; + QString lastPacmanPixmapName; + QString lastDyingPixmapName; + QString lastEyesPixmapName; + QString lastMonsterPixmapName; + QString lastFruitScorePixmapName; + QString lastMonsterScorePixmapName; + + QList<QPixmap> *loadPixmap(QWidget *parent, QString pixmapName, + QList<QPixmap> *pixmaps=0); + QList<QPixmap> *textPixmap(QStrList &, QList<QPixmap> *pixmaps=0, + QColor fg = BLACK, QColor bg = QColor()); + QList<QPixmap> *textPixmap(QString str, QList<QPixmap> *pixmaps=0, + QColor fg = BLACK, QColor bg = QColor()); + + QPoint point(int pos); + int checkRange(int value, int max, int min=0); + + QList<QPixmap> *wallPix; + QList<QPixmap> *prisonPix; + QList<QPixmap> *pointPix; + QList<QPixmap> *energizerPix; + QList<QPixmap> *fruitPix; + QList<QPixmap> *pacmanPix; + QList<QPixmap> *dyingPix; + QList<QPixmap> *eyesPix; + QList<QPixmap> *monsterPix; + QList<QPixmap> *fruitScorePix; + QList<QPixmap> *monsterScorePix; + + QPixmap roomPix; + QPixmap backPix; + + bool plainColor; + QColor backgroundColor; + + int maxLevel; + int level; + + int scheme; + int mode; +}; + +#endif // PAINTER_H diff --git a/noncore/games/kpacman/portable.h b/noncore/games/kpacman/portable.h new file mode 100644 index 0000000..ff0912b --- a/dev/null +++ b/noncore/games/kpacman/portable.h @@ -0,0 +1,63 @@ +/*************************************************************************** + portable.h - various bits that ease porting kpacman to other platforms. + Currently KDE2 and Qtopia ports exist. + ------------------- + begin : Mon Mar 18 12:35:24 EET 2002 + copyright : (C) 2002 by Catalin Climov + email : catalin@climov.com + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef PORTABLE_H +#define PORTABLE_H + +#ifdef QWS +#define QPE_PORT +#else +#define KDE2_PORT +#define KDE_PORT +#endif + +#if defined( KDE2_PORT ) + +#define APP kapp + +#define APP_CONFIG_BEGIN( cfgname ) KConfig cfgname = kapp->config() +#define APP_CONFIG_END( cfgname ) cfgname->sync() +#define SAVE_CONFIG_GROUP( cfgname, groupname ) QString groupname = configname->group() +#define RESTORE_CONFIG_GROUP( cfgname, groupname ) configname->setGroup( groupname ) + +#define FIND_APP_DATA( dataname ) KGlobal::dirs()->findResource( "appdata", dataname ) + +#elif defined( QPE_PORT ) + +#define i18n( x ) x +#define KTMainWindow QMainWindow +#define KMenuBar QMenuBar +#define KAccel QAccel +#define APP qApp + +#define APP_CONFIG_BEGIN( cfgname ) Config* cfgname = new Config("kpacman"); cfgname->setGroup("Default"); +#define APP_CONFIG_END( cfgname ) delete cfgname +#define SAVE_CONFIG_GROUP( cfgname, groupname ) +#define RESTORE_CONFIG_GROUP( cfgname, groupname ) cfgname->setGroup("Default") + +#define FIND_APP_DATA( dataname ) (QPEApplication::qpeDir()+"share/kpacman/"+dataname) + +#else + +#error "Err, I don't know what platform to compile for (KDE2 or Qtopia)" + +#endif + +#define APP_QUIT() APP->quit() + +#endif // PORTABLE_H diff --git a/noncore/games/kpacman/referee.cpp b/noncore/games/kpacman/referee.cpp new file mode 100644 index 0000000..567a8ed --- a/dev/null +++ b/noncore/games/kpacman/referee.cpp @@ -0,0 +1,1426 @@ + +#include "portable.h" + +#if defined( KDE2_PORT ) +#include <kapp.h> +#include <kconfig.h> +#include <kstddirs.h> +#include <kaccel.h> +#include <referee.h> +#include <referee.moc> +#elif defined( QPE_PORT ) +#include <qaccel.h> +#include <qpe/qpeapplication.h> +#include "config.h" +#include "referee.h" +#endif + +#include <qdatetm.h> +#include <stdlib.h> +#include <qtimer.h> +#include <qevent.h> +#include <qcolor.h> +#include <qkeycode.h> +#include <qfileinfo.h> + +#include "board.h" +#include "pacman.h" +#include "monster.h" +#include "fruit.h" +#include "painter.h" + +Referee::Referee( QWidget *parent, const char *name, int Scheme, int Mode, Bitfont *font) + : QWidget( parent, name ) +{ + gameState.resize(12); + gameTimer = 0; + energizerTimer = 0; + + focusedPause = FALSE; + setFocusPolicy(QWidget::StrongFocus); + + initKeys(); + + scheme = Scheme; + mode = Mode; + confScheme(); + + board = new Board(BoardWidth*BoardHeight); + + pix = new Painter(board, this, scheme, mode, font); + setFixedSize(pix->levelPix().size()); + + pacman = new Pacman(board); + + fruit = new Fruit(board); + + monsters = new QList<Monster>; + monsters->setAutoDelete(TRUE); + + monsterRect = new QList<QRect>; + monsterRect->setAutoDelete(TRUE); + + energizers = new QList<Energizer>; + energizers->setAutoDelete(TRUE); + + energizerRect = new QList<QRect>; + energizerRect->setAutoDelete(TRUE); + + pacmanRect.setRect(0, 0, 0, 0); + fruitRect.setRect(0, 0, 0, 0); + + QTime midnight( 0, 0, 0 ); + srand( midnight.secsTo(QTime::currentTime()) ); + + lifes = 0; + points = 0; + + emit setLifes(lifes); + emit setPoints(points); + + intro(); +} + +void Referee::paintEvent( QPaintEvent *e) +{ + if (gameState.testBit(HallOfFame)) + return; + + QRect rect = e->rect(); + + if (!rect.isEmpty()) { + QPixmap p = pix->levelPix(); + bitBlt(this, rect.x(), rect.y(), + &p, rect.x(), rect.y(), rect.width(), rect.height()); + } + + if ((gameState.testBit(GameOver) || gameState.testBit(Demonstration)) && + rect.intersects(pix->rect(board->position(fruithome), i18n("GAME OVER")))) + pix->draw(board->position(fruithome), Widget, i18n("GAME OVER"), RED); + + for (Energizer *e = energizers->first(); e != 0; e = energizers->next()) { + if (e && e->state() == on && + rect.intersects(pix->rect(e->position(), EnergizerPix)) && + !(e->position() == pacman->position() && gameState.testBit(Scoring))) { + if (e->pix() != -1) + pix->draw(e->position(), Widget, EnergizerPix, e->pix()); + } + } + + if (!gameState.testBit(Init)) { + + if (!gameState.testBit(Dying) && (fruit->pix() != -1)) + if (fruit->state() != active) { + if (rect.intersects(pix->rect(fruit->position(), FruitScorePix, fruit->pix()))) + pix->draw(fruit->position(), Widget, FruitScorePix, fruit->pix()); + } else { + if (rect.intersects(pix->rect(fruit->position(), FruitPix, fruit->pix()))) + pix->draw(fruit->position(), Widget, FruitPix, fruit->pix()); + } + + for (Monster *m = monsters->first(); m != 0; m = monsters->next()) + if (m && m->state() == harmless && + rect.intersects(pix->rect(m->position(), MonsterPix)) && + !(m->position() == pacman->position() && gameState.testBit(Scoring))) { + if (m->body() != -1) + pix->draw(m->position(), Widget, MonsterPix, m->body()); + if (m->eyes() != -1) + pix->draw(m->position(), Widget, EyesPix, m->eyes()); + } + + if (!gameState.testBit(Scoring) && !gameState.testBit(LevelDone) && + rect.intersects(pix->rect(pacman->position(), PacmanPix)) && pacman->pix() != -1) + pix->draw(pacman->position(), Widget, PacmanPix, pacman->pix()); + + for (Monster *m = monsters->first(); m != 0; m = monsters->next()) + if (m && m->state() != harmless && + rect.intersects(pix->rect(m->position(), MonsterPix)) && + !(m->position() == pacman->position() && gameState.testBit(Scoring))) { + if (m->body() != -1) + pix->draw(m->position(), Widget, MonsterPix, m->body()); + if (m->eyes() != -1) + pix->draw(m->position(), Widget, EyesPix, m->eyes()); + } + } + + if (gameState.testBit(Scoring) && + rect.intersects(pix->rect(pacman->position(), MonsterScorePix, monstersEaten-1))) + pix->draw(pacman->position(), Widget, MonsterScorePix, monstersEaten-1); + + if (gameState.testBit(Init) && gameState.testBit(Dying) && + timerCount < pix->maxPixmaps(DyingPix) && + rect.intersects(pix->rect(pacman->position(), PacmanPix))) + pix->draw(pacman->position(), Widget, DyingPix, timerCount); + + if (gameState.testBit(LevelDone) && + rect.intersects(pix->rect(pacman->position(), PacmanPix))) + pix->draw(pacman->position(), Widget, PacmanPix, pacman->pix()); + + if (gameState.testBit(Player) && + rect.intersects(pix->rect(board->position(monsterhome, 0), i18n("PLAYER ONE")))) + pix->draw(board->position(monsterhome, 0), Widget, i18n("PLAYER ONE"), CYAN); + + if (gameState.testBit(Ready) && + rect.intersects(pix->rect(board->position(fruithome), i18n("READY!")))) + pix->draw(board->position(fruithome), Widget, i18n("READY!"), YELLOW); + + if (gameState.testBit(Paused) && + rect.intersects(pix->rect((BoardWidth*BoardHeight)/2-BoardWidth, i18n("PAUSED")))) + pix->draw((BoardWidth*BoardHeight)/2-BoardWidth, Widget, i18n("PAUSED"), RED, BLACK); +} + +void Referee::timerEvent( QTimerEvent *e ) +{ + if (gameState.testBit(HallOfFame)) + return; + + QRect lastRect; + int lastPix; + bool moved = FALSE; + int eated = 0; + + if (e->timerId() == energizerTimer) { + for (int e = 0; e < board->energizers(); e++) { + lastRect = pix->rect(energizers->at(e)->position(), EnergizerPix); + lastPix = energizers->at(e)->pix(); + if (energizers->at(e)->move()) { + moved = TRUE; + *energizerRect->at(e) = pix->rect(energizers->at(e)->position(), EnergizerPix); + if (lastPix == energizers->at(e)->pix() && + lastRect == pix->rect(energizers->at(e)->position(), EnergizerPix)) + energizerRect->at(e)->setRect(0, 0, 0, 0); + else + *energizerRect->at(e) = pix->rect(*energizerRect->at(e), lastRect); + } + } + + for (int e = 0; e < board->energizers(); e++) + if (!energizerRect->at(e)->isNull()) + repaint(*energizerRect->at(e), FALSE); + + return; + } + + timerCount++; + + lastRect = pix->rect(pacman->position(), PacmanPix); + lastPix = pacman->pix(); + + if (moved = pacman->move()) { // pacman really moved + pacmanRect = pix->rect(pacman->position(), PacmanPix); + if (lastPix == pacman->pix() && + lastRect == pix->rect(pacman->position(), PacmanPix)) + pacmanRect.setRect(0, 0, 0, 0); // nothing to do, because the pixmap + else // and the position isn't changed. + pacmanRect = pix->rect(pacmanRect, lastRect); + } else + pacmanRect.setRect(0, 0, 0, 0); + + int pos = pacman->position(); + + if (moved && board->isMonster(pos) && !gameState.testBit(Dying)) { + for (Monster *m = monsters->first(); m != 0; m = monsters->next()) + if (m && m->position() == pos) { + if (m->state() == harmless && !gameState.testBit(Dying)) { + m->setREM(remTicks[level]); + m->setDirection(X); // prevent movement before eaten() + eated++; + if (gameState.testBit(Introducing)) + m->setPosition(OUT); + } + if (m->state() == dangerous && !gameState.testBit(Dying)) + killed(); + } + } + + if (moved && !gameState.testBit(Dying)) { + if (board->isPoint(pos)) { + board->reset(pos, Point); + score(pointScore); + pix->erase(pos, PointPix); + } + if (board->isEnergizer(pos)) { + for (int e = 0; e < board->energizers();e++) { + if (energizers->at(e)->position() == pos) { + energizers->at(e)->setOff(); + energizers->remove(e); + energizerRect->remove(e); + e = board->energizers(); + } + } + board->reset(pos, energizer); + score(energizerScore); + monstersEaten = 0; + for (Monster *m = monsters->first(); m != 0; m = monsters->next()) + if (m && m->state() != rem) { + m->setHarmless(harmlessTicks[level], harmlessDurTicks[level], + harmlessWarnTicks[level]); + if (gameState.testBit(Introducing)) + m->setDirection(board->turn(m->direction())); + } + } + if (pos == fruit->position() && fruit->state() == active) { + fruit->setEaten(fruitScoreDurTicks[level]); + initFruit(FALSE); + score(fruitScore[fruit->pix()]); + } + } + + if (!gameState.testBit(Introducing)) { + if (fruit->state() != active && fruit->pix() >= 0) + lastRect = pix->rect(fruit->position(), FruitScorePix, fruit->pix()); + else + lastRect = pix->rect(fruit->position(), FruitPix, fruit->pix()); + + lastPix = fruit->pix(); + if (fruit->move()) { + if (pos == fruit->position() && fruit->state() == active) { + fruit->setEaten(fruitScoreDurTicks[level]); + initFruit(FALSE); + score(fruitScore[fruit->pix()]); + } + if (fruit->state() != active && fruit->pix() >= 0) + fruitRect = pix->rect(fruit->position(), FruitScorePix, fruit->pix()); + else + fruitRect = pix->rect(fruit->position(), FruitPix, fruit->pix()); + if (lastPix == fruit->pix() && lastRect == fruitRect) + fruitRect.setRect(0, 0, 0, 0); + else + fruitRect = pix->rect(fruitRect, lastRect); + } else + fruitRect.setRect(0, 0, 0, 0); + } else + fruitRect.setRect(0, 0, 0, 0); + + int lastBodyPix; + int lastEyesPix; + + for (Monster *m = monsters->first(); m != 0; m = monsters->next()) + if (m) { + lastRect = pix->rect(m->position(), MonsterPix); + lastBodyPix = m->body(); + lastEyesPix = m->eyes(); + if (m->move()) { + moved = TRUE; + *monsterRect->at(m->id()) = pix->rect(m->position(), MonsterPix); + if (lastBodyPix == m->body() && lastEyesPix == m->eyes() && + lastRect == pix->rect(m->position(), MonsterPix)) + monsterRect->at(m->id())->setRect(0, 0, 0, 0); + else + *monsterRect->at(m->id()) = pix->rect(*monsterRect->at(m->id()), lastRect); + if (m->position() == pos && !gameState.testBit(Dying)) { + if (m->state() == harmless && !gameState.testBit(Dying)) { + m->setREM(remTicks[level]); + eated++; + if (gameState.testBit(Introducing)) { + m->setPosition(OUT); + m->setDirection(X); + } + } + if (m->state() == dangerous && !gameState.testBit(Dying)) + killed(); + } + } else + monsterRect->at(m->id())->setRect(0, 0, 0, 0); + } + + for (int m = 0; m < board->monsters(); m++) + if (pacmanRect.intersects(*monsterRect->at(m))) { + pacmanRect = pix->rect(pacmanRect, *monsterRect->at(m)); + monsterRect->at(m)->setRect(0, 0, 0, 0); + } else + for (int im = m+1; im < board->monsters(); im++) + if (monsterRect->at(m)->intersects(*monsterRect->at(im))) { + *monsterRect->at(m) = pix->rect(*monsterRect->at(m), *monsterRect->at(im)); + monsterRect->at(im)->setRect(0, 0, 0, 0); + } + + if (!pacmanRect.isNull()) + repaint(pacmanRect, FALSE); + + if (!fruitRect.isNull()) + repaint(fruitRect, FALSE); + + for (int m = 0; m < board->monsters(); m++) + if (!monsterRect->at(m)->isNull()) + repaint(*monsterRect->at(m), FALSE); + + if (board->points() == 0 && !gameState.testBit(Dying)) + levelUp(); + + if (eated > 0 && !gameState.testBit(Dying)) { + timerCount = eated; + eaten(); + } + + if (gameState.testBit(Introducing) && moved) + introPlay(); +} + +void Referee::repaintFigures() +{ + pacmanRect = pix->rect(pacman->position(), PacmanPix); + + for (int e = 0; e < board->energizers(); e++) { + *energizerRect->at(e) = pix->rect(board->position(energizer, e), EnergizerPix); + + if (pacmanRect.intersects(*energizerRect->at(e))) { + pacmanRect = pix->rect(pacmanRect, *energizerRect->at(e)); + energizerRect->at(e)->setRect(0, 0, 0, 0); + } else + for (int ie = e+1; ie < board->energizers(); ie++) + if (energizerRect->at(e)->intersects(*energizerRect->at(ie))) { + *energizerRect->at(e) = pix->rect(*energizerRect->at(e), *energizerRect->at(ie)); + energizerRect->at(ie)->setRect(0, 0, 0, 0); + } + } + + if (fruit->pix() != -1 && fruit->state() != active) + fruitRect = pix->rect(fruit->position(), FruitScorePix, fruit->pix()); + else + fruitRect = pix->rect(fruit->position(), FruitPix, fruit->pix()); + + if (pacmanRect.intersects(fruitRect)) { + pacmanRect = pix->rect(pacmanRect, fruitRect); + fruitRect.setRect(0, 0, 0, 0); + } + + for (int m = 0; m < board->monsters(); m++) { + *monsterRect->at(m) = pix->rect(board->position(monster, m), MonsterPix); + + if (pacmanRect.intersects(*monsterRect->at(m))) { + pacmanRect = pix->rect(pacmanRect, *monsterRect->at(m)); + monsterRect->at(m)->setRect(0, 0, 0, 0); + } else + for (int im = m+1; im < board->monsters(); im++) + if (monsterRect->at(m)->intersects(*monsterRect->at(im))) { + *monsterRect->at(m) = pix->rect(*monsterRect->at(m), *monsterRect->at(im)); + monsterRect->at(im)->setRect(0, 0, 0, 0); + } + } + + if (!pacmanRect.isNull()) + repaint(pacmanRect, FALSE); + + if (!fruitRect.isNull()) + repaint(fruitRect, FALSE); + + for (int m = 0; m < board->monsters(); m++) + if (!monsterRect->at(m)->isNull()) + repaint(*monsterRect->at(m), FALSE); + + for (int e = 0; e < board->energizers(); e++) + if (!energizerRect->at(e)->isNull()) + repaint(*energizerRect->at(e), FALSE); + +} + +void Referee::initKeys() +{ + APP_CONFIG_BEGIN( cfg ); + QString up("Up"); + up = cfg->readEntry("upKey", (const char*) up); + UpKey = KAccel::stringToKey(up); + + QString down("Down"); + down = cfg->readEntry("downKey", (const char*) down); + DownKey = KAccel::stringToKey(down); + + QString left("Left"); + left = cfg->readEntry("leftKey", (const char*) left); + LeftKey = KAccel::stringToKey(left); + + QString right("Right"); + right = cfg->readEntry("rightKey", (const char*) right); + RightKey = KAccel::stringToKey(right); + APP_CONFIG_END( cfg ); +} + +void Referee::fillArray(QArray<int> &array, QString values, int max) +{ + if (max < 0) + max = values.contains(',')+1; + + array.resize(max); + int last = 0; + bool ok; + QString value; + + for (uint i = 0; i < array.size(); i++) { + if (values.find(',') < 0 && values.length() > 0) { + value = values; + values = ""; + } + if (values.find(',') >= 0) { + value = values.left(values.find(',')); + values.remove(0,values.find(',')+1); + } + array[i] = value.toInt(&ok); + if (ok) + last = array[i]; + else + array[i] = last; + } +} + +void Referee::fillStrList(QStrList &list, QString values, int max) +{ + if (!list.isEmpty()) + list.clear(); + + QString last = ""; + QString value; + + for (uint i = 0; i < (uint) max; i++) { + if (values.find(',') < 0 && values.length() > 0) { + value = values; + values = ""; + } + if (values.find(',') >= 0) { + value = values.left(values.find(',')); + values.remove(0,values.find(',')+1); + } + if (!value.isEmpty()) + last = value; + + list.append(last); + } +} + +void Referee::fillMapName() +{ + QStrList list = mapName; + + if (!mapName.isEmpty()) + mapName.clear(); + + QString map; + + QFileInfo fileInfo; + + for (uint i = 0; i < list.count(); i++) { + map = list.at(i); + + if (map.left(1) != "/" && map.left(1) != "~") + map = FIND_APP_DATA( mapDirectory+map ); + + fileInfo.setFile(map); + if (!fileInfo.isReadable()) + map = ""; + + mapName.append(map); + } +} + +void Referee::confLevels(bool defGroup) +{ + APP_CONFIG_BEGIN( cfg ); + if (defGroup || cfg->hasKey("Levels")) + maxLevel = cfg->readNumEntry("Levels", 13); + APP_CONFIG_END( cfg ); +} + +void Referee::confMisc(bool defGroup) +{ + APP_CONFIG_BEGIN( cfg ); + if (defGroup || cfg->hasKey("PixmapDirectory")) { + pixmapDirectory = cfg->readEntry("PixmapDirectory"); + + if (pixmapDirectory.left(1) != "/" && pixmapDirectory.left(1) != "~") + pixmapDirectory.insert(0, "pics/"); + if (pixmapDirectory.right(1) != "/") + pixmapDirectory.append("/"); + } + + if (defGroup || cfg->hasKey("MapDirectory")) { + mapDirectory = cfg->readEntry("MapDirectory"); + + if (mapDirectory.left(1) != "/" && mapDirectory.left(1) != "~") + mapDirectory.insert(0, "maps/"); + if (mapDirectory.right(1) != "/") + mapDirectory.append("/"); + } + + if (defGroup || cfg->hasKey("MapName")) + fillStrList(mapName, cfg->readEntry("MapName", "map"), maxLevel+1); + + if (defGroup || cfg->hasKey("MonsterIQ")) + fillArray(monsterIQ, cfg->readEntry("MonsterIQ", "0,170,180,170,180,170,180"), maxLevel+1); + if (defGroup || cfg->hasKey("FruitIQ")) + fillArray(fruitIQ, cfg->readEntry("FruitIQ", "0,170,180,170,180,170,180"), maxLevel+1); + if (defGroup || cfg->hasKey("FruitIndex")) + fillArray(fruitIndex, cfg->readEntry("FruitIndex", "0"), maxLevel+1); + APP_CONFIG_END( cfg ); +} + +void Referee::confTiming(bool defGroup) +{ + APP_CONFIG_BEGIN( cfg ); + if (defGroup || cfg->hasKey("SpeedMS")) + fillArray(speed, cfg->readEntry("SpeedMS", "20"), maxLevel+1); + if (defGroup || cfg->hasKey("PacmanTicks")) + fillArray(pacmanTicks,cfg->readEntry("PacmanTicks", "3"), maxLevel+1); + if (defGroup || cfg->hasKey("RemTicks")) + fillArray(remTicks, cfg->readEntry("RemTicks", "1"), maxLevel+1); + if (defGroup || cfg->hasKey("DangerousTicks")) + fillArray(dangerousTicks, cfg->readEntry("DangerousTicks", "3"), maxLevel+1); + if (defGroup || cfg->hasKey("HarmlessTicks")) + fillArray(harmlessTicks, cfg->readEntry("HarmlessTicks", "7,6,,5,,4"), maxLevel+1); + if (defGroup || cfg->hasKey("HarmlessDurationTicks")) + fillArray(harmlessDurTicks, cfg->readEntry("HarmlessDurationTicks", "375,,,300,,250,200,150"), maxLevel+1); + if (defGroup || cfg->hasKey("HarmlessWarningTicks")) + fillArray(harmlessWarnTicks, cfg->readEntry("HarmlessWarningTicks", "135"), maxLevel+1); + if (defGroup || cfg->hasKey("ArrestTicks")) + fillArray(arrestTicks, cfg->readEntry("ArrestTicks", "6"), maxLevel+1); + if (defGroup || cfg->hasKey("ArrestDurationTicks")) + fillArray(arrestDurTicks, cfg->readEntry("ArrestDurationTicks", "200,,,150"), maxLevel+1); + if (defGroup || cfg->hasKey("FruitTicks")) + fillArray(fruitTicks, cfg->readEntry("FruitTicks", "7,6,,5,,4"), maxLevel+1); + if (defGroup || cfg->hasKey("FruitAppearsTicks")) + fillArray(fruitAppearsTicks, cfg->readEntry("FruitAppearsTicks", "1000,,1500,2000,2500,3000,3500,4000"), maxLevel+1); + if (defGroup || cfg->hasKey("FruitDurationTicks")) + fillArray(fruitDurTicks, cfg->readEntry("FruitDurationTicks", "500,,,400,350,300,,250,200,150"), maxLevel+1); + if (defGroup || cfg->hasKey("FruitScoreDurationTicks")) + fillArray(fruitScoreDurTicks, cfg->readEntry("FruitScoreDurationTicks", "150"), maxLevel+1); + + if (defGroup || cfg->hasKey("MonsterScoreDurationMS")) + monsterScoreDurMS = cfg->readNumEntry("MonsterScoreDurationMS", 1000); + if (defGroup || cfg->hasKey("PlayerDurationMS")) + playerDurMS = cfg->readNumEntry("PlayerDurationMS", 3000); + if (defGroup || cfg->hasKey("ReadyDurationMS")) + readyDurMS = cfg->readNumEntry("ReadyDurationMS", 2000); + if (defGroup || cfg->hasKey("GameOverDurationMS")) + gameOverDurMS = cfg->readNumEntry("GameOverDurationMS", 3000); + if (defGroup || cfg->hasKey("AfterPauseMS")) + afterPauseMS = cfg->readNumEntry("AfterPauseMS", 1000); + if (defGroup || cfg->hasKey("DyingPreAnimationMS")) + dyingPreAnimationMS = cfg->readNumEntry("DyingPreAnimationMS", 1000); + if (defGroup || cfg->hasKey("DyingAnimationMS")) + dyingAnimationMS = cfg->readNumEntry("DyingAnimationMS", 100); + if (defGroup || cfg->hasKey("DyingPostAnimationMS")) + dyingPostAnimationMS = cfg->readNumEntry("DyingPostAnimationMS", 500); + if (defGroup || cfg->hasKey("IntroAnimationMS")) + introAnimationMS = cfg->readNumEntry("IntroAnimationMS", 800); + if (defGroup || cfg->hasKey("IntroPostAnimationMS")) + introPostAnimationMS = cfg->readNumEntry("IntroPostAnimationMS", 1000); + if (defGroup || cfg->hasKey("LevelUpPreAnimationMS")) + levelUpPreAnimationMS = cfg->readNumEntry("LevelUpPreAnimationMS", 2000); + if (defGroup || cfg->hasKey("LevelUpAnimationMS")) + levelUpAnimationMS = cfg->readNumEntry("LevelUpAnimationMS", 2000); + if (defGroup || cfg->hasKey("EnergizerAnimationMS")) + energizerAnimationMS = cfg->readNumEntry("EnergizerAnimationMS", 200); + APP_CONFIG_END( cfg ); +} + +void Referee::confScoring(bool defGroup) +{ + APP_CONFIG_BEGIN( cfg ); + if (defGroup || cfg->hasKey("PointScore")) + pointScore = cfg->readNumEntry("PointScore", 10); + if (defGroup || cfg->hasKey("EnergizerScore")) + energizerScore = cfg->readNumEntry("EnergizerScore", 50); + if (defGroup || cfg->hasKey("FruitScore")) + fillArray(fruitScore, cfg->readEntry("FruitScore", "100,300,500,,700,,1000,,2000,,3000,,5000"), maxLevel+1); + if (defGroup || cfg->hasKey("MonsterScore")) + fillArray(monsterScore, cfg->readEntry("MonsterScore", "200,400,800,1600"), 4); + if (defGroup || cfg->hasKey("ExtraLifeScore")) + fillArray(extraLifeScore, cfg->readEntry("ExtraLifeScore", "10000"), -1); + APP_CONFIG_END( cfg ); +} + +void Referee::confScheme() +{ + APP_CONFIG_BEGIN( cfg ); + SAVE_CONFIG_GROUP( cfg, oldgroup ); + QString newgroup; + + // if not set, read mode and scheme from the configfile + if (mode == -1 && scheme == -1) { + scheme = cfg->readNumEntry("Scheme", -1); + mode = cfg->readNumEntry("Mode", -1); + + // if mode is not set in the defGroup-group, lookup the scheme group + if (scheme != -1 || mode == -1) { + newgroup.sprintf("Scheme %d", scheme); + cfg->setGroup(newgroup); + + mode = cfg->readNumEntry("Mode", -1); + RESTORE_CONFIG_GROUP( cfg, oldgroup ); + } + } + + confLevels(); + + if (mode != -1) { + newgroup.sprintf("Mode %d", mode); + cfg->setGroup(newgroup); + + confLevels(FALSE); + } + + if (scheme != -1) { + newgroup.sprintf("Scheme %d", scheme); + cfg->setGroup(newgroup); + + confLevels(FALSE); + } + + RESTORE_CONFIG_GROUP( cfg, oldgroup ); + + confMisc(); + confTiming(); + confScoring(); + + if (mode != -1) { + newgroup.sprintf("Mode %d", mode); + cfg->setGroup(newgroup); + + confMisc(FALSE); + confTiming(FALSE); + confScoring(FALSE); + } + + if (scheme != -1) { + newgroup.sprintf("Scheme %d", scheme); + cfg->setGroup(newgroup); + + confMisc(FALSE); + confTiming(FALSE); + confScoring(FALSE); + } + + fillMapName(); + + RESTORE_CONFIG_GROUP( cfg, oldgroup ); + APP_CONFIG_END( cfg ); +} + +void Referee::setScheme(int Scheme, int Mode, Bitfont *font) +{ + mode = Mode; + scheme = Scheme; + + confScheme(); + + pix->setScheme(scheme, mode, font); + + pacman->setMaxPixmaps(pix->maxPixmaps(PacmanPix)); + fruit->setMaxPixmaps(pix->maxPixmaps(FruitPix)); + + for (Monster *m = monsters->first(); m != 0; m = monsters->next()) + if (m) + m->setMaxPixmaps(pix->maxPixmaps(MonsterPix), pix->maxPixmaps(EyesPix)); + + for (Energizer *e = energizers->first(); e != 0; e = energizers->next()) + if (e) + e->setMaxPixmaps(pix->maxPixmaps(EnergizerPix)); + + if (gameState.testBit(Introducing)) + for (int i = 0; i < (gameState.testBit(Init) ? timerCount : 15); i++) + introPaint(i); + + setFixedSize(pix->levelPix().size()); + repaint(); +} + +void Referee::keyPressEvent( QKeyEvent *k ) +{ + uint key = k->key(); +#ifdef QWS + // "OK" => new game + if ( key == Key_F33 || key == Key_F2 || key == Key_Enter ) + play(); + else if ( !gameState.testBit(Playing) && key == Key_Space ) + play(); + // "Space" => pause + //else if ( key == Key_Space || key == Key_F3 ) + // pause(); + // "Menu" => hall of fame + //else if ( key == Key_F11 || key == Key_F4 ) + // toggleHallOfFame(); +#endif + + if (gameState.testBit(Paused) || gameState.testBit(HallOfFame) || + gameState.testBit(Demonstration) || gameState.testBit(Dying) || + gameState.testBit(Ready) || gameState.testBit(LevelDone) || + !gameState.testBit(Playing)) + return; + + if (key == UpKey) + pacman->setDirection(N); + else if (key == DownKey) + pacman->setDirection(S); + else if (key == RightKey) + pacman->setDirection(E); + else if (key == LeftKey) + pacman->setDirection(W); + +#ifdef CHEATS + else if (key == Key_L) { printf("levelUp()\n"); levelUp(); } + else if (key == Key_F) { printf("fruit->move(TRUE)\n"); fruit->move(TRUE); repaint(FALSE); } + else if (key == Key_E) { printf("setLifes(++lifes)\n"); emit setLifes(++lifes); } +#endif + + else { + k->ignore(); + return; + } + k->accept(); +} + +void Referee::score(int p) +{ + if (!gameState.testBit(Playing)) + return; + + if ((points += p) < 0) + points = 0; + + emit setPoints(points); + + if (points >= nextExtraLifeScore) { + emit setLifes(++lifes); + if (extraLifeScoreIndex < (int) extraLifeScore.size()-1) + extraLifeScoreIndex++; + if (extraLifeScore[extraLifeScoreIndex] < 0) + nextExtraLifeScore = extraLifeScore[extraLifeScoreIndex] * -1; + else + nextExtraLifeScore += extraLifeScore[extraLifeScoreIndex]; + } +} + +void Referee::eaten() +{ + if (gameState.testBit(Ready)) + return; + + stop(); + + if (monstersEaten < 4) + monstersEaten++; + + gameState.setBit(Scoring); + score(monsterScore[monstersEaten-1]); + + repaint(pix->rect(pix->rect(pacman->position(), MonsterPix), + pix->rect(pacman->position(), MonsterScorePix, monstersEaten-1))); + + if (--timerCount > 0) + QTimer::singleShot( monsterScoreDurMS, this, SLOT(eaten())); + else { + for (Monster *m = monsters->first(); m != 0; m = monsters->next()) + if (m && m->direction() == X && !gameState.testBit(Introducing)) + m->setDirection(N); + if (monstersEaten != 4 || !gameState.testBit(Introducing)) + QTimer::singleShot( monsterScoreDurMS, this, SLOT(start())); + } +} + +void Referee::toggleHallOfFame() +{ + gameState.toggleBit(HallOfFame); +} + +void Referee::hallOfFame() +{ + if (gameState.testBit(HallOfFame)) // If the HallOfFame is switched on manually, toggle the + toggleHallOfFame(); // bit twice. + + emit setLevel(0); // Clear status display for hall of fame + emit setScore(level, 0); + emit forcedHallOfFame(TRUE); +} + +void Referee::pause() +{ + static int pausedTimer = 0; + + if (!gameState.testBit(Paused)) { + pausedTimer = gameTimer; + stop(); + stopEnergizer(); + gameState.setBit(Paused); + repaint(pix->rect((BoardWidth*BoardHeight)/2-BoardWidth, i18n("PAUSED")), FALSE); + } else { + gameState.clearBit(Paused); + repaint(pix->rect((BoardWidth*BoardHeight)/2-BoardWidth, i18n("PAUSED")), FALSE); + if (pausedTimer) { + pausedTimer = 0; + start(); + } + } + emit togglePaused(); +} + +void Referee::intro() +{ + stop(); + stopEnergizer(); + bool paused = gameState.testBit(Paused); + + gameState.fill(FALSE); + gameState.setBit(Introducing); + gameState.setBit(Init); + + if (paused) + gameState.setBit(Paused); + + level = 0; + emit setLevel(level); + + board->init(Intro); + pix->setLevel(level); + + initPacman(); + initFruit(); + initMonsters(); + initEnergizers(); + + repaint(); + + monstersEaten = 0; + timerCount = 0; + introPlay(); +} + +void Referee::introMonster(int id) +{ + Monster *m = new Monster(board, id); + + m->setPosition((10+id*6)*BoardWidth+10); + m->setDirection(E); + m->setDangerous(dangerousTicks[level], monsterIQ[level]); + m->setMaxPixmaps(pix->maxPixmaps(MonsterPix), pix->maxPixmaps(EyesPix)); + + if (m->body() != -1) + pix->draw(m->position(), RoomPix, MonsterPix, m->body()); + if (m->eyes() != -1) + pix->draw(m->position(), RoomPix, EyesPix, m->eyes()); + + repaint(pix->rect(m->position(), MonsterPix), FALSE); + m->setPosition(OUT); +} + +void Referee::introPaint(int t) +{ + QString pts; + + switch (t) { + case 0 : repaint(pix->draw(16, 6, RoomPix, i18n("CHARACTER"), WHITE, QColor(), AlignLeft), FALSE); + repaint(pix->draw(36, 6, RoomPix, i18n("/"), WHITE, QColor(), AlignLeft), FALSE); + repaint(pix->draw(40, 6, RoomPix, i18n("NICKNAME"), WHITE, QColor(), AlignLeft), FALSE); + break; + case 1 : introMonster(0); + break; + case 2 : repaint(pix->draw(16, 10, RoomPix, i18n("-SHADOW"), RED, QColor(), AlignLeft), FALSE); + break; + case 3 : repaint(pix->draw(38, 10, RoomPix, i18n("\"BLINKY\""), RED, QColor(), AlignLeft), FALSE); + break; + case 4 : introMonster(1); + break; + case 5 : repaint(pix->draw(16, 16, RoomPix, i18n("-SPEEDY"), PINK, QColor(), AlignLeft), FALSE); + break; + case 6 : repaint(pix->draw(38, 16, RoomPix, i18n("\"PINKY\""), PINK, QColor(), AlignLeft), FALSE); + break; + case 7 : introMonster(2); + break; + case 8 : repaint(pix->draw(16, 22, RoomPix, i18n("-BASHFUL"), CYAN, QColor(), AlignLeft), FALSE); + break; + case 9 : repaint(pix->draw(38, 22, RoomPix, i18n("\"INKY\""), CYAN, QColor(), AlignLeft), FALSE); + break; + case 10 : introMonster(3); + break; + case 11 : repaint(pix->draw(16, 28, RoomPix, i18n("-POKEY"), ORANGE, QColor(), AlignLeft), FALSE); + break; + case 12 : repaint(pix->draw(38, 28, RoomPix, i18n("\"CLYDE\""), ORANGE, QColor(), AlignLeft), FALSE); + break; + case 13 : pts.sprintf("%d", pointScore); + repaint(pix->draw(28, 44, RoomPix, pts.data(), WHITE, QColor(), AlignRight), FALSE); + repaint(pix->draw(31, 44, RoomPix, "\x1C\x1D\x1E", WHITE, QColor(), AlignLeft), FALSE); + pts.sprintf("%d", energizerScore); + repaint(pix->draw(28, 48, RoomPix, pts.data(), WHITE, QColor(), AlignRight), FALSE); + repaint(pix->draw(31, 48, RoomPix, "\x1C\x1D\x1E", WHITE, QColor(), AlignLeft), FALSE); + break; + case 14 : // "@ 1980 MIDWAY MFG.CO." +#if defined( KDE2_PORT ) + repaint(pix->draw(30, 58, RoomPix, "© 1998-2002 J.THÖNNISSEN", PINK), FALSE); +#elif defined( QPE_PORT ) + repaint(pix->draw(30, 55, RoomPix, "© 1998-2002 J.THÖNNISSEN", PINK), FALSE); + repaint(pix->draw(29, 60, RoomPix, "Qtopia port: Catalin CLIMOV", GREEN), FALSE); +#endif + break; + } +} + +void Referee::introPlay() +{ + if (!gameState.testBit(Introducing) || gameState.testBit(Ready)) + return; + if (gameState.testBit(Paused) || gameState.testBit(HallOfFame)) { + QTimer::singleShot(afterPauseMS, this, SLOT(introPlay())); + return; + } + + if (!gameState.testBit(Init)) { + if (monstersEaten == 4) { + stop(); + QTimer::singleShot(introPostAnimationMS, this, SLOT(demo())); + } + if (pacman->direction() == W) { + int id = -1; + if (pacman->position() == 37*BoardWidth-6) + id = 0; + else + if (board->isMonster(37*BoardWidth-6)) + for (Monster *m = monsters->first(); m != 0; m = monsters->next()) + if (m && m->position() == 37*BoardWidth-6) { + id = m->id(); + id++; + break; + } + + if (id >= 0 && id <= 4) + for (Monster *m = monsters->first(); m != 0; m = monsters->next()) + if (m && m->id() == id && m->position() == OUT) { + m->setPosition(37*BoardWidth-1); + m->setDirection(W); + m->setDangerous(dangerousTicks[level], monsterIQ[level]); + board->set(37*BoardWidth-1, monsterhome, id); + repaint(pix->rect(m->position(), MonsterPix)); + break; + } + } + return; + } + + if (timerCount < 15) + introPaint(timerCount); + + switch (timerCount) { + case 13 : board->set(44*BoardWidth+22, Point); + pix->drawPoint(44*BoardWidth+22); + repaint(pix->rect(44*BoardWidth+22, PointPix), FALSE); + energizers->at(0)->setPosition(48*BoardWidth+22); + energizers->at(0)->setOn(); + repaint(pix->rect(48*BoardWidth+22, EnergizerPix), FALSE); + break; + case 14 : energizers->at(1)->setPosition(36*BoardWidth+10); + energizers->at(1)->setOn(); + repaint(pix->rect(36*BoardWidth+10, EnergizerPix), FALSE); + for (int pos = 8; pos < BoardWidth; pos++) { + board->set(34*BoardWidth+pos, out); + board->set(38*BoardWidth+pos, out); + } + board->set(36*BoardWidth+8, out); + break; + case 15 : gameState.clearBit(Init); + initPacman(); + pacman->setDemo(TRUE); + pacman->setPosition(37*BoardWidth-1); + repaintFigures(); + start(); + return; + } + + if (timerCount++ < 15) + QTimer::singleShot(introAnimationMS, this, SLOT(introPlay())); +} + +void Referee::demo() +{ + if (gameState.testBit(Ready)) + return; + + if (gameState.testBit(Paused) || gameState.testBit(HallOfFame)) { + QTimer::singleShot(afterPauseMS, this, SLOT(demo())); + return; + } + + stop(); + stopEnergizer(); + + gameState.fill(FALSE); + gameState.setBit(Init); + gameState.setBit(Demonstration); + + level = 0; + emit setLevel(level); + + board->init(Demo, mapName.at(0)); + pix->setLevel(level); + + initPacman(); + initFruit(); + initMonsters(); + initEnergizers(); + + gameState.clearBit(Init); + + repaint(); + + timerCount = 0; + QTimer::singleShot(playerDurMS, this, SLOT(start())); +} + +void Referee::play() +{ + stop(); + stopEnergizer(); + + gameState.fill(FALSE); + gameState.setBit(Init); + gameState.setBit(Playing); + gameState.setBit(Player); + gameState.setBit(Ready); + + lifes = 3; + level = 1; + points = 0; + + extraLifeScoreIndex = 0; + nextExtraLifeScore = extraLifeScore[extraLifeScoreIndex]; + if (nextExtraLifeScore < 0) + nextExtraLifeScore *= -1; + + board->init(Level, mapName.at(level)); + pix->setLevel(level); + + initPacman(); + initFruit(); + initMonsters(); + initEnergizers(); + + repaint(); + emit toggleNew(); + emit setLifes(lifes); + emit setLevel(level); + emit setPoints(points); + + repaint(pix->rect(board->position(monsterhome, 0), i18n("PLAYER ONE")), FALSE); + repaint(pix->rect(board->position(fruithome), i18n("READY!")), FALSE); + + timerCount = 0; + QTimer::singleShot(playerDurMS, this, SLOT(ready())); +} + +void Referee::ready() +{ + if (gameState.testBit(Paused) || gameState.testBit(HallOfFame)) { + QTimer::singleShot(afterPauseMS, this, SLOT(ready())); + return; + } + + if (gameState.testBit(Player)) { + emit setLifes(--lifes); + gameState.clearBit(Player); + gameState.clearBit(Init); + repaint(pix->rect(board->position(monsterhome, 0), i18n("PLAYER ONE")), FALSE); + repaintFigures(); + QTimer::singleShot(playerDurMS, this, SLOT(ready())); + return; + } + + if (gameState.testBit(Ready)) { + gameState.clearBit(Ready); + repaint(pix->rect(board->position(fruithome), i18n("READY!")), FALSE); + start(); + } else { + gameState.setBit(Ready); + gameState.clearBit(Init); + repaint(pix->rect(board->position(fruithome), i18n("READY!")), FALSE); + QTimer::singleShot(readyDurMS, this, SLOT(ready())); + } +} + + +void Referee::levelUp() +{ + stop(); + stopEnergizer(); + + gameState.setBit(LevelDone); + pacman->setPosition(pacman->position()); // set mouthPosition to "0" + repaint(pix->rect(pacman->position(), PacmanPix)); + + timerCount = 0; + QTimer::singleShot(levelUpPreAnimationMS, this, SLOT(levelUpPlay())); +} + +void Referee::levelUpPlay() +{ + if (gameState.testBit(Ready)) + return; + + if (gameState.testBit(Paused) || gameState.testBit(HallOfFame)) { + QTimer::singleShot(afterPauseMS, this, SLOT(levelUpPlay())); + return; + } + + switch (timerCount) { + case 0 : gameState.setBit(Init); + setOnEnergizers(); + repaintFigures(); + break; + case 1 : gameState.clearBit(LevelDone); + repaint(pix->rect(pacman->position(), PacmanPix)); + break; + } + + if (timerCount++ < 2) { + QTimer::singleShot(levelUpAnimationMS, this, SLOT(levelUpPlay())); + return; + } + + gameState.clearBit(Init); + + if (gameState.testBit(Demonstration)) { + hallOfFame(); + return; + } + + if (level < maxLevel) + level++; + + board->init(Level, mapName.at(level)); + pix->setLevel(level); + + initPacman(); + initFruit(); + initMonsters(); + initEnergizers(); + + repaint(); + emit setLevel(level); + + ready(); +} + +void Referee::start() +{ + if (gameState.testBit(Ready)) + return; + + if (gameState.testBit(Paused) || gameState.testBit(HallOfFame)) { + QTimer::singleShot(afterPauseMS, this, SLOT(start())); + return; + } + + if (gameState.testBit(Scoring)) { + gameState.clearBit(Scoring); + repaint(pix->rect(pix->rect(pacman->position(), MonsterPix), + pix->rect(pacman->position(), MonsterScorePix, monstersEaten-1))); + } + + if (!gameTimer) + gameTimer = startTimer( speed [level] ); + + if (!energizerTimer) + energizerTimer = startTimer( energizerAnimationMS ); +} + +void Referee::start(int t) +{ + gameTimer = startTimer(t); +} + +void Referee::stop() +{ + if (gameTimer) { + killTimer (gameTimer); + gameTimer = 0; + } +} + +void Referee::stopEnergizer() +{ + if (energizerTimer) { + killTimer (energizerTimer); + energizerTimer = 0; + } +} + +void Referee::killed() +{ + if (gameState.testBit(Ready)) + return; + + if (!gameState.testBit(Dying)) { + gameState.setBit(Dying); + + pacman->setDirection(X, TRUE); + for (Monster *m = monsters->first(); m != 0; m = monsters->next()) + if (m) + m->setDirection(X); + QTimer::singleShot(dyingPreAnimationMS, this, SLOT(killed())); + } else { + stop(); + if (gameState.testBit(Paused) || gameState.testBit(HallOfFame)) { + QTimer::singleShot(afterPauseMS, this, SLOT(killed())); + return; + } + + gameState.setBit(Init); + + repaintFigures(); + + timerCount = 0; + killedPlay(); + } +} + +void Referee::killedPlay() +{ + if (!gameState.testBit(Dying) || gameState.testBit(Ready)) + return; + if (gameState.testBit(Paused) || gameState.testBit(HallOfFame)) { + QTimer::singleShot(afterPauseMS, this, SLOT(killedPlay())); + return; + } + + if (timerCount <= pix->maxPixmaps(DyingPix)) { + repaint(pix->rect(pacman->position(), PacmanPix), FALSE); + if (timerCount >= pix->maxPixmaps(DyingPix)-1 || timerCount == 0) + QTimer::singleShot(dyingPostAnimationMS, this, SLOT(killedPlay())); + else + QTimer::singleShot(dyingAnimationMS, this, SLOT(killedPlay())); + timerCount++; + } else { + gameState.clearBit(Dying); + stopEnergizer(); + if (lifes == 0) { + gameState.setBit(GameOver); + gameState.clearBit(Playing); + for (int e = 0; e < board->energizers(); e++) { + energizers->at(e)->setOff(); + repaint(pix->rect(board->position(energizer, e), EnergizerPix), FALSE); + } + repaint(pix->rect(board->position(fruithome), i18n("GAME OVER")), FALSE); + QTimer::singleShot(gameOverDurMS, this, SLOT(hallOfFame())); + } else { + gameState.clearBit(Init); + initPacman(); + initFruit(); + initMonsters(); + initEnergizers(); + emit setLifes(--lifes); + repaintFigures(); + ready(); + } + } +} + +void Referee::initPacman() +{ + pacman->setMaxPixmaps(pix->maxPixmaps(PacmanPix)); + pacman->setDemo(gameState.testBit(Demonstration)); + pacman->setPosition(board->position(pacmanhome)); + pacman->setDirection(W, TRUE); + pacman->setAlive(pacmanTicks[level]); +} + +void Referee::initFruit(bool fullInitialization) +{ + if (fullInitialization) { + fruit->setMaxPixmaps(pix->maxPixmaps(FruitPix)); + if (fruitIndex[level] == 0) + fruit->setLevel(level, fruitAppearsTicks[level], + fruitDurTicks[level], fruitTicks[level]); + else if (fruitIndex[level] < 0) + fruit->setLevel(pix->maxPixmaps(FruitPix)+1, + fruitAppearsTicks[level], + fruitDurTicks[level], fruitTicks[level]); + else + fruit->setLevel(fruitIndex[level], fruitAppearsTicks[level], + fruitDurTicks[level], fruitTicks[level]); + } + + if (board->tunnels() > 0) + fruit->setMovement(board->position(tunnel, rand() % board->tunnels()), + board->position(tunnel, rand() % board->tunnels()), + fruitIQ[level]); +} + +void Referee::initMonsters() +{ + if( !monsters->isEmpty()) + monsters->clear(); + if( !monsterRect->isEmpty()) + monsterRect->clear(); + + for (int id = 0; id < (gameState.testBit(Introducing) ? 4 : board->monsters()); id++) { + Monster *m = new Monster(board, id); + monsters->append(m); + QRect *r = new QRect(); + monsterRect->append(r); + if (!gameState.testBit(Introducing)) { + m->setFreedom(board->position(prisonexit)); + m->setDangerous(dangerousTicks[level], monsterIQ[level]); + if (id == 0) + m->setPrison(board->position(prisonentry)); + else { + m->setPrison(board->position(monsterhome, id)); + m->setArrested(arrestTicks[level], arrestDurTicks[level]*id); + } + m->setPosition(board->position(monsterhome, id)); + switch(id) { + case 0 : m->setDirection(W); break; + case 1 : m->setDirection(N); break; + default : m->setDirection(S); + } + } + m->setMaxPixmaps(pix->maxPixmaps(MonsterPix), pix->maxPixmaps(EyesPix)); + } +} + +void Referee::initEnergizers() +{ + if( !energizers->isEmpty()) + energizers->clear(); + if( !energizerRect->isEmpty()) + energizerRect->clear(); + + for (int id = 0; id < (gameState.testBit(Introducing) ? 2 : board->energizers()); id++) { + Energizer *e = new Energizer(board); + energizers->append(e); + QRect *r = new QRect(); + energizerRect->append(r); + if (!gameState.testBit(Introducing)) { + e->setPosition(board->position(energizer, id)); + e->setOn(); + } + e->setMaxPixmaps(pix->maxPixmaps(EnergizerPix)); + } +} + +void Referee::setOnEnergizers() +{ + for (int e = 0; e < board->energizers(); e++) { + energizers->at(e)->setOn(); + } +} + +void Referee::setFocusOutPause(bool FocusOutPause) +{ + focusOutPause = FocusOutPause; +} + +void Referee::setFocusInContinue(bool FocusInContinue) +{ + focusInContinue = FocusInContinue; +} + +void Referee::focusInEvent(QFocusEvent *) +{ + if (focusInContinue && focusedPause && + gameState.testBit(Paused) && gameState.testBit(Playing)) { + pause(); + } +} + +void Referee::focusOutEvent(QFocusEvent *) +{ + if (focusOutPause && !gameState.testBit(Paused) && gameState.testBit(Playing)) { + focusedPause = TRUE; + pause(); + } +} diff --git a/noncore/games/kpacman/referee.h b/noncore/games/kpacman/referee.h new file mode 100644 index 0000000..f812de4 --- a/dev/null +++ b/noncore/games/kpacman/referee.h @@ -0,0 +1,196 @@ +#ifndef REFEREE_H +#define REFEREE_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "portable.h" + +#if defined( KDE2_PORT ) +#include <kapp.h> +#endif + +#include <qwidget.h> +#include <qlist.h> +#include <qstrlist.h> +#include <qarray.h> +#include <qbitarry.h> + +#include "board.h" +#include "pacman.h" +#include "monster.h" +#include "fruit.h" +#include "energizer.h" +#include "bitfont.h" +#include "painter.h" + +enum { Init, Introducing, Playing, Demonstration, Paused, Player, Ready, + Scoring, LevelDone, Dying, GameOver, HallOfFame }; + + +class Referee : public QWidget +{ + Q_OBJECT +public: + Referee (QWidget *parent=0, const char *name=0, int scheme=-1, int mode=-1, Bitfont *font=0); + + void setSkill(int); + void setRoom(int); + +public slots: + void setScheme(int scheme, int mode, Bitfont *font=0); + + void levelUp(); + void levelUpPlay(); + + void pause(); + void ready(); + void intro(); + void introPlay(); + void hallOfFame(); + void demo(); + void play(); + void killed(); + void killedPlay(); + void eaten(); + void toggleHallOfFame(); + + void setFocusOutPause(bool focusOutPause); + void setFocusInContinue(bool focusInContinue); + void initKeys(); + + void repaintFigures(); + +private slots: + void start(); + void stop(); + void stopEnergizer(); + +signals: + void setScore(int, int); + void setPoints(int); + void setLevel(int); + void setLifes(int); + + void toggleNew(); + void togglePaused(); + void forcedHallOfFame(bool); + +protected: + void timerEvent(QTimerEvent *); + void paintEvent(QPaintEvent *); + void keyPressEvent(QKeyEvent *); + + void focusOutEvent(QFocusEvent *); + void focusInEvent(QFocusEvent *); + + void fillArray(QArray<int> &, QString, int); + void fillStrList(QStrList &, QString, int); + void fillMapName(); + + void confScheme(); + void confLevels(bool defGroup=TRUE); + void confMisc(bool defGroup=TRUE); + void confTiming(bool defGroup=TRUE); + void confScoring(bool defGroup=TRUE); + +private: + QBitArray gameState; + int timerCount; + int maxLevel; + + int scheme; + int mode; + + QString pixmapDirectory; + QString mapDirectory; + QStrList mapName; + + QArray<int> speed; + QArray<int> monsterIQ; + QArray<int> fruitIQ; + QArray<int> fruitIndex; + QArray<int> pacmanTicks; + QArray<int> remTicks; + QArray<int> dangerousTicks; + QArray<int> harmlessTicks; + QArray<int> harmlessDurTicks; + QArray<int> harmlessWarnTicks; + QArray<int> arrestTicks; + QArray<int> arrestDurTicks; + QArray<int> fruitTicks; + QArray<int> fruitAppearsTicks; + QArray<int> fruitDurTicks; + QArray<int> fruitScoreDurTicks; + + int monsterScoreDurMS; + int playerDurMS; + int readyDurMS; + int gameOverDurMS; + int afterPauseMS; + int dyingPreAnimationMS; + int dyingAnimationMS; + int dyingPostAnimationMS; + int introAnimationMS; + int introPostAnimationMS; + int levelUpPreAnimationMS; + int levelUpAnimationMS; + int energizerAnimationMS; + + int pointScore; + int energizerScore; + QArray<int> fruitScore; + QArray<int> monsterScore; + QArray<int> extraLifeScore; + + int extraLifeScoreIndex; + int nextExtraLifeScore; + + int monstersEaten; + int points; + int lifes; + int level; + + bool focusedPause; + bool focusOutPause; + bool focusInContinue; + + Board *board; + Painter *pix; + Pacman *pacman; + Fruit *fruit; + + QList<Monster> *monsters; + QList<QRect> *monsterRect; + + QList<Energizer> *energizers; + QList<QRect> *energizerRect; + + QRect pacmanRect; + QRect fruitRect; + + void introMonster(int id); + void introPaint(int t); + + void initMonsters(); + void initPacman(); + void initFruit(bool fullInitialization=TRUE); + void initEnergizers(); + + void setOnEnergizers(); + + int gameTimer; + int energizerTimer; + void start(int); + void init(bool); + + void score(int); + + uint UpKey; + uint DownKey; + uint RightKey; + uint LeftKey; +}; + +#endif // REFEREE_H diff --git a/noncore/games/kpacman/score.cpp b/noncore/games/kpacman/score.cpp new file mode 100644 index 0000000..6e660e8 --- a/dev/null +++ b/noncore/games/kpacman/score.cpp @@ -0,0 +1,642 @@ + +#include "portable.h" + +#if defined( KDE2_PORT ) +#include <score.h> +#include <score.moc> + +#include <kaccel.h> +#include <kapp.h> +#include <kconfig.h> +#include <kstddirs.h> +#include <kmessagebox.h> +#elif defined( QPE_PORT ) +#include <qaccel.h> +#include "config.h" +#include "score.h" +#endif + +#include <stdlib.h> +#include <ctype.h> + +#include <qpixmap.h> +#include <qstring.h> +#include <qdstream.h> +#include <qkeycode.h> +#include <qtimer.h> +#include <qfileinfo.h> + +#include "bitfont.h" + +Score::Score(QWidget *parent, const char *name, int Scheme, int Mode, Bitfont *font) : QWidget(parent, name) +{ + setFocusPolicy(QWidget::StrongFocus); + + paused = FALSE; + + lastScore = -1; + lastPlayer = -1; + + cursorBlinkTimer = 0; + cursorBlinkMS = -1; + cursor.x = -1; + cursor.y = -1; + cursor.on = FALSE; + cursor.chr = QChar('?'); + + initKeys(); + + scheme = Scheme; + mode = Mode; + confScheme(); + + bitfont = font; + + highscoreFile.setName(locateHighscoreFilePath().filePath()); + read(); + + for (int p = 0; p < maxPlayer; p++) { + playerScore[p] = 0; + playerName[p] = getenv("LOGNAME"); + if (playerName[p].length() < minPlayerNameLength) + playerName[p].setExpand(minPlayerNameLength-1, ' '); + + for (uint i = 0; i < playerName[p].length(); i++) + if (playerName[p].at(i) < bitfont->firstChar() || + playerName[p].at(i) > bitfont->lastChar()) + playerName[p].at(i) = playerName[p].at(i).upper(); + } +} + +Score::~Score() +{ + // write(); +} + +void Score::paintEvent( QPaintEvent *e) +{ + if (rect(1, 0, i18n(" 1UP ")).intersects(e->rect())) { + QPixmap pix; + QColor fg = BLACK; + if (cursor.on || paused || lastPlayer != 0) + fg = WHITE; + pix = bitfont->text(i18n(" 1UP "), fg, BLACK); + bitBlt(this, x(1), y(0), &pix); + } + + if (rect(8, 0, i18n(" HIGH SCORE ")).intersects(e->rect())) { + QPixmap pix = bitfont->text(i18n(" HIGH SCORE "), WHITE, BLACK); + bitBlt(this, x(8), y(0), &pix); + } + + if (maxPlayer > 1 && rect(21, 0, i18n(" 2UP ")).intersects(e->rect())) { + QPixmap pix; + QColor fg = BLACK; + if (cursor.on || paused || lastPlayer != 1) + fg = WHITE; + pix = bitfont->text(i18n(" 2UP "), fg, BLACK); + bitBlt(this, x(21), y(0), &pix); + } + + QString s; + + s.sprintf("%6d0", playerScore[0]/10); + if (rect(0, 1, s).intersects(e->rect())) { + QPixmap pix = bitfont->text(s, WHITE, BLACK); + bitBlt(this, x(0), y(1), &pix); + } + + s.sprintf("%8d0", HighScore/10); + if (rect(8, 1, s).intersects(e->rect())) { + QPixmap pix = bitfont->text(s, WHITE, BLACK); + bitBlt(this, x(8), y(1), &pix); + } + + if (lastScore >= 0) { + if (rect(1, 4*1.25, i18n(" CONGRATULATIONS ")).intersects(e->rect())) { + QPixmap pix = bitfont->text(i18n(" CONGRATULATIONS "), YELLOW, BLACK); + bitBlt(this, x(1), y(4*1.25), &pix); + } + if (rect(1, 6*1.25, i18n(" YOU HAVE ARCHIEVED ")).intersects(e->rect())) { + QPixmap pix = bitfont->text(i18n(" YOU HAVE ARCHIEVED "), CYAN, BLACK); + bitBlt(this, x(1), y(6*1.25), &pix); + } + if (rect(1, 7*1.25, i18n(" A SCORE IN THE TOP 10. ")).intersects(e->rect())) { + QPixmap pix = bitfont->text(i18n(" A SCORE IN THE TOP 10. "), CYAN, BLACK); + bitBlt(this, x(1), y(7*1.25), &pix); + } + if (rect(1, 8*1.25, i18n(" ")).intersects(e->rect())) { + QPixmap pix = bitfont->text(i18n(" "), CYAN, BLACK); + bitBlt(this, x(1), y(8*1.25), &pix); + } + } + + if (rect(1, 9.5*1.25, i18n("RNK SCORE NAME DATE")).intersects(e->rect())) { + QPixmap pix = bitfont->text(i18n("RNK SCORE NAME DATE"), WHITE, BLACK); + bitBlt(this, x(1), y(9.5*1.25), &pix); + } + + for (int i = 0; i < 10; i++) { + s.sprintf("%2d%9d %-3.3s %-8.8s", + i+1, hallOfFame[i].points, hallOfFame[i].name.utf8().data(), + formatDate(hallOfFame[i].moment.date()).data()); + if (rect(1, (11+i)*1.25, s).intersects(e->rect())) { + QPixmap pix = bitfont->text(s, (i == lastScore) ? YELLOW : WHITE, BLACK); + bitBlt(this, x(1), y((11+i)*1.25), &pix); + } + } + + if (cursor.x != -1 && cursor.y != -1 && cursor.on) { + if (rect(cursor.x, (cursor.y*1.25), cursor.chr).intersects(e->rect())) { + QPixmap pix = bitfont->text(cursor.chr, BLACK, YELLOW); + bitBlt(this, x(cursor.x), y(cursor.y*1.25), &pix); + } + } + + if (paused) { + + QPixmap pix = bitfont->text(i18n("PAUSED"), RED, BLACK); + QRect r = bitfont->rect(i18n("PAUSED")); + r.moveCenter(QPoint(this->width()/2, this->height()/2)); + + bitBlt(this, r.x(), r.y(), &pix); + } +} + +void Score::timerEvent(QTimerEvent*) +{ + cursor.on = !cursor.on; + + if (paused) + return; + + if (cursor.x != -1 && cursor.y != -1) + repaint(rect(cursor.x, cursor.y*1.25, cursor.chr), FALSE); + scrollRepeat = FALSE; + + if (lastPlayer == 0) + repaint(rect(1, 0, i18n(" 1UP ")), FALSE); + + if (lastPlayer == 1) + repaint(rect(21, 0, i18n(" 2UP ")), FALSE); +} + +void Score::keyPressEvent(QKeyEvent *k) +{ + if (lastScore < 0 || lastPlayer < 0 || lastPlayer >= maxPlayer || paused) { + k->ignore(); + return; + } + + int x = cursor.x; + int y = cursor.y; + + uint key = k->key(); + + if (scrollRepeat && (key == UpKey || key == Key_Up || key == DownKey || key == Key_Down)) { + k->ignore(); + return; + } + + if (key != Key_Return) { + if (key == RightKey || key == Key_Right) + if (++cursor.x > 16) + cursor.x = 14; + if (key == LeftKey || key == Key_Left) + if (--cursor.x < 14) + cursor.x = 16; + if (key == UpKey || key == Key_Up) + if (cursor.chr.unicode() < bitfont->lastChar()) + cursor.chr = cursor.chr.unicode()+1; + else + cursor.chr = bitfont->firstChar(); + if (key == DownKey || key == Key_Down) + if (cursor.chr.unicode() > bitfont->firstChar()) + cursor.chr = cursor.chr.unicode()-1; + else + cursor.chr = bitfont->lastChar(); + + if (cursor.x == x && cursor.y == y && + cursor.chr == hallOfFame[lastScore].name.at(cursor.x-14)) { + uint ascii = k->ascii(); + + if (ascii < bitfont->firstChar() || ascii > bitfont->lastChar()) + ascii = toupper(ascii); + + if (ascii >= bitfont->firstChar() && ascii <= bitfont->lastChar()) { + cursor.chr = ascii; + hallOfFame[lastScore].name.at(cursor.x-14) = cursor.chr; + if (++cursor.x > 16) + cursor.x = 14; + } + } + } + + if (key == Key_Return) { + playerName[lastPlayer] = hallOfFame[lastScore].name; + write(); + read(); + lastScore = -1; + cursor.x = -1; + cursor.y = -1; +// killTimers(); + emit toggleNew(); + end(); + } + + if (x != cursor.x || y != cursor.y) { + if (cursor.x != -1) + cursor.chr = hallOfFame[lastScore].name.at(cursor.x-14); + scrollRepeat = FALSE; + repaint(rect(x, y*1.25, cursor.chr), FALSE); + } else + hallOfFame[lastScore].name.at(cursor.x-14) = cursor.chr; + + if (key == UpKey || key == Key_Up || key == DownKey || key == Key_Down) + scrollRepeat = TRUE; + else + repaint(rect(cursor.x, cursor.y*1.25, cursor.chr), FALSE); +} + +void Score::initKeys() +{ + APP_CONFIG_BEGIN( cfg ); + QString up("Up"); + up = cfg->readEntry("upKey", (const char*) up); + UpKey = KAccel::stringToKey(up); + + QString down("Down"); + down = cfg->readEntry("downKey", (const char*) down); + DownKey = KAccel::stringToKey(down); + + QString left("Left"); + left = cfg->readEntry("leftKey", (const char*) left); + LeftKey = KAccel::stringToKey(left); + + QString right("Right"); + right = cfg->readEntry("rightKey", (const char*) right); + RightKey = KAccel::stringToKey(right); + APP_CONFIG_END( cfg ); +} + +void Score::confTiming(bool defGroup) +{ + APP_CONFIG_BEGIN( cfg ); + if (defGroup || cfg->hasKey("CursorBlinkMS")) + cursorBlinkMS = cfg->readNumEntry("CursorBlinkMS", 250); + if (defGroup || cfg->hasKey("HallOfFameMS")) + hallOfFameMS = cfg->readNumEntry("HallOfFameMS", 7000); + if (defGroup || cfg->hasKey("AfterPauseMS")) + afterPauseMS = cfg->readNumEntry("AfterPauseMS", 1000); + APP_CONFIG_END( cfg ); +} + +void Score::confScheme() +{ + APP_CONFIG_BEGIN( cfg ); + SAVE_CONFIG_GROUP( cfg, oldgroup ); + QString newgroup; + + // if not set, read mode and scheme from the configfile + if (mode == -1 && scheme == -1) { + scheme = cfg->readNumEntry("Scheme", -1); + mode = cfg->readNumEntry("Mode", -1); + + // if mode is not set in the defGroup-group, lookup the scheme group + if (scheme != -1 || mode == -1) { + newgroup.sprintf("Scheme %d", scheme); + cfg->setGroup(newgroup); + + mode = cfg->readNumEntry("Mode", -1); + RESTORE_CONFIG_GROUP( cfg, oldgroup ); + } + } + + int oldCursorBlinkMS = cursorBlinkMS; + + confTiming(); + + if (mode != -1) { + newgroup.sprintf("Mode %d", mode); + cfg->setGroup(newgroup); + + confTiming(FALSE); + } + + if (scheme != -1) { + newgroup.sprintf("Scheme %d", scheme); + cfg->setGroup(newgroup); + + confTiming(FALSE); + } + + if (cursorBlinkMS != oldCursorBlinkMS) { + if (cursorBlinkTimer) + killTimer(cursorBlinkTimer); + cursorBlinkTimer = startTimer(cursorBlinkMS); + } + + RESTORE_CONFIG_GROUP( cfg, oldgroup ); + APP_CONFIG_END( cfg ); +} + +void Score::setScheme(int Scheme, int Mode, Bitfont *font) +{ + mode = Mode; + scheme = Scheme; + + confScheme(); + + bitfont = font; + + for (int p = 0; p < maxPlayer; p++) + for (uint i = 0; i < playerName[p].length(); i++) + if (playerName[p].at(i) < bitfont->firstChar() || + playerName[p].at(i) > bitfont->lastChar()) + playerName[p].at(i) = playerName[p].at(i).upper(); + + for (int i = 0; i < 10; i++) + for (uint j = 0; j < hallOfFame[i].name.length(); j++) + if (hallOfFame[i].name.at(j) < bitfont->firstChar() || + hallOfFame[i].name.at(j) > bitfont->lastChar()) + hallOfFame[i].name.at(j) = hallOfFame[i].name.at(j).upper(); + + if (cursor.chr.unicode() < bitfont->firstChar() || + cursor.chr.unicode() > bitfont->lastChar()) + cursor.chr = cursor.chr.upper(); +} + +void Score::set(int score) +{ + set(score, 0); +} + +void Score::set(int score, int player) +{ + if (player < 0 || player >= maxPlayer) + return; + + lastPlayer = player; + playerScore[lastPlayer] = score; + + QString s; + + s.sprintf("%6d0", playerScore[lastPlayer]/10); + repaint(rect(0, 1, s), FALSE); + + if (score > HighScore) { + HighScore = score; + s.sprintf("%8d0", HighScore/10); + repaint(rect(8, 1, s), FALSE); + } +} + +/* + * Set the score for player after the game if over. If the score is in the + * high scores then the hall of fame is updated (shifted) and the scoreboard + * is shown. + */ + +void Score::setScore(int level, int player) +{ + lastScore = -1; + + if (player < 0 || player >= maxPlayer || level == 0) { + if (level != 0) + emit toggleNew(); + QTimer::singleShot(hallOfFameMS, this, SLOT(end())); + return; + } + + lastPlayer = player; + + for (int i = 0; i < 10; i++) + if ( playerScore[lastPlayer] > hallOfFame[i].points) { + lastScore = i; + break; + } + + if (lastScore < 0) { + emit toggleNew(); + QTimer::singleShot(hallOfFameMS, this, SLOT(end())); + return; + } + + for (int i = 9; i > lastScore && i > 0; i--) + hallOfFame[i] = hallOfFame[i-1]; + + hallOfFame[lastScore].points = playerScore[lastPlayer]; + hallOfFame[lastScore].levels = level; + hallOfFame[lastScore].moment = QDateTime::currentDateTime(); + hallOfFame[lastScore].name = playerName[lastPlayer]; + + cursor.x = 14; + cursor.y = 11+lastScore; + cursor.chr = hallOfFame[lastScore].name.at(cursor.x-14); + +// startTimer(cursorBlinkMS); + setFocus(); +} + +/* + * Read the highscores, if no file or a file shorter than 4 bytes (versions before 0.2.4 stores only + * the points of one highscore) exists - the highscores were initialized with default values. + */ +void Score::read() +{ + if (highscoreFile.exists() && highscoreFile.size() > 4) { + if (highscoreFile.open(IO_ReadOnly)) { + QDataStream s(&highscoreFile); + char *name; + for (int i = 0; i < 10; i++) { + s >> hallOfFame[i].points >> hallOfFame[i].levels >> hallOfFame[i].duration >> + hallOfFame[i].moment >> name; + hallOfFame[i].name = QString::fromLatin1(name); + delete(name); + } + highscoreFile.close(); + } + } else { + for (int i = 0; i < 10; i++) { + hallOfFame[i].points = 5000; + hallOfFame[i].levels = 0; + hallOfFame[i].duration = QTime(); + hallOfFame[i].moment = QDateTime(); + hallOfFame[i].name = "???"; + } + // write(); + } + + for (int i = 0; i < 10; i++) + for (uint j = 0; j < hallOfFame[i].name.length(); j++) + if (hallOfFame[i].name.at(j) < bitfont->firstChar() || + hallOfFame[i].name.at(j) > bitfont->lastChar()) + hallOfFame[i].name.at(j) = hallOfFame[i].name.at(j).upper(); + + HighScore = hallOfFame[0].points; +} + +void Score::write() +{ +#ifndef QWS + if (!highscoreFile.exists() && highscoreFile.name() == systemHighscoreFileInfo.filePath()) + KMessageBox::information(0, + i18n("You're going to create the highscore-file\n" + "'%1'\n" + "for your maschine, that should be used systemwide.\n" + "\n" + "To grant access to the other users, set the appropriate rights (a+w)\n" + "on that file or ask your systemadministator for that favor.\n" + "\n" + "To use a different directory or filename for the highscores," + "specify them in the configfile (kpacmanrc:highscoreFilePath)." + ).arg(systemHighscoreFileInfo.filePath())); + + if (highscoreFile.name() == privateHighscoreFileInfo.filePath()) + KMessageBox::information(0, + i18n("You're using a private highscore-file, that's mostly because of\n" + "missing write-access to the systemwide file\n" + "'%1' .\n" + "\n" + "Ask your systemadministrator for granting you access to that file,\n" + "by setting the appropriate rights (a+w) on it.\n" + "\n" + "To use a different directory or filename for the highscores," + "specify them in the configfile (kpacmanrc:highscoreFilePath)." + ).arg(systemHighscoreFileInfo.filePath()), + QString::null, "PrivateHighscore"); +#endif + if (highscoreFile.open(IO_WriteOnly)) { + QDataStream s(&highscoreFile); + for (int i = 0; i < 10; i++) + s << hallOfFame[i].points << hallOfFame[i].levels << hallOfFame[i].duration << + hallOfFame[i].moment << hallOfFame[i].name.latin1(); + highscoreFile.close(); + } +} + +void Score::setPause(bool Paused) +{ + paused = Paused; + + QRect r = bitfont->rect(i18n("PAUSED")); + r.moveCenter(QPoint(this->width()/2, this->height()/2)); + repaint(r, TRUE); + + // repaint 1UP or 2UP + repaint(FALSE); +} + +void Score::end() +{ + if (paused) { + QTimer::singleShot(afterPauseMS, this, SLOT(end())); + return; + } + + // repaint 1UP or 2UP + lastPlayer = -1; + repaint(FALSE); + + emit forcedHallOfFame(FALSE); +} + +/* + * Return the date in a formatted QString. The format can be changed using internationalization + * of the string "YY/MM/DD". Invalid QDate's where returned as "00/00/00". + */ +QString Score::formatDate(QDate date) +{ + QString s = i18n("@YY@/@MM@/@DD@"); + + QString dd; + dd.sprintf("%02d", date.isValid() ? date.year() % 100 : 0); + s.replace(QRegExp("@YY@"), dd); + dd.sprintf("%02d", date.isValid() ? date.month() : 0); + s.replace(QRegExp("@MM@"), dd); + dd.sprintf("%02d", date.isValid() ? date.day() : 0); + s.replace(QRegExp("@DD@"), dd); + + return s; +} + +QRect Score::rect(int col, float row, QString str, int align) +{ + QRect r = bitfont->rect(str); + r.moveBy(x(col), y(row)); + + int dx = 0; + int dy = 0; + + if (align & AlignLeft || align & AlignRight) { + dx = (str.length()-1) * (bitfont->width()/2); + if (align & AlignRight) + dx *= -1; + } + + if (align & AlignTop || align & AlignBottom) { + dy = bitfont->height()/2; + if (align & AlignBottom) + dy *= -1; + } + + if (dx != 0 || dy != 0) + r.moveBy(dx, dy); + + return r; +} + +int Score::x(int col) +{ + return col*bitfont->width(); +} + +int Score::y(float row) +{ + return (int) (row*(bitfont->height()+bitfont->height()/4)); +} + +/** + * Ermittelt die zu benutzende "highscore"-Datei, in die auch geschrieben werden kann. + * Über den "highscoreFilePath"-KConfig-Eintrag, kann abweichend von der Standardlokation + * der Standort der "highscore"-Datei spezifiziert werden. + * Wenn die systemweite "highscore"-Datei nicht beschrieben werden kann, wird mit einer + * privaten Datei gearbeitet. + */ +QFileInfo Score::locateHighscoreFilePath() +{ +#ifndef QWS + QFileInfo systemHighscoreDirPath; + QStringList systemHighscoreDirs; + + // Schreibfähige "private" highscore-Datei ermitteln für den fallback. + privateHighscoreFileInfo.setFile(KGlobal::dirs()->saveLocation("appdata")+highscoreName); + + // FilePath aus der Konfigurationsdatei benutzen + systemHighscoreFileInfo.setFile(cfg->readEntry("HighscoreFilePath")); + + // Kein Wert aus der Konfiguration erhalten, dann die "system"-Datei suchen. + if (systemHighscoreFileInfo.filePath().isEmpty()) + systemHighscoreDirs = KGlobal::dirs()->resourceDirs("appdata"); + else + systemHighscoreDirs = QStringList(systemHighscoreFileInfo.filePath()); + + for (QStringList::Iterator i = systemHighscoreDirs.begin(); i != systemHighscoreDirs.end(); ++i) { + + systemHighscoreFileInfo.setFile(*i); + if (systemHighscoreFileInfo.fileName().isEmpty()) + systemHighscoreFileInfo.setFile(systemHighscoreFileInfo.dirPath()+"/"+highscoreName); + + // privateHighscoreFileInfo für die "system" Suche ignorieren + if (systemHighscoreFileInfo.filePath() != privateHighscoreFileInfo.filePath()) + if (!systemHighscoreFileInfo.exists()) { + systemHighscoreDirPath.setFile(systemHighscoreFileInfo.dirPath()); + if (systemHighscoreDirPath.exists() && systemHighscoreDirPath.isWritable()) + return systemHighscoreFileInfo; + } else + if (systemHighscoreFileInfo.isWritable()) + return systemHighscoreFileInfo; + } +#endif + return privateHighscoreFileInfo; +} diff --git a/noncore/games/kpacman/score.h b/noncore/games/kpacman/score.h new file mode 100644 index 0000000..87f24b9 --- a/dev/null +++ b/noncore/games/kpacman/score.h @@ -0,0 +1,129 @@ +#ifndef SCORE_H +#define SCORE_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "portable.h" + +#if defined( KDE2_PORT ) +#include <kapp.h> +#endif + +#include <qwidget.h> +#include <qstring.h> +#include <qpoint.h> +#include <qrect.h> +#include <qfile.h> + +#include <qfileinfo.h> +#include <qdatetime.h> + +#include "painter.h" +#include "bitfont.h" + +#define maxPlayer 1 +#define minPlayerNameLength 3 +#define highscoreName "highscore" + +class Score : public QWidget +{ + Q_OBJECT +public: + Score (QWidget *parent=0, const char *name=0, int scheme=-1, int mode=-1, Bitfont *font=0); + ~Score(); + +public slots: + void setScheme(int scheme, int mode, Bitfont *font=0); + + void set(int score); + void set(int score, int player); + void setScore(int level, int player); + void setPause(bool paused); + + void initKeys(); + +private slots: + void read(); + void write(); + void end(); + +signals: + void toggleNew(); + void forcedHallOfFame(bool); + +protected: + void timerEvent(QTimerEvent *); + void paintEvent(QPaintEvent *); + void keyPressEvent(QKeyEvent *); + + void focusInEvent(QFocusEvent *) { ; } + void focusOutEvent(QFocusEvent *) { ; } + + void confScheme(); + void confTiming(bool defGroup=TRUE); + +private: + Bitfont *bitfont; + + QRect rect(int col, float row, QString str, int align = AlignCenter); + int x(int col); + int y(float row); + + QString formatDate(QDate date); + + /** + * Ermittelt die zu benutzende "highscore"-Datei, in die auch geschrieben werden kann. + * Über den "highscoreFilePath"-KConfig-Eintrag, kann abweichend von der Standardlokation + * der Standort der "highscore"-Datei spezifiziert werden. + * Wenn die systemweite "globale" Datei nicht beschrieben werden kann, wird mit einer + * privaten Datei gearbeitet. + */ + QFileInfo locateHighscoreFilePath(); + + int cursorBlinkMS; + int hallOfFameMS; + int afterPauseMS; + + bool paused; + + uint UpKey; + uint DownKey; + uint RightKey; + uint LeftKey; + + int lastScore; + int lastPlayer; + int HighScore; + int playerScore[maxPlayer]; + QString playerName[maxPlayer]; + + struct { + int x; + int y; + QChar chr; + bool on; + } cursor; + + int cursorBlinkTimer; + bool scrollRepeat; + + struct { + int points; + int levels; + QTime duration; + QDateTime moment; + QString name; + } hallOfFame[10]; + + QFileInfo systemHighscoreFileInfo; + QFileInfo privateHighscoreFileInfo; + + QFile highscoreFile; + + int scheme; + int mode; +}; + +#endif // SCORE_H diff --git a/noncore/games/kpacman/status.cpp b/noncore/games/kpacman/status.cpp new file mode 100644 index 0000000..00d1f22 --- a/dev/null +++ b/noncore/games/kpacman/status.cpp @@ -0,0 +1,367 @@ + +#include "portable.h" + +#if defined( KDE2_PORT ) +#include <kapp.h> +#include <klocale.h> +#include <kstddirs.h> +#include <status.h> +#include <status.moc> +#elif defined( QPE_PORT ) +#include <qpe/qpeapplication.h> +#include "config.h" +#include "status.h" +#endif + +#include <qpixmap.h> +#include <qbitmap.h> +#include <qstring.h> +#include <qmsgbox.h> +#include <qfileinfo.h> + +Status::Status( QWidget *parent, const char *name, int Scheme, int Mode ) : + QWidget( parent, name ) +{ + actualLifes = 0; + actualLevel = 0; + + lifesPix = NULL; + levelPix = NULL; + + scheme = Scheme; + mode = Mode; + level = 0; + + confScheme(); +} + +QList<QPixmap> *Status::loadPixmap(QWidget *parent, QString pixmapName, + QList<QPixmap> *pixmaps) +{ + if (pixmaps == NULL) { + pixmaps = new QList<QPixmap>; + pixmaps->setAutoDelete(TRUE); + } + + if (!pixmaps->isEmpty()) + pixmaps->clear(); + + QPixmap PIXMAP(pixmapName); + if (PIXMAP.isNull() || PIXMAP.mask() == NULL) { + QString msg = i18n("The pixmap could not be contructed.\n\n" + "The file '@PIXMAPNAME@' does not exist,\n" + "or is of an unknown format."); + msg.replace(QRegExp("@PIXMAPNAME@"), pixmapName); + QMessageBox::information(parent, i18n("Initialization Error"), + (const char *) msg); + return 0; + } + + int height = PIXMAP.height(); + int width = (height == 0) ? 0 : PIXMAP.width()/(PIXMAP.width()/height); + + QBitmap BITMAP; + QBitmap MASK; + + BITMAP = *PIXMAP.mask(); + MASK.resize(width, height); + + for (int x = 0; x < PIXMAP.width()/width; x++) { + QPixmap *pixmap = new QPixmap(width, height); + pixmaps->append(pixmap); + bitBlt(pixmap, 0, 0, &PIXMAP, x*width, 0, width, height, CopyROP, TRUE); + bitBlt(&MASK, 0, 0, &BITMAP, x*width, 0, width, height, CopyROP, TRUE); + pixmap->setMask(MASK); + } + + return pixmaps; +} + +void Status::paintEvent( QPaintEvent *) +{ + for (int x = 0; x < actualLifes && !lifesPix->isEmpty(); x++) + bitBlt(this, lifesPix->at(0)->width()+(lifesPix->at(0)->width()*x), + (height()-lifesPix->at(0)->height())/2, + lifesPix->at(0), 0, 0, + lifesPix->at(0)->width(), lifesPix->at(0)->height()); + + for (int x = 0; x < actualLevel && !levelPix->isEmpty(); x++) { + erase((width()-levelPix->at(x)->width()*2)-(levelPix->at(x)->width()*levelPos[x]), + (height()-levelPix->at(x)->height())/2, + levelPix->at(x)->width(), levelPix->at(x)->height()); + bitBlt(this, (width()-levelPix->at(x)->width()*2)-(levelPix->at(x)->width()*levelPos[x]), + (height()-levelPix->at(x)->height())/2, + levelPix->at(x), 0, 0, + levelPix->at(x)->width(), levelPix->at(x)->height()); + } +} + +void Status::initPixmaps() +{ + if (lastLifesPixmapName != lifesPixmapName.at(level)) { + lifesPix = loadPixmap(this, lifesPixmapName.at(level), lifesPix); + lastLifesPixmapName = lifesPixmapName.at(level); + } + if (lastLevelPixmapName != levelPixmapName.at(level)) { + levelPix = loadPixmap(this, levelPixmapName.at(level), levelPix); + lastLevelPixmapName = levelPixmapName.at(level); + } +} + +QString Status::decodeHexOctString(QString s) +{ + QString value; + QString valids; + int pos, xpos = 0, opos = 0; + int v, len, leadin; + const char *ptr; + uchar c; + + while (((xpos = s.find(QRegExp("\\\\x[0-9a-fA-F]+"), xpos)) != -1) || + ((opos = s.find(QRegExp("\\\\[0-7]+"), opos)) != -1)) { + if (xpos != -1) { + valids = "0123456789abcdef"; + leadin = 2; + pos = xpos; + } else { + valids = "01234567"; + leadin = 1; + pos = opos; + } + + c = '\0'; + len = 0; + value = s.mid(pos+leadin, 3); + ptr = (const char *) value; + + while (*ptr != '\0' && (v = valids.find(*ptr++, 0, FALSE)) != -1) { + c = (c * valids.length()) + v; + len++; + } + + value.fill(c, 1); + s.replace(pos, len+leadin, value); + } + + return s; +} + +void Status::fillArray(QArray<int> &array, QString values, int max) +{ + array.resize(max); + int last = 0; + bool ok; + QString value; + + for (uint i = 0; i < array.size(); i++) { + if (values.find(',') < 0 && values.length() > 0) { + value = values; + values = ""; + } + if (values.find(',') >= 0) { + value = values.left(values.find(',')); + values.remove(0,values.find(',')+1); + } + array[i] = value.toInt(&ok); + if (ok) + last = array[i]; + else + array[i] = last; + } +} + +void Status::fillStrList(QStrList &list, QString values, int max) +{ + if (!list.isEmpty()) + list.clear(); + + QString last = ""; + QString value; + + for (uint i = 0; i < (uint) max; i++) { + if (values.find(',') < 0 && values.length() > 0) { + value = values; + values = ""; + } + if (values.find(',') >= 0) { + value = values.left(values.find(',')); + values.remove(0,values.find(',')+1); + } + if (!value.isEmpty()) + last = decodeHexOctString(value); + list.append(last); + } +} + +void Status::fillPixmapName(QStrList &pixmapName) +{ + QStrList list = pixmapName; + + if (!pixmapName.isEmpty()) + pixmapName.clear(); + + QString pixmap; + + QFileInfo fileInfo; + + for (uint i = 0; i < list.count(); i++) { + pixmap = list.at(i); + + if (pixmap.left(1) != "/" && pixmap.left(1) != "~") + pixmap = FIND_APP_DATA( pixmapDirectory+pixmap ); + + fileInfo.setFile(pixmap); + if (!fileInfo.isReadable() || !fileInfo.isFile()) + pixmap = ""; + + pixmapName.append(pixmap); + } +} + +void Status::confLevels(bool defGroup) +{ + APP_CONFIG_BEGIN( cfg ); + if (defGroup || cfg->hasKey("Levels")) + maxLevel = cfg->readNumEntry("Levels", 13); + APP_CONFIG_END( cfg ); +} + +void Status::confMisc(bool defGroup) +{ + APP_CONFIG_BEGIN( cfg ); + if (defGroup || cfg->hasKey("LevelPosition")) + fillArray(levelPos, cfg->readEntry("LevelPosition", "0,1,2,3,,4,,5,,6,,7"), maxLevel); + + if (defGroup || cfg->hasKey("PixmapDirectory")) { + pixmapDirectory = cfg->readEntry("PixmapDirectory"); + + if (pixmapDirectory.left(1) != "/" && pixmapDirectory.left(1) != "~") + pixmapDirectory.insert(0, "pics/"); + if (pixmapDirectory.right(1) != "/") + pixmapDirectory.append("/"); + } + + if (defGroup || cfg->hasKey("LifesPixmapName")) + fillStrList(lifesPixmapName, + cfg->readEntry("LifesPixmapName", "lifes.xpm"), maxLevel+1); + if (defGroup || cfg->hasKey("LevelPixmapName")) + fillStrList(levelPixmapName, + cfg->readEntry("LevelPixmapName", "level.xpm"), maxLevel+1); + APP_CONFIG_END( cfg ); +} + +void Status::confScheme() +{ + APP_CONFIG_BEGIN( cfg ); + SAVE_CONFIG_GROUP( cfg, oldgroup ); + QString newgroup; + + // if not set, read mode and scheme from the configfile + if (mode == -1 && scheme == -1) { + scheme = cfg->readNumEntry("Scheme", -1); + mode = cfg->readNumEntry("Mode", -1); + + // if mode is not set in the defGroup-group, lookup the scheme group + if (scheme != -1 || mode == -1) { + newgroup.sprintf("Scheme %d", scheme); + cfg->setGroup(newgroup); + + mode = cfg->readNumEntry("Mode", -1); + RESTORE_CONFIG_GROUP( cfg, oldgroup ); + } + } + + confLevels(); + + if (mode != -1) { + newgroup.sprintf("Mode %d", mode); + cfg->setGroup(newgroup); + + confLevels(FALSE); + } + + if (scheme != -1) { + newgroup.sprintf("Scheme %d", scheme); + cfg->setGroup(newgroup); + + confLevels(FALSE); + } + + RESTORE_CONFIG_GROUP( cfg, oldgroup ); + + confMisc(); + + if (mode != -1) { + newgroup.sprintf("Mode %d", mode); + cfg->setGroup(newgroup); + + confMisc(FALSE); + } + + if (scheme != -1) { + newgroup.sprintf("Scheme %d", scheme); + cfg->setGroup(newgroup); + + confMisc(FALSE); + } + + fillPixmapName(lifesPixmapName); + fillPixmapName(levelPixmapName); + + initPixmaps(); + + setFixedHeight(minHeight()); + + RESTORE_CONFIG_GROUP( cfg, oldgroup ); + APP_CONFIG_END( cfg ); +} + +void Status::setScheme(int Scheme, int Mode) +{ + mode = Mode; + scheme = Scheme; + + confScheme(); + + repaint(); +} + +int Status::minHeight() +{ + if (lifesPix->isEmpty() && levelPix->isEmpty()) + return 0; + if (levelPix->isEmpty()) + return lifesPix->at(0)->height(); + if (lifesPix->isEmpty()) + return levelPix->at(0)->height(); + return (lifesPix->at(0)->height() > levelPix->at(0)->height()) ? + lifesPix->at(0)->height() : levelPix->at(0)->height(); +} + +int Status::minWidth() +{ + if (lifesPix->isEmpty() && levelPix->isEmpty()) + return 0; + if (levelPix->isEmpty()) + return lifesPix->at(0)->width(); + if (lifesPix->isEmpty()) + return levelPix->at(0)->width(); + return (lifesPix->at(0)->width() > levelPix->at(0)->width()) ? + lifesPix->at(0)->width() : levelPix->at(0)->width(); +} + +void Status::setLifes(int lifes) +{ + actualLifes = lifes; + repaint(); +} + +void Status::setLevel(int Level) +{ + level = Level; + + initPixmaps(); + + actualLevel = (level > (int) levelPix->count()) ? (int) levelPix->count() : level; + repaint(); +} diff --git a/noncore/games/kpacman/status.h b/noncore/games/kpacman/status.h new file mode 100644 index 0000000..4f69b02 --- a/dev/null +++ b/noncore/games/kpacman/status.h @@ -0,0 +1,78 @@ +#ifndef STATUS_H +#define STATUS_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "portable.h" + +#if defined( KDE2_PORT ) +#include <kapp.h> +#include <kconfig.h> +#endif + +#include <qwidget.h> +#include <qpixmap.h> +#include <qstring.h> +#include <qarray.h> +#include <qlist.h> +#include <qstrlist.h> +#include <qregexp.h> + +class Status : public QWidget +{ + Q_OBJECT +public: + Status(QWidget *parent=0, const char *name=0, int scheme=-1, int mode=-1); + ~Status() {}; + +public slots: + void setScheme(int scheme, int mode); + void setLevel(int level); + void setLifes(int lifes); + +protected: + void paintEvent(QPaintEvent *); + int minHeight(); + int minWidth(); + + QString decodeHexOctString(QString str); + + void fillArray(QArray<int> &, QString, int); + void fillStrList(QStrList &, QString, int); + void fillPixmapName(QStrList &); + + void confScheme(); + void confLevels(bool defGroup=TRUE); + void confMisc(bool defGroup=TRUE); + + void initPixmaps(); + +private: + QArray<int> levelPos; + int actualLifes; + int actualLevel; + + QString pixmapDirectory; + + QStrList lifesPixmapName; + QStrList levelPixmapName; + + QString lastLifesPixmapName; + QString lastLevelPixmapName; + + QList<QPixmap> *loadPixmap(QWidget *parent, QString pixmapName, + QList<QPixmap> *pixmaps=0); + + QList<QPixmap> *lifesPix; + QList<QPixmap> *levelPix; + + int maxLevel; + int level; + + int scheme; + int mode; +}; + +#endif // STATUS_H |