From 6f2c87870081718731cccee678e1e89869826de2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sl=C3=A1vek=20Banko?= Date: Mon, 17 Aug 2020 18:58:43 +0200 Subject: Initial import of version 0.3.2 from the source package. https://sourceforge.net/projects/kpacman/files/kpacman/0.3.2/kpacman-0.3.2.tar.gz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Original package is licenced under GPL 2.0. Signed-off-by: Slávek Banko --- kpacman/score.cpp | 627 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 627 insertions(+) create mode 100644 kpacman/score.cpp (limited to 'kpacman/score.cpp') diff --git a/kpacman/score.cpp b/kpacman/score.cpp new file mode 100644 index 0000000..1bbd427 --- /dev/null +++ b/kpacman/score.cpp @@ -0,0 +1,627 @@ +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 *e) +{ + 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; + lastPlayer = -1; + cursor.x = -1; + cursor.y = -1; + emit gameFinished(); + 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() +{ + QString up("Up"); + up = kapp->config()->readEntry("upKey", (const char*) up); + UpKey = KAccel::stringToKey(up); + + QString down("Down"); + down = kapp->config()->readEntry("downKey", (const char*) down); + DownKey = KAccel::stringToKey(down); + + QString left("Left"); + left = kapp->config()->readEntry("leftKey", (const char*) left); + LeftKey = KAccel::stringToKey(left); + + QString right("Right"); + right = kapp->config()->readEntry("rightKey", (const char*) right); + RightKey = KAccel::stringToKey(right); +} + +void Score::confTiming(bool defGroup) +{ + if (defGroup || kapp->config()->hasKey("CursorBlinkMS")) + cursorBlinkMS = kapp->config()->readNumEntry("CursorBlinkMS", 250); + if (defGroup || kapp->config()->hasKey("HallOfFameMS")) + hallOfFameMS = kapp->config()->readNumEntry("HallOfFameMS", 7000); + if (defGroup || kapp->config()->hasKey("AfterPauseMS")) + afterPauseMS = kapp->config()->readNumEntry("AfterPauseMS", 1000); +} + +void Score::confScheme() +{ + QString oldgroup = kapp->config()->group(); + QString newgroup; + + // if not set, read mode and scheme from the configfile + if (mode == -1 && scheme == -1) { + scheme = kapp->config()->readNumEntry("Scheme", -1); + mode = kapp->config()->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); + kapp->config()->setGroup(newgroup); + + mode = kapp->config()->readNumEntry("Mode", -1); + kapp->config()->setGroup(oldgroup); + } + } + + int oldCursorBlinkMS = cursorBlinkMS; + + confTiming(); + + if (mode != -1) { + newgroup.sprintf("Mode %d", mode); + kapp->config()->setGroup(newgroup); + + confTiming(FALSE); + } + + if (scheme != -1) { + newgroup.sprintf("Scheme %d", scheme); + kapp->config()->setGroup(newgroup); + + confTiming(FALSE); + } + + if (cursorBlinkMS != oldCursorBlinkMS) { + if (cursorBlinkTimer) + killTimer(cursorBlinkTimer); + cursorBlinkTimer = startTimer(cursorBlinkMS); + } + + kapp->config()->setGroup(oldgroup); +} + +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) +{ + // pointer to the array-position of a new archived top score + lastScore = -1; + + // was it a real game or just a demo (level == 0) + if (player >= 0 && player < maxPlayer && level != 0) { + + lastPlayer = player; + + for (int i = 0; i < 10; i++) + if ( playerScore[lastPlayer] > hallOfFame[i].points) { + lastScore = i; + break; + } + } + + // no new highscore archived, finish after specified time + if (lastScore < 0) { + // enable gameNew directly for an immediate next try + emit gameFinished(); + lastPlayer = -1; + QTimer::singleShot(hallOfFameMS, this, SLOT(end())); + return; + } + + // shift old (lower) scores to make place for the new one + 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() +{ + 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"); + + 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 + repaint(FALSE); + + // if lastPlayer != -1 we're already in playing mode + if (lastPlayer == -1) + emit gameHighscores(); +} + +/* + * 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() +{ + 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(kapp->config()->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; + } + + return privateHighscoreFileInfo; +} -- cgit v1.2.1