summaryrefslogtreecommitdiff
path: root/noncore/games/kpacman/score.cpp
Unidiff
Diffstat (limited to 'noncore/games/kpacman/score.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/games/kpacman/score.cpp642
1 files changed, 642 insertions, 0 deletions
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 @@
1
2#include "portable.h"
3
4#if defined( KDE2_PORT )
5#include <score.h>
6#include <score.moc>
7
8#include <kaccel.h>
9#include <kapp.h>
10#include <kconfig.h>
11#include <kstddirs.h>
12#include <kmessagebox.h>
13#elif defined( QPE_PORT )
14#include <qaccel.h>
15#include "config.h"
16#include "score.h"
17#endif
18
19#include <stdlib.h>
20#include <ctype.h>
21
22#include <qpixmap.h>
23#include <qstring.h>
24#include <qdstream.h>
25#include <qkeycode.h>
26#include <qtimer.h>
27#include <qfileinfo.h>
28
29#include "bitfont.h"
30
31Score::Score(QWidget *parent, const char *name, int Scheme, int Mode, Bitfont *font) : QWidget(parent, name)
32{
33 setFocusPolicy(QWidget::StrongFocus);
34
35 paused = FALSE;
36
37 lastScore = -1;
38 lastPlayer = -1;
39
40 cursorBlinkTimer = 0;
41 cursorBlinkMS = -1;
42 cursor.x = -1;
43 cursor.y = -1;
44 cursor.on = FALSE;
45 cursor.chr = QChar('?');
46
47 initKeys();
48
49 scheme = Scheme;
50 mode = Mode;
51 confScheme();
52
53 bitfont = font;
54
55 highscoreFile.setName(locateHighscoreFilePath().filePath());
56 read();
57
58 for (int p = 0; p < maxPlayer; p++) {
59 playerScore[p] = 0;
60 playerName[p] = getenv("LOGNAME");
61 if (playerName[p].length() < minPlayerNameLength)
62 playerName[p].setExpand(minPlayerNameLength-1, ' ');
63
64 for (uint i = 0; i < playerName[p].length(); i++)
65 if (playerName[p].at(i) < bitfont->firstChar() ||
66 playerName[p].at(i) > bitfont->lastChar())
67 playerName[p].at(i) = playerName[p].at(i).upper();
68 }
69}
70
71Score::~Score()
72{
73 // write();
74}
75
76void Score::paintEvent( QPaintEvent *e)
77{
78 if (rect(1, 0, i18n(" 1UP ")).intersects(e->rect())) {
79 QPixmap pix;
80 QColor fg = BLACK;
81 if (cursor.on || paused || lastPlayer != 0)
82 fg = WHITE;
83 pix = bitfont->text(i18n(" 1UP "), fg, BLACK);
84 bitBlt(this, x(1), y(0), &pix);
85 }
86
87 if (rect(8, 0, i18n(" HIGH SCORE ")).intersects(e->rect())) {
88 QPixmap pix = bitfont->text(i18n(" HIGH SCORE "), WHITE, BLACK);
89 bitBlt(this, x(8), y(0), &pix);
90 }
91
92 if (maxPlayer > 1 && rect(21, 0, i18n(" 2UP ")).intersects(e->rect())) {
93 QPixmap pix;
94 QColor fg = BLACK;
95 if (cursor.on || paused || lastPlayer != 1)
96 fg = WHITE;
97 pix = bitfont->text(i18n(" 2UP "), fg, BLACK);
98 bitBlt(this, x(21), y(0), &pix);
99 }
100
101 QString s;
102
103 s.sprintf("%6d0", playerScore[0]/10);
104 if (rect(0, 1, s).intersects(e->rect())) {
105 QPixmap pix = bitfont->text(s, WHITE, BLACK);
106 bitBlt(this, x(0), y(1), &pix);
107 }
108
109 s.sprintf("%8d0", HighScore/10);
110 if (rect(8, 1, s).intersects(e->rect())) {
111 QPixmap pix = bitfont->text(s, WHITE, BLACK);
112 bitBlt(this, x(8), y(1), &pix);
113 }
114
115 if (lastScore >= 0) {
116 if (rect(1, 4*1.25, i18n(" CONGRATULATIONS ")).intersects(e->rect())) {
117 QPixmap pix = bitfont->text(i18n(" CONGRATULATIONS "), YELLOW, BLACK);
118 bitBlt(this, x(1), y(4*1.25), &pix);
119 }
120 if (rect(1, 6*1.25, i18n(" YOU HAVE ARCHIEVED ")).intersects(e->rect())) {
121 QPixmap pix = bitfont->text(i18n(" YOU HAVE ARCHIEVED "), CYAN, BLACK);
122 bitBlt(this, x(1), y(6*1.25), &pix);
123 }
124 if (rect(1, 7*1.25, i18n(" A SCORE IN THE TOP 10. ")).intersects(e->rect())) {
125 QPixmap pix = bitfont->text(i18n(" A SCORE IN THE TOP 10. "), CYAN, BLACK);
126 bitBlt(this, x(1), y(7*1.25), &pix);
127 }
128 if (rect(1, 8*1.25, i18n(" ")).intersects(e->rect())) {
129 QPixmap pix = bitfont->text(i18n(" "), CYAN, BLACK);
130 bitBlt(this, x(1), y(8*1.25), &pix);
131 }
132 }
133
134 if (rect(1, 9.5*1.25, i18n("RNK SCORE NAME DATE")).intersects(e->rect())) {
135 QPixmap pix = bitfont->text(i18n("RNK SCORE NAME DATE"), WHITE, BLACK);
136 bitBlt(this, x(1), y(9.5*1.25), &pix);
137 }
138
139 for (int i = 0; i < 10; i++) {
140 s.sprintf("%2d%9d %-3.3s %-8.8s",
141 i+1, hallOfFame[i].points, hallOfFame[i].name.utf8().data(),
142 formatDate(hallOfFame[i].moment.date()).data());
143 if (rect(1, (11+i)*1.25, s).intersects(e->rect())) {
144 QPixmap pix = bitfont->text(s, (i == lastScore) ? YELLOW : WHITE, BLACK);
145 bitBlt(this, x(1), y((11+i)*1.25), &pix);
146 }
147 }
148
149 if (cursor.x != -1 && cursor.y != -1 && cursor.on) {
150 if (rect(cursor.x, (cursor.y*1.25), cursor.chr).intersects(e->rect())) {
151 QPixmap pix = bitfont->text(cursor.chr, BLACK, YELLOW);
152 bitBlt(this, x(cursor.x), y(cursor.y*1.25), &pix);
153 }
154 }
155
156 if (paused) {
157
158 QPixmap pix = bitfont->text(i18n("PAUSED"), RED, BLACK);
159 QRect r = bitfont->rect(i18n("PAUSED"));
160 r.moveCenter(QPoint(this->width()/2, this->height()/2));
161
162 bitBlt(this, r.x(), r.y(), &pix);
163 }
164}
165
166void Score::timerEvent(QTimerEvent*)
167{
168 cursor.on = !cursor.on;
169
170 if (paused)
171 return;
172
173 if (cursor.x != -1 && cursor.y != -1)
174 repaint(rect(cursor.x, cursor.y*1.25, cursor.chr), FALSE);
175 scrollRepeat = FALSE;
176
177 if (lastPlayer == 0)
178 repaint(rect(1, 0, i18n(" 1UP ")), FALSE);
179
180 if (lastPlayer == 1)
181 repaint(rect(21, 0, i18n(" 2UP ")), FALSE);
182}
183
184void Score::keyPressEvent(QKeyEvent *k)
185{
186 if (lastScore < 0 || lastPlayer < 0 || lastPlayer >= maxPlayer || paused) {
187 k->ignore();
188 return;
189 }
190
191 int x = cursor.x;
192 int y = cursor.y;
193
194 uint key = k->key();
195
196 if (scrollRepeat && (key == UpKey || key == Key_Up || key == DownKey || key == Key_Down)) {
197 k->ignore();
198 return;
199 }
200
201 if (key != Key_Return) {
202 if (key == RightKey || key == Key_Right)
203 if (++cursor.x > 16)
204 cursor.x = 14;
205 if (key == LeftKey || key == Key_Left)
206 if (--cursor.x < 14)
207 cursor.x = 16;
208 if (key == UpKey || key == Key_Up)
209 if (cursor.chr.unicode() < bitfont->lastChar())
210 cursor.chr = cursor.chr.unicode()+1;
211 else
212 cursor.chr = bitfont->firstChar();
213 if (key == DownKey || key == Key_Down)
214 if (cursor.chr.unicode() > bitfont->firstChar())
215 cursor.chr = cursor.chr.unicode()-1;
216 else
217 cursor.chr = bitfont->lastChar();
218
219 if (cursor.x == x && cursor.y == y &&
220 cursor.chr == hallOfFame[lastScore].name.at(cursor.x-14)) {
221 uint ascii = k->ascii();
222
223 if (ascii < bitfont->firstChar() || ascii > bitfont->lastChar())
224 ascii = toupper(ascii);
225
226 if (ascii >= bitfont->firstChar() && ascii <= bitfont->lastChar()) {
227 cursor.chr = ascii;
228 hallOfFame[lastScore].name.at(cursor.x-14) = cursor.chr;
229 if (++cursor.x > 16)
230 cursor.x = 14;
231 }
232 }
233 }
234
235 if (key == Key_Return) {
236 playerName[lastPlayer] = hallOfFame[lastScore].name;
237 write();
238 read();
239 lastScore = -1;
240 cursor.x = -1;
241 cursor.y = -1;
242// killTimers();
243 emit toggleNew();
244 end();
245 }
246
247 if (x != cursor.x || y != cursor.y) {
248 if (cursor.x != -1)
249 cursor.chr = hallOfFame[lastScore].name.at(cursor.x-14);
250 scrollRepeat = FALSE;
251 repaint(rect(x, y*1.25, cursor.chr), FALSE);
252 } else
253 hallOfFame[lastScore].name.at(cursor.x-14) = cursor.chr;
254
255 if (key == UpKey || key == Key_Up || key == DownKey || key == Key_Down)
256 scrollRepeat = TRUE;
257 else
258 repaint(rect(cursor.x, cursor.y*1.25, cursor.chr), FALSE);
259}
260
261void Score::initKeys()
262{
263 APP_CONFIG_BEGIN( cfg );
264 QString up("Up");
265 up = cfg->readEntry("upKey", (const char*) up);
266 UpKey = KAccel::stringToKey(up);
267
268 QString down("Down");
269 down = cfg->readEntry("downKey", (const char*) down);
270 DownKey = KAccel::stringToKey(down);
271
272 QString left("Left");
273 left = cfg->readEntry("leftKey", (const char*) left);
274 LeftKey = KAccel::stringToKey(left);
275
276 QString right("Right");
277 right = cfg->readEntry("rightKey", (const char*) right);
278 RightKey = KAccel::stringToKey(right);
279 APP_CONFIG_END( cfg );
280}
281
282void Score::confTiming(bool defGroup)
283{
284 APP_CONFIG_BEGIN( cfg );
285 if (defGroup || cfg->hasKey("CursorBlinkMS"))
286 cursorBlinkMS = cfg->readNumEntry("CursorBlinkMS", 250);
287 if (defGroup || cfg->hasKey("HallOfFameMS"))
288 hallOfFameMS = cfg->readNumEntry("HallOfFameMS", 7000);
289 if (defGroup || cfg->hasKey("AfterPauseMS"))
290 afterPauseMS = cfg->readNumEntry("AfterPauseMS", 1000);
291 APP_CONFIG_END( cfg );
292}
293
294void Score::confScheme()
295{
296 APP_CONFIG_BEGIN( cfg );
297 SAVE_CONFIG_GROUP( cfg, oldgroup );
298 QString newgroup;
299
300 // if not set, read mode and scheme from the configfile
301 if (mode == -1 && scheme == -1) {
302 scheme = cfg->readNumEntry("Scheme", -1);
303 mode = cfg->readNumEntry("Mode", -1);
304
305 // if mode is not set in the defGroup-group, lookup the scheme group
306 if (scheme != -1 || mode == -1) {
307 newgroup.sprintf("Scheme %d", scheme);
308 cfg->setGroup(newgroup);
309
310 mode = cfg->readNumEntry("Mode", -1);
311 RESTORE_CONFIG_GROUP( cfg, oldgroup );
312 }
313 }
314
315 int oldCursorBlinkMS = cursorBlinkMS;
316
317 confTiming();
318
319 if (mode != -1) {
320 newgroup.sprintf("Mode %d", mode);
321 cfg->setGroup(newgroup);
322
323 confTiming(FALSE);
324 }
325
326 if (scheme != -1) {
327 newgroup.sprintf("Scheme %d", scheme);
328 cfg->setGroup(newgroup);
329
330 confTiming(FALSE);
331 }
332
333 if (cursorBlinkMS != oldCursorBlinkMS) {
334 if (cursorBlinkTimer)
335 killTimer(cursorBlinkTimer);
336 cursorBlinkTimer = startTimer(cursorBlinkMS);
337 }
338
339 RESTORE_CONFIG_GROUP( cfg, oldgroup );
340 APP_CONFIG_END( cfg );
341}
342
343void Score::setScheme(int Scheme, int Mode, Bitfont *font)
344{
345 mode = Mode;
346 scheme = Scheme;
347
348 confScheme();
349
350 bitfont = font;
351
352 for (int p = 0; p < maxPlayer; p++)
353 for (uint i = 0; i < playerName[p].length(); i++)
354 if (playerName[p].at(i) < bitfont->firstChar() ||
355 playerName[p].at(i) > bitfont->lastChar())
356 playerName[p].at(i) = playerName[p].at(i).upper();
357
358 for (int i = 0; i < 10; i++)
359 for (uint j = 0; j < hallOfFame[i].name.length(); j++)
360 if (hallOfFame[i].name.at(j) < bitfont->firstChar() ||
361 hallOfFame[i].name.at(j) > bitfont->lastChar())
362 hallOfFame[i].name.at(j) = hallOfFame[i].name.at(j).upper();
363
364 if (cursor.chr.unicode() < bitfont->firstChar() ||
365 cursor.chr.unicode() > bitfont->lastChar())
366 cursor.chr = cursor.chr.upper();
367}
368
369void Score::set(int score)
370{
371 set(score, 0);
372}
373
374void Score::set(int score, int player)
375{
376 if (player < 0 || player >= maxPlayer)
377 return;
378
379 lastPlayer = player;
380 playerScore[lastPlayer] = score;
381
382 QString s;
383
384 s.sprintf("%6d0", playerScore[lastPlayer]/10);
385 repaint(rect(0, 1, s), FALSE);
386
387 if (score > HighScore) {
388 HighScore = score;
389 s.sprintf("%8d0", HighScore/10);
390 repaint(rect(8, 1, s), FALSE);
391 }
392}
393
394/*
395 * Set the score for player after the game if over. If the score is in the
396 * high scores then the hall of fame is updated (shifted) and the scoreboard
397 * is shown.
398 */
399
400void Score::setScore(int level, int player)
401{
402 lastScore = -1;
403
404 if (player < 0 || player >= maxPlayer || level == 0) {
405 if (level != 0)
406 emit toggleNew();
407 QTimer::singleShot(hallOfFameMS, this, SLOT(end()));
408 return;
409 }
410
411 lastPlayer = player;
412
413 for (int i = 0; i < 10; i++)
414 if ( playerScore[lastPlayer] > hallOfFame[i].points) {
415 lastScore = i;
416 break;
417 }
418
419 if (lastScore < 0) {
420 emit toggleNew();
421 QTimer::singleShot(hallOfFameMS, this, SLOT(end()));
422 return;
423 }
424
425 for (int i = 9; i > lastScore && i > 0; i--)
426 hallOfFame[i] = hallOfFame[i-1];
427
428 hallOfFame[lastScore].points = playerScore[lastPlayer];
429 hallOfFame[lastScore].levels = level;
430 hallOfFame[lastScore].moment = QDateTime::currentDateTime();
431 hallOfFame[lastScore].name = playerName[lastPlayer];
432
433 cursor.x = 14;
434 cursor.y = 11+lastScore;
435 cursor.chr = hallOfFame[lastScore].name.at(cursor.x-14);
436
437// startTimer(cursorBlinkMS);
438 setFocus();
439}
440
441/*
442 * Read the highscores, if no file or a file shorter than 4 bytes (versions before 0.2.4 stores only
443 * the points of one highscore) exists - the highscores were initialized with default values.
444 */
445void Score::read()
446{
447 if (highscoreFile.exists() && highscoreFile.size() > 4) {
448 if (highscoreFile.open(IO_ReadOnly)) {
449 QDataStream s(&highscoreFile);
450 char *name;
451 for (int i = 0; i < 10; i++) {
452 s >> hallOfFame[i].points >> hallOfFame[i].levels >> hallOfFame[i].duration >>
453 hallOfFame[i].moment >> name;
454 hallOfFame[i].name = QString::fromLatin1(name);
455 delete(name);
456 }
457 highscoreFile.close();
458 }
459 } else {
460 for (int i = 0; i < 10; i++) {
461 hallOfFame[i].points = 5000;
462 hallOfFame[i].levels = 0;
463 hallOfFame[i].duration = QTime();
464 hallOfFame[i].moment = QDateTime();
465 hallOfFame[i].name = "???";
466 }
467 // write();
468 }
469
470 for (int i = 0; i < 10; i++)
471 for (uint j = 0; j < hallOfFame[i].name.length(); j++)
472 if (hallOfFame[i].name.at(j) < bitfont->firstChar() ||
473 hallOfFame[i].name.at(j) > bitfont->lastChar())
474 hallOfFame[i].name.at(j) = hallOfFame[i].name.at(j).upper();
475
476 HighScore = hallOfFame[0].points;
477}
478
479void Score::write()
480{
481#ifndef QWS
482 if (!highscoreFile.exists() && highscoreFile.name() == systemHighscoreFileInfo.filePath())
483 KMessageBox::information(0,
484 i18n("You're going to create the highscore-file\n"
485 "'%1'\n"
486 "for your maschine, that should be used systemwide.\n"
487 "\n"
488 "To grant access to the other users, set the appropriate rights (a+w)\n"
489 "on that file or ask your systemadministator for that favor.\n"
490 "\n"
491 "To use a different directory or filename for the highscores,"
492 "specify them in the configfile (kpacmanrc:highscoreFilePath)."
493 ).arg(systemHighscoreFileInfo.filePath()));
494
495 if (highscoreFile.name() == privateHighscoreFileInfo.filePath())
496 KMessageBox::information(0,
497 i18n("You're using a private highscore-file, that's mostly because of\n"
498 "missing write-access to the systemwide file\n"
499 "'%1' .\n"
500 "\n"
501 "Ask your systemadministrator for granting you access to that file,\n"
502 "by setting the appropriate rights (a+w) on it.\n"
503 "\n"
504 "To use a different directory or filename for the highscores,"
505 "specify them in the configfile (kpacmanrc:highscoreFilePath)."
506 ).arg(systemHighscoreFileInfo.filePath()),
507 QString::null, "PrivateHighscore");
508#endif
509 if (highscoreFile.open(IO_WriteOnly)) {
510 QDataStream s(&highscoreFile);
511 for (int i = 0; i < 10; i++)
512 s << hallOfFame[i].points << hallOfFame[i].levels << hallOfFame[i].duration <<
513 hallOfFame[i].moment << hallOfFame[i].name.latin1();
514 highscoreFile.close();
515 }
516}
517
518void Score::setPause(bool Paused)
519{
520 paused = Paused;
521
522 QRect r = bitfont->rect(i18n("PAUSED"));
523 r.moveCenter(QPoint(this->width()/2, this->height()/2));
524 repaint(r, TRUE);
525
526 // repaint 1UP or 2UP
527 repaint(FALSE);
528}
529
530void Score::end()
531{
532 if (paused) {
533 QTimer::singleShot(afterPauseMS, this, SLOT(end()));
534 return;
535 }
536
537 // repaint 1UP or 2UP
538 lastPlayer = -1;
539 repaint(FALSE);
540
541 emit forcedHallOfFame(FALSE);
542}
543
544/*
545 * Return the date in a formatted QString. The format can be changed using internationalization
546 * of the string "YY/MM/DD". Invalid QDate's where returned as "00/00/00".
547 */
548QString Score::formatDate(QDate date)
549{
550 QString s = i18n("@YY@/@MM@/@DD@");
551
552 QString dd;
553 dd.sprintf("%02d", date.isValid() ? date.year() % 100 : 0);
554 s.replace(QRegExp("@YY@"), dd);
555 dd.sprintf("%02d", date.isValid() ? date.month() : 0);
556 s.replace(QRegExp("@MM@"), dd);
557 dd.sprintf("%02d", date.isValid() ? date.day() : 0);
558 s.replace(QRegExp("@DD@"), dd);
559
560 return s;
561}
562
563QRect Score::rect(int col, float row, QString str, int align)
564{
565 QRect r = bitfont->rect(str);
566 r.moveBy(x(col), y(row));
567
568 int dx = 0;
569 int dy = 0;
570
571 if (align & AlignLeft || align & AlignRight) {
572 dx = (str.length()-1) * (bitfont->width()/2);
573 if (align & AlignRight)
574 dx *= -1;
575 }
576
577 if (align & AlignTop || align & AlignBottom) {
578 dy = bitfont->height()/2;
579 if (align & AlignBottom)
580 dy *= -1;
581 }
582
583 if (dx != 0 || dy != 0)
584 r.moveBy(dx, dy);
585
586 return r;
587}
588
589int Score::x(int col)
590{
591 return col*bitfont->width();
592}
593
594int Score::y(float row)
595{
596 return (int) (row*(bitfont->height()+bitfont->height()/4));
597}
598
599/**
600 * Ermittelt die zu benutzende "highscore"-Datei, in die auch geschrieben werden kann.
601 * Über den "highscoreFilePath"-KConfig-Eintrag, kann abweichend von der Standardlokation
602 * der Standort der "highscore"-Datei spezifiziert werden.
603 * Wenn die systemweite "highscore"-Datei nicht beschrieben werden kann, wird mit einer
604 * privaten Datei gearbeitet.
605 */
606QFileInfo Score::locateHighscoreFilePath()
607{
608#ifndef QWS
609 QFileInfo systemHighscoreDirPath;
610 QStringList systemHighscoreDirs;
611
612 // Schreibfähige "private" highscore-Datei ermitteln für den fallback.
613 privateHighscoreFileInfo.setFile(KGlobal::dirs()->saveLocation("appdata")+highscoreName);
614
615 // FilePath aus der Konfigurationsdatei benutzen
616 systemHighscoreFileInfo.setFile(cfg->readEntry("HighscoreFilePath"));
617
618 // Kein Wert aus der Konfiguration erhalten, dann die "system"-Datei suchen.
619 if (systemHighscoreFileInfo.filePath().isEmpty())
620 systemHighscoreDirs = KGlobal::dirs()->resourceDirs("appdata");
621 else
622 systemHighscoreDirs = QStringList(systemHighscoreFileInfo.filePath());
623
624 for (QStringList::Iterator i = systemHighscoreDirs.begin(); i != systemHighscoreDirs.end(); ++i) {
625
626 systemHighscoreFileInfo.setFile(*i);
627 if (systemHighscoreFileInfo.fileName().isEmpty())
628 systemHighscoreFileInfo.setFile(systemHighscoreFileInfo.dirPath()+"/"+highscoreName);
629
630 // privateHighscoreFileInfo für die "system" Suche ignorieren
631 if (systemHighscoreFileInfo.filePath() != privateHighscoreFileInfo.filePath())
632 if (!systemHighscoreFileInfo.exists()) {
633 systemHighscoreDirPath.setFile(systemHighscoreFileInfo.dirPath());
634 if (systemHighscoreDirPath.exists() && systemHighscoreDirPath.isWritable())
635 return systemHighscoreFileInfo;
636 } else
637 if (systemHighscoreFileInfo.isWritable())
638 return systemHighscoreFileInfo;
639 }
640#endif
641 return privateHighscoreFileInfo;
642}