00001
00002 #include "portable.h"
00003
00004 #if defined( KDE2_PORT )
00005 #include <score.h>
00006 #include <score.moc>
00007
00008 #include <kaccel.h>
00009 #include <kapp.h>
00010 #include <kconfig.h>
00011 #include <kstddirs.h>
00012 #include <kmessagebox.h>
00013 #elif defined( QPE_PORT )
00014 #include <qaccel.h>
00015 #include <qpe/config.h>
00016 #include "score.h"
00017 #endif
00018
00019 #include <stdlib.h>
00020 #include <ctype.h>
00021
00022 #include <qtimer.h>
00023
00024
00025 Score::Score(QWidget *parent, const char *name, int Scheme, int Mode, Bitfont *font) : QWidget(parent, name)
00026 {
00027 setFocusPolicy(QWidget::StrongFocus);
00028
00029 paused = FALSE;
00030
00031 lastScore = -1;
00032 lastPlayer = -1;
00033
00034 cursorBlinkTimer = 0;
00035 cursorBlinkMS = -1;
00036 cursor.x = -1;
00037 cursor.y = -1;
00038 cursor.on = FALSE;
00039 cursor.chr = QChar('?');
00040
00041 initKeys();
00042
00043 scheme = Scheme;
00044 mode = Mode;
00045 confScheme();
00046
00047 bitfont = font;
00048
00049 highscoreFile.setName(locateHighscoreFilePath().filePath());
00050 read();
00051
00052 for (int p = 0; p < maxPlayer; p++) {
00053 playerScore[p] = 0;
00054 playerName[p] = getenv("LOGNAME");
00055 if (playerName[p].length() < minPlayerNameLength)
00056 playerName[p].setExpand(minPlayerNameLength-1, ' ');
00057
00058 for (uint i = 0; i < playerName[p].length(); i++)
00059 if (playerName[p].at(i) < bitfont->firstChar() ||
00060 playerName[p].at(i) > bitfont->lastChar())
00061 playerName[p].at(i) = playerName[p].at(i).upper();
00062 }
00063 }
00064
00065 Score::~Score()
00066 {
00067
00068 }
00069
00070 void Score::paintEvent( QPaintEvent *e)
00071 {
00072 if (rect(1, 0, tr(" 1UP ")).intersects(e->rect())) {
00073 QPixmap pix;
00074 QColor fg = BLACK;
00075 if (cursor.on || paused || lastPlayer != 0)
00076 fg = WHITE;
00077 pix = bitfont->text(tr(" 1UP "), fg, BLACK);
00078 bitBlt(this, x(1), y(0), &pix);
00079 }
00080
00081 if (rect(8, 0, tr(" HIGH SCORE ")).intersects(e->rect())) {
00082 QPixmap pix = bitfont->text(tr(" HIGH SCORE "), WHITE, BLACK);
00083 bitBlt(this, x(8), y(0), &pix);
00084 }
00085
00086 if (maxPlayer > 1 && rect(21, 0, tr(" 2UP ")).intersects(e->rect())) {
00087 QPixmap pix;
00088 QColor fg = BLACK;
00089 if (cursor.on || paused || lastPlayer != 1)
00090 fg = WHITE;
00091 pix = bitfont->text(tr(" 2UP "), fg, BLACK);
00092 bitBlt(this, x(21), y(0), &pix);
00093 }
00094
00095 QString s;
00096
00097 s.sprintf("%6d0", playerScore[0]/10);
00098 if (rect(0, 1, s).intersects(e->rect())) {
00099 QPixmap pix = bitfont->text(s, WHITE, BLACK);
00100 bitBlt(this, x(0), y(1), &pix);
00101 }
00102
00103 s.sprintf("%8d0", HighScore/10);
00104 if (rect(8, 1, s).intersects(e->rect())) {
00105 QPixmap pix = bitfont->text(s, WHITE, BLACK);
00106 bitBlt(this, x(8), y(1), &pix);
00107 }
00108
00109 if (lastScore >= 0) {
00110 if (rect(1, 4*1.25, tr(" CONGRATULATIONS ")).intersects(e->rect())) {
00111 QPixmap pix = bitfont->text(tr(" CONGRATULATIONS "), YELLOW, BLACK);
00112 bitBlt(this, x(1), y(4*1.25), &pix);
00113 }
00114 if (rect(1, 6*1.25, tr(" YOU HAVE ARCHIEVED ")).intersects(e->rect())) {
00115 QPixmap pix = bitfont->text(tr(" YOU HAVE ARCHIEVED "), CYAN, BLACK);
00116 bitBlt(this, x(1), y(6*1.25), &pix);
00117 }
00118 if (rect(1, 7*1.25, tr(" A SCORE IN THE TOP 10. ")).intersects(e->rect())) {
00119 QPixmap pix = bitfont->text(tr(" A SCORE IN THE TOP 10. "), CYAN, BLACK);
00120 bitBlt(this, x(1), y(7*1.25), &pix);
00121 }
00122 if (rect(1, 8*1.25, tr(" ")).intersects(e->rect())) {
00123 QPixmap pix = bitfont->text(tr(" "), CYAN, BLACK);
00124 bitBlt(this, x(1), y(8*1.25), &pix);
00125 }
00126 }
00127
00128 if (rect(1, 9.5*1.25, tr("RNK SCORE NAME DATE")).intersects(e->rect())) {
00129 QPixmap pix = bitfont->text(tr("RNK SCORE NAME DATE"), WHITE, BLACK);
00130 bitBlt(this, x(1), y(9.5*1.25), &pix);
00131 }
00132
00133 for (int i = 0; i < 10; i++) {
00134 s.sprintf("%2d%9d %-3.3s %-8.8s",
00135 i+1, hallOfFame[i].points, hallOfFame[i].name.utf8().data(),
00136 formatDate(hallOfFame[i].moment.date()).data());
00137 if (rect(1, (11+i)*1.25, s).intersects(e->rect())) {
00138 QPixmap pix = bitfont->text(s, (i == lastScore) ? YELLOW : WHITE, BLACK);
00139 bitBlt(this, x(1), y((11+i)*1.25), &pix);
00140 }
00141 }
00142
00143 if (cursor.x != -1 && cursor.y != -1 && cursor.on) {
00144 if (rect(cursor.x, (cursor.y*1.25), cursor.chr).intersects(e->rect())) {
00145 QPixmap pix = bitfont->text(cursor.chr, BLACK, YELLOW);
00146 bitBlt(this, x(cursor.x), y(cursor.y*1.25), &pix);
00147 }
00148 }
00149
00150 if (paused) {
00151
00152 QPixmap pix = bitfont->text(tr("PAUSED"), RED, BLACK);
00153 QRect r = bitfont->rect(tr("PAUSED"));
00154 r.moveCenter(QPoint(this->width()/2, this->height()/2));
00155
00156 bitBlt(this, r.x(), r.y(), &pix);
00157 }
00158 }
00159
00160 void Score::timerEvent(QTimerEvent*)
00161 {
00162 cursor.on = !cursor.on;
00163
00164 if (paused)
00165 return;
00166
00167 if (cursor.x != -1 && cursor.y != -1)
00168 repaint(rect(cursor.x, cursor.y*1.25, cursor.chr), FALSE);
00169 scrollRepeat = FALSE;
00170
00171 if (lastPlayer == 0)
00172 repaint(rect(1, 0, tr(" 1UP ")), FALSE);
00173
00174 if (lastPlayer == 1)
00175 repaint(rect(21, 0, tr(" 2UP ")), FALSE);
00176 }
00177
00178 void Score::keyPressEvent(QKeyEvent *k)
00179 {
00180 if (lastScore < 0 || lastPlayer < 0 || lastPlayer >= maxPlayer || paused) {
00181 k->ignore();
00182 return;
00183 }
00184
00185 int x = cursor.x;
00186 int y = cursor.y;
00187
00188 uint key = k->key();
00189
00190 if (scrollRepeat && (key == UpKey || key == Key_Up || key == DownKey || key == Key_Down)) {
00191 k->ignore();
00192 return;
00193 }
00194
00195 if (key != Key_Return) {
00196 if (key == RightKey || key == Key_Right)
00197 if (++cursor.x > 16)
00198 cursor.x = 14;
00199 if (key == LeftKey || key == Key_Left)
00200 if (--cursor.x < 14)
00201 cursor.x = 16;
00202 if (key == UpKey || key == Key_Up)
00203 if (cursor.chr.unicode() < bitfont->lastChar())
00204 cursor.chr = cursor.chr.unicode()+1;
00205 else
00206 cursor.chr = bitfont->firstChar();
00207 if (key == DownKey || key == Key_Down)
00208 if (cursor.chr.unicode() > bitfont->firstChar())
00209 cursor.chr = cursor.chr.unicode()-1;
00210 else
00211 cursor.chr = bitfont->lastChar();
00212
00213 if (cursor.x == x && cursor.y == y &&
00214 cursor.chr == hallOfFame[lastScore].name.at(cursor.x-14)) {
00215 uint ascii = k->ascii();
00216
00217 if (ascii < bitfont->firstChar() || ascii > bitfont->lastChar())
00218 ascii = toupper(ascii);
00219
00220 if (ascii >= bitfont->firstChar() && ascii <= bitfont->lastChar()) {
00221 cursor.chr = ascii;
00222 hallOfFame[lastScore].name.at(cursor.x-14) = cursor.chr;
00223 if (++cursor.x > 16)
00224 cursor.x = 14;
00225 }
00226 }
00227 }
00228
00229 if (key == Key_Return) {
00230 playerName[lastPlayer] = hallOfFame[lastScore].name;
00231 write();
00232 read();
00233 lastScore = -1;
00234 cursor.x = -1;
00235 cursor.y = -1;
00236
00237 emit toggleNew();
00238 end();
00239 }
00240
00241 if (x != cursor.x || y != cursor.y) {
00242 if (cursor.x != -1)
00243 cursor.chr = hallOfFame[lastScore].name.at(cursor.x-14);
00244 scrollRepeat = FALSE;
00245 repaint(rect(x, y*1.25, cursor.chr), FALSE);
00246 } else
00247 hallOfFame[lastScore].name.at(cursor.x-14) = cursor.chr;
00248
00249 if (key == UpKey || key == Key_Up || key == DownKey || key == Key_Down)
00250 scrollRepeat = TRUE;
00251 else
00252 repaint(rect(cursor.x, cursor.y*1.25, cursor.chr), FALSE);
00253 }
00254
00255 void Score::initKeys()
00256 {
00257 APP_CONFIG_BEGIN( cfg );
00258 QString up("Up");
00259 up = cfg->readEntry("upKey", (const char*) up);
00260 UpKey = KAccel::stringToKey(up);
00261
00262 QString down("Down");
00263 down = cfg->readEntry("downKey", (const char*) down);
00264 DownKey = KAccel::stringToKey(down);
00265
00266 QString left("Left");
00267 left = cfg->readEntry("leftKey", (const char*) left);
00268 LeftKey = KAccel::stringToKey(left);
00269
00270 QString right("Right");
00271 right = cfg->readEntry("rightKey", (const char*) right);
00272 RightKey = KAccel::stringToKey(right);
00273 APP_CONFIG_END( cfg );
00274 }
00275
00276 void Score::confTiming(bool defGroup)
00277 {
00278 APP_CONFIG_BEGIN( cfg );
00279 if (defGroup || cfg->hasKey("CursorBlinkMS"))
00280 cursorBlinkMS = cfg->readNumEntry("CursorBlinkMS", 250);
00281 if (defGroup || cfg->hasKey("HallOfFameMS"))
00282 hallOfFameMS = cfg->readNumEntry("HallOfFameMS", 7000);
00283 if (defGroup || cfg->hasKey("AfterPauseMS"))
00284 afterPauseMS = cfg->readNumEntry("AfterPauseMS", 1000);
00285 APP_CONFIG_END( cfg );
00286 }
00287
00288 void Score::confScheme()
00289 {
00290 APP_CONFIG_BEGIN( cfg );
00291 SAVE_CONFIG_GROUP( cfg, oldgroup );
00292 QString newgroup;
00293
00294
00295 if (mode == -1 && scheme == -1) {
00296 scheme = cfg->readNumEntry("Scheme", -1);
00297 mode = cfg->readNumEntry("Mode", -1);
00298
00299
00300 if (scheme != -1 || mode == -1) {
00301 newgroup.sprintf("Scheme %d", scheme);
00302 cfg->setGroup(newgroup);
00303
00304 mode = cfg->readNumEntry("Mode", -1);
00305 RESTORE_CONFIG_GROUP( cfg, oldgroup );
00306 }
00307 }
00308
00309 int oldCursorBlinkMS = cursorBlinkMS;
00310
00311 confTiming();
00312
00313 if (mode != -1) {
00314 newgroup.sprintf("Mode %d", mode);
00315 cfg->setGroup(newgroup);
00316
00317 confTiming(FALSE);
00318 }
00319
00320 if (scheme != -1) {
00321 newgroup.sprintf("Scheme %d", scheme);
00322 cfg->setGroup(newgroup);
00323
00324 confTiming(FALSE);
00325 }
00326
00327 if (cursorBlinkMS != oldCursorBlinkMS) {
00328 if (cursorBlinkTimer)
00329 killTimer(cursorBlinkTimer);
00330 cursorBlinkTimer = startTimer(cursorBlinkMS);
00331 }
00332
00333 RESTORE_CONFIG_GROUP( cfg, oldgroup );
00334 APP_CONFIG_END( cfg );
00335 }
00336
00337 void Score::setScheme(int Scheme, int Mode, Bitfont *font)
00338 {
00339 mode = Mode;
00340 scheme = Scheme;
00341
00342 confScheme();
00343
00344 bitfont = font;
00345
00346 for (int p = 0; p < maxPlayer; p++)
00347 for (uint i = 0; i < playerName[p].length(); i++)
00348 if (playerName[p].at(i) < bitfont->firstChar() ||
00349 playerName[p].at(i) > bitfont->lastChar())
00350 playerName[p].at(i) = playerName[p].at(i).upper();
00351
00352 for (int i = 0; i < 10; i++)
00353 for (uint j = 0; j < hallOfFame[i].name.length(); j++)
00354 if (hallOfFame[i].name.at(j) < bitfont->firstChar() ||
00355 hallOfFame[i].name.at(j) > bitfont->lastChar())
00356 hallOfFame[i].name.at(j) = hallOfFame[i].name.at(j).upper();
00357
00358 if (cursor.chr.unicode() < bitfont->firstChar() ||
00359 cursor.chr.unicode() > bitfont->lastChar())
00360 cursor.chr = cursor.chr.upper();
00361 }
00362
00363 void Score::set(int score)
00364 {
00365 set(score, 0);
00366 }
00367
00368 void Score::set(int score, int player)
00369 {
00370 if (player < 0 || player >= maxPlayer)
00371 return;
00372
00373 lastPlayer = player;
00374 playerScore[lastPlayer] = score;
00375
00376 QString s;
00377
00378 s.sprintf("%6d0", playerScore[lastPlayer]/10);
00379 repaint(rect(0, 1, s), FALSE);
00380
00381 if (score > HighScore) {
00382 HighScore = score;
00383 s.sprintf("%8d0", HighScore/10);
00384 repaint(rect(8, 1, s), FALSE);
00385 }
00386 }
00387
00388
00389
00390
00391
00392
00393
00394 void Score::setScore(int level, int player)
00395 {
00396 lastScore = -1;
00397
00398 if (player < 0 || player >= maxPlayer || level == 0) {
00399 if (level != 0)
00400 emit toggleNew();
00401 QTimer::singleShot(hallOfFameMS, this, SLOT(end()));
00402 return;
00403 }
00404
00405 lastPlayer = player;
00406
00407 for (int i = 0; i < 10; i++)
00408 if ( playerScore[lastPlayer] > hallOfFame[i].points) {
00409 lastScore = i;
00410 break;
00411 }
00412
00413 if (lastScore < 0) {
00414 emit toggleNew();
00415 QTimer::singleShot(hallOfFameMS, this, SLOT(end()));
00416 return;
00417 }
00418
00419 for (int i = 9; i > lastScore && i > 0; i--)
00420 hallOfFame[i] = hallOfFame[i-1];
00421
00422 hallOfFame[lastScore].points = playerScore[lastPlayer];
00423 hallOfFame[lastScore].levels = level;
00424 hallOfFame[lastScore].moment = QDateTime::currentDateTime();
00425 hallOfFame[lastScore].name = playerName[lastPlayer];
00426
00427 cursor.x = 14;
00428 cursor.y = 11+lastScore;
00429 cursor.chr = hallOfFame[lastScore].name.at(cursor.x-14);
00430
00431
00432 setFocus();
00433 }
00434
00435
00436
00437
00438
00439 void Score::read()
00440 {
00441 if (highscoreFile.exists() && highscoreFile.size() > 4) {
00442 if (highscoreFile.open(IO_ReadOnly)) {
00443 QDataStream s(&highscoreFile);
00444 char *name;
00445 for (int i = 0; i < 10; i++) {
00446 s >> hallOfFame[i].points >> hallOfFame[i].levels >> hallOfFame[i].duration >>
00447 hallOfFame[i].moment >> name;
00448 hallOfFame[i].name = QString::fromLatin1(name);
00449 delete(name);
00450 }
00451 highscoreFile.close();
00452 }
00453 } else {
00454 for (int i = 0; i < 10; i++) {
00455 hallOfFame[i].points = 5000;
00456 hallOfFame[i].levels = 0;
00457 hallOfFame[i].duration = QTime();
00458 hallOfFame[i].moment = QDateTime();
00459 hallOfFame[i].name = "???";
00460 }
00461
00462 }
00463
00464 for (int i = 0; i < 10; i++)
00465 for (uint j = 0; j < hallOfFame[i].name.length(); j++)
00466 if (hallOfFame[i].name.at(j) < bitfont->firstChar() ||
00467 hallOfFame[i].name.at(j) > bitfont->lastChar())
00468 hallOfFame[i].name.at(j) = hallOfFame[i].name.at(j).upper();
00469
00470 HighScore = hallOfFame[0].points;
00471 }
00472
00473 void Score::write()
00474 {
00475 if (highscoreFile.open(IO_WriteOnly)) {
00476 QDataStream s(&highscoreFile);
00477 for (int i = 0; i < 10; i++)
00478 s << hallOfFame[i].points << hallOfFame[i].levels << hallOfFame[i].duration <<
00479 hallOfFame[i].moment << hallOfFame[i].name.latin1();
00480 highscoreFile.close();
00481 }
00482 }
00483
00484 void Score::setPause(bool Paused)
00485 {
00486 paused = Paused;
00487
00488 QRect r = bitfont->rect(tr("PAUSED"));
00489 r.moveCenter(QPoint(this->width()/2, this->height()/2));
00490 repaint(r, TRUE);
00491
00492
00493 repaint(FALSE);
00494 }
00495
00496 void Score::end()
00497 {
00498 if (paused) {
00499 QTimer::singleShot(afterPauseMS, this, SLOT(end()));
00500 return;
00501 }
00502
00503
00504 lastPlayer = -1;
00505 repaint(FALSE);
00506
00507 emit forcedHallOfFame(FALSE);
00508 }
00509
00510
00511
00512
00513
00514 QString Score::formatDate(QDate date)
00515 {
00516 QString s = tr("@YY@/@MM@/@DD@");
00517
00518 QString dd;
00519 dd.sprintf("%02d", date.isValid() ? date.year() % 100 : 0);
00520 s.replace(QRegExp("@YY@"), dd);
00521 dd.sprintf("%02d", date.isValid() ? date.month() : 0);
00522 s.replace(QRegExp("@MM@"), dd);
00523 dd.sprintf("%02d", date.isValid() ? date.day() : 0);
00524 s.replace(QRegExp("@DD@"), dd);
00525
00526 return s;
00527 }
00528
00529 QRect Score::rect(int col, float row, QString str, int align)
00530 {
00531 QRect r = bitfont->rect(str);
00532 r.moveBy(x(col), y(row));
00533
00534 int dx = 0;
00535 int dy = 0;
00536
00537 if (align & AlignLeft || align & AlignRight) {
00538 dx = (str.length()-1) * (bitfont->width()/2);
00539 if (align & AlignRight)
00540 dx *= -1;
00541 }
00542
00543 if (align & AlignTop || align & AlignBottom) {
00544 dy = bitfont->height()/2;
00545 if (align & AlignBottom)
00546 dy *= -1;
00547 }
00548
00549 if (dx != 0 || dy != 0)
00550 r.moveBy(dx, dy);
00551
00552 return r;
00553 }
00554
00555 int Score::x(int col)
00556 {
00557 return col*bitfont->width();
00558 }
00559
00560 int Score::y(float row)
00561 {
00562 return (int) (row*(bitfont->height()+bitfont->height()/4));
00563 }
00564
00572 QFileInfo Score::locateHighscoreFilePath()
00573 {
00574 return privateHighscoreFileInfo;
00575 }