Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

wordgame.cpp

Go to the documentation of this file.
00001 /**********************************************************************
00002 ** Copyright (C) 2000 Trolltech AS.  All rights reserved.
00003 **
00004 ** This file is part of Qtopia Environment.
00005 **
00006 ** This file may be distributed and/or modified under the terms of the
00007 ** GNU General Public License version 2 as published by the Free Software
00008 ** Foundation and appearing in the file LICENSE.GPL included in the
00009 ** packaging of this file.
00010 **
00011 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00012 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00013 **
00014 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
00015 **
00016 ** Contact info@trolltech.com if any conditions of this licensing are
00017 ** not clear to you.
00018 **
00019 **********************************************************************/
00020 
00021 
00022 #include "wordgame.h"
00023 
00024 #include <opie2/oresource.h>
00025 
00026 #include <qpe/global.h>
00027 #include <qpe/config.h>
00028 
00029 #include <qapplication.h>
00030 #include <qmessagebox.h>
00031 #include <qcombobox.h>
00032 #include <qdir.h>
00033 #include <qlineedit.h>
00034 #include <qpushbutton.h>
00035 #include <qtextstream.h>
00036 #include <qtimer.h>
00037 #include <qtoolbar.h>
00038 #include <qtoolbutton.h>
00039 #include <qvbox.h>
00040 #include <qwidgetstack.h>
00041 #include <qlayout.h>
00042 
00043 #include <stdlib.h>
00044 #include <unistd.h>
00045 #include <pwd.h>
00046 #include <sys/types.h>
00047 
00048 enum RuleEffects {
00049     Multiplier=15,
00050     MultiplyAll=64,
00051     Start=128
00052 };
00053 
00054 static int tile_smallw = 16;
00055 static int tile_smallh = 16;
00056 static int tile_bigw = 22;
00057 static int tile_bigh = 22;
00058 static int tile_stweak = -2;
00059 static int tile_btweak = -1;
00060 
00061 static const int rack_tiles=7;
00062 
00063 const char* sampleWGR=
00064         "wordgame_shapes\n"
00065         "15 15\n"
00066         "400001040100004\n"
00067         "030000000000030\n"
00068         "002002000200200\n"
00069         "000300020003000\n"
00070         "000020000020000\n"
00071         "102001000100201\n"
00072         "000000202000000\n"
00073         "400200050002004\n"
00074         "000000202000000\n"
00075         "102001000100201\n"
00076         "000020000020000\n"
00077         "000300020003000\n"
00078         "002002000200200\n"
00079         "030000000000030\n"
00080         "400001040100004\n"
00081         "1 2 3 66 67 194 100 0\n"
00082         "1 j 8\n"
00083         "1 q 7\n"
00084         "1 x 6\n"
00085         "1 z 6\n"
00086         "1 w 4\n"
00087         "1 k 4\n"
00088         "1 v 3\n"
00089         "1 f 3\n"
00090         "2 y 3\n"
00091         "2 h 2\n"
00092         "2 b 2\n"
00093         "2 m 2\n"
00094         "3 p 2\n"
00095         "3 g 2\n"
00096         "3 u 2\n"
00097         "4 d 2\n"
00098         "4 c 2\n"
00099         "5 l 1\n"
00100         "5 o 1\n"
00101         "7 t 1\n"
00102         "7 n 1\n"
00103         "7 a 1\n"
00104         "7 r 1\n"
00105         "8 s 1\n"
00106         "8 i 1\n"
00107         "11 e 1\n"
00108         "0\n";
00109 
00110 WordGame::WordGame( QWidget* parent, const char* name, WFlags fl ) :
00111     QMainWindow(parent, name, fl)
00112 {
00113     if ( qApp->desktop()->width() < 240 ) {
00114         tile_smallw = 10;
00115         tile_smallh = 10;
00116         tile_bigw = 16;
00117         tile_bigh = 16;
00118         tile_stweak = 0;
00119         tile_btweak = 0;
00120     }
00121 
00122     setIcon( Opie::Core::OResource::loadPixmap( "wordgame/WordGame" ) );
00123     setCaption( tr("Word Game") );
00124 
00125     setToolBarsMovable( FALSE );
00126     vbox = new QVBox(this);
00127 
00128     setCentralWidget(vbox);
00129     toolbar = new QToolBar(this);
00130     addToolBar(toolbar, Bottom);
00131     bool useBigIcon = qApp->desktop()->size().width() > 330;
00132     reset = new QToolButton(Opie::Core::OResource::loadPixmap("back", Opie::Core::OResource::SmallIcon),
00133                             tr("Back"), "", this, SLOT(resetTurn()), toolbar);
00134     reset->setUsesBigPixmap( useBigIcon );
00135     done = new QToolButton(Opie::Core::OResource::loadPixmap("done", Opie::Core::OResource::SmallIcon),
00136                            tr("Done"), "", this, SLOT(endTurn()), toolbar);
00137     done->setUsesBigPixmap( useBigIcon );
00138     scoreinfo = new ScoreInfo(toolbar);
00139     scoreinfo->setFont(QFont("Helvetica",10));
00140     QToolButton *btn = new QToolButton(Opie::Core::OResource::loadPixmap("finish", Opie::Core::OResource::SmallIcon),
00141                                        tr("Close"), "", this, SLOT(endGame()), toolbar);
00142     btn->setUsesBigPixmap( useBigIcon );
00143     toolbar->setStretchableWidget(scoreinfo);
00144 
00145     cpu = 0;
00146     board = 0;
00147     bag = 0;
00148     racks = 0;
00149 
00150     aiheart = new QTimer(this);
00151     connect(aiheart, SIGNAL(timeout()), this, SLOT(think()));
00152 
00153     readConfig();
00154 }
00155 
00156 WordGame::~WordGame()
00157 {
00158     writeConfig();
00159 }
00160 
00161 void WordGame::writeConfig()
00162 {
00163     Config cfg("WordGame");
00164     cfg.setGroup("Game");
00165     cfg.writeEntry("NameList",namelist,';');
00166     cfg.writeEntry("CurrentPlayer",gameover ? 0 : player+1);
00167     if ( !gameover ) {
00168         cfg.writeEntry("Rules",rules);
00169         bag->writeConfig(cfg);
00170         board->writeConfig(cfg);
00171         scoreinfo->writeConfig(cfg);
00172     }
00173     for (int p=0; p<nplayers; p++) {
00174         cfg.setGroup("Player"+QString::number(p+1));
00175         if ( gameover ) cfg.clearGroup(); else rack(p)->writeConfig(cfg);
00176     }
00177 }
00178 
00179 void WordGame::readConfig()
00180 {
00181     Config cfg("WordGame");
00182     cfg.setGroup("Game");
00183     int currentplayer = cfg.readNumEntry("CurrentPlayer",0);
00184     QStringList pnames = cfg.readListEntry("NameList",';');
00185     if ( currentplayer ) {
00186         gameover = FALSE;
00187         rules = cfg.readEntry("Rules");
00188         if ( rules.find("x-wordgamerules") >= 0 ) {
00189             // rules files moved
00190             rules = "Sample.rules";
00191         }
00192         if ( loadRules(rules) ) {
00193             startGame(pnames);
00194             bag->readConfig(cfg);
00195             board->readConfig(cfg);
00196             scoreinfo->readConfig(cfg);
00197             for (int p=0; p<nplayers; p++) {
00198                 cfg.setGroup("Player"+QString::number(p+1));
00199                 rack(p)->readConfig(cfg);
00200             }
00201             player=currentplayer-1;
00202             readyRack(player);
00203             return;
00204         }
00205     }
00206     // fall-back
00207     openGameSelector(pnames);
00208 }
00209 
00210 void WordGame::openGameSelector(const QStringList& initnames)
00211 {
00212     toolbar->hide();
00213     gameover = FALSE;
00214 
00215     delete board;
00216     board = 0;
00217     delete racks;
00218     racks = 0;
00219 
00220     delete cpu;
00221     cpu = 0;
00222 
00223     newgame = new NewGame(vbox);
00224 
00225     //Rules rules(this);
00226     //connect(game.editrules, SIGNAL(clicked()), &rules, SLOT(editRules()));
00227     //connect(&rules, SIGNAL(rulesChanged()), &game, SLOT(updateRuleSets()));
00228     struct passwd* n = getpwuid(getuid());
00229     QString playername = n ? n->pw_name : "";
00230     if ( playername.isEmpty() ) {
00231         playername = "Player";
00232     }
00233     newgame->player0->changeItem(playername,0);
00234     newgame->player1->setCurrentItem(1);
00235     newgame->updateRuleSets();
00236     newgame->show();
00237 
00238     connect(newgame->buttonOk, SIGNAL(clicked()), this, SLOT(startGame()));
00239 }
00240 
00241 void WordGame::startGame()
00242 {
00243     rules = newgame->ruleslist[newgame->rules->currentItem()];
00244     if ( loadRules(rules) ) {
00245         QStringList names;
00246         names.append(newgame->player0->currentText());
00247         names.append(newgame->player1->currentText());
00248         names.append(newgame->player2->currentText());
00249         names.append(newgame->player3->currentText());
00250         names.append(newgame->player4->currentText());
00251         names.append(newgame->player5->currentText());
00252         delete newgame;
00253         startGame(names);
00254     } else {
00255         // error...
00256         delete newgame;
00257         close();
00258     }
00259 }
00260 
00261 void WordGame::startGame(const QStringList& playerlist)
00262 {
00263     toolbar->show();
00264     racks = new QWidgetStack(vbox);
00265     racks->setFixedHeight(TileItem::bigHeight()+2);
00266     namelist.clear();
00267     nplayers=0;
00268     for (QStringList::ConstIterator it=playerlist.begin(); it!=playerlist.end(); ++it)
00269         addPlayer(*it);
00270     scoreinfo->init(namelist);
00271 
00272     if ( nplayers ) {
00273         player=0;
00274         readyRack(player);
00275     }
00276 
00277     board->show();
00278     racks->show();
00279 }
00280 
00281 bool WordGame::loadRules(const QString &name)
00282 {
00283     QString filename = Global::applicationFileName( "wordgame", name );
00284     QFile file( filename );
00285     if ( !file.open( IO_ReadOnly ) )
00286         return FALSE;
00287 
00288     QTextStream ts( &file );
00289 
00290     QString title = name;
00291     title.truncate( title.length() - 6 );
00292     //setCaption( title );
00293 
00294     QString shapepixmap;
00295     ts >> shapepixmap;
00296     int htiles,vtiles;
00297     ts >> htiles >> vtiles;
00298 
00299     if ( htiles < 3 || vtiles < 3 )
00300         return FALSE;
00301 
00302     QString rule_shapes;
00303     for (int i=0; i<vtiles; i++) {
00304         QString line;
00305         ts >> line;
00306         rule_shapes += line;
00307     }
00308     static int rule_effects[12];
00309     int re=0,e;
00310     ts >> e;
00311     while ( e && re < 10 ) {
00312         rule_effects[re] = e;
00313         if ( re++ < 10 ) ts >> e;
00314     }
00315 
00316     QImage shim = Opie::Core::OResource::loadImage("wordgame/wordgame_shapes");
00317     shim = shim.smoothScale((re-1)*TileItem::smallWidth(),TileItem::smallHeight());
00318     QPixmap bgshapes;
00319     bgshapes.convertFromImage(shim);
00320 
00321     rule_effects[re++] = 100; // default bonus
00322     board = new Board(bgshapes, htiles, vtiles, vbox);
00323     board->setRules(rule_shapes, rule_effects);
00324     connect(board, SIGNAL(temporaryScore(int)), scoreinfo, SLOT(showTemporaryScore(int)));
00325 
00326     bag = new Bag;
00327 
00328     int count;
00329     ts >> count;
00330     while ( count ) {
00331         QString text;
00332         int value;
00333         ts >> text >> value;
00334         if ( text == "_" )
00335             text = "";
00336 
00337         Tile t(text, value);
00338         for (int n=count; n--; )
00339             bag->add(t);
00340 
00341         ts >> count;
00342     }
00343 
00344     return TRUE;
00345 }
00346 
00347 
00348 NewGame::NewGame(QWidget* parent) :
00349     NewGameBase(parent)
00350 {
00351 }
00352 
00353 void NewGame::updateRuleSets()
00354 {
00355     rules->clear();
00356 
00357     QString rulesDir = Global::applicationFileName( "wordgame", "" );
00358     QDir dir( rulesDir, "*.rules" );
00359     ruleslist = dir.entryList();
00360     if ( ruleslist.isEmpty() ) {
00361         // Provide a sample
00362         QFile file( rulesDir + "Sample.rules" );
00363         if ( file.open( IO_WriteOnly ) ) {
00364             file.writeBlock( sampleWGR, strlen(sampleWGR) );
00365             file.close();
00366             updateRuleSets();
00367         }
00368         return;
00369     }
00370     int newest=0;
00371     int newest_age=INT_MAX;
00372     QDateTime now = QDateTime::currentDateTime();
00373     QStringList::Iterator it;
00374     for ( it = ruleslist.begin(); it != ruleslist.end(); ++it ) {
00375         QFileInfo fi((*it));
00376         int age = fi.lastModified().secsTo(now);
00377         QString name = *it;
00378         name.truncate( name.length()-6 ); // remove extension
00379         rules->insertItem( name );
00380         if ( age < newest_age ) {
00381             newest_age = age;
00382             newest = rules->count()-1;
00383         }
00384     }
00385     rules->setCurrentItem(newest);
00386 }
00387 
00388 Rules::Rules(QWidget* parent) :
00389     RulesBase(parent,0,TRUE)
00390 {
00391 }
00392 
00393 void Rules::editRules()
00394 {
00395     if ( exec() ) {
00396         // ### create a new set of rules
00397         emit rulesChanged();
00398     }
00399 }
00400 
00401 void Rules::deleteRuleSet()
00402 {
00403     // ### delete existing rule set
00404     emit rulesChanged();
00405 }
00406 
00407 void WordGame::addPlayer(const QString& name)
00408 {
00409     if ( !name.isEmpty() ) {
00410         int colon = name.find(':');
00411         int cpu = (colon >=0 && name.left(2) == "AI") ? name.mid(2,1).toInt() : 0;
00412         addPlayer(name,cpu);
00413     }
00414 }
00415 
00416 void WordGame::addPlayer(const QString& name, int cpu)
00417 {
00418     Rack* r = new Rack(rack_tiles,racks);
00419     r->setPlayerName(name);
00420     r->setComputerization(cpu);
00421     racks->addWidget(r, nplayers);
00422     refillRack(nplayers);
00423     namelist.append(name);
00424 
00425     ++nplayers;
00426 }
00427 
00428 void WordGame::nextPlayer()
00429 {
00430     if ( !refillRack(player) ) {
00431         endGame();
00432     } else {
00433         player = (player+1)%nplayers;
00434         scoreinfo->setBoldOne(player);
00435         readyRack(player);
00436     }
00437 }
00438 
00439 bool WordGame::mayEndGame()
00440 {
00441     int out=-1;
00442     int i;
00443     for (i=0; i<nplayers; i++)
00444         if ( !rack(i)->count() )
00445             out = i;
00446     if ( out<0 ) {
00447         if ( QMessageBox::warning(this,tr("End game"),
00448                                   tr("Do you want to end the game early?"), 
00449                                   tr("Yes"), tr("No") )!=0 )
00450         {
00451             return FALSE;
00452         }
00453     }
00454     return TRUE;
00455 }
00456 
00457 void WordGame::endGame()
00458 {
00459     if ( gameover ) {
00460         close();
00461         return;
00462     }
00463 
00464     if ( !mayEndGame() )
00465         return;
00466     int out=-1;
00467     int totalleft=0;
00468     int i;
00469     for (i=0; i<nplayers; i++) {
00470         Rack* r = rack(i);
00471         int c = r->count();
00472         if ( c ) {
00473             int lose=0;
00474             for ( int j=0; j<c; j++ )
00475                 lose += r->tileRef(j)->value();
00476             totalleft += lose;
00477             scoreinfo->addScore(i,-lose);
00478         } else {
00479             out = i;
00480         }
00481     }
00482     int highest=0;
00483     int winner=0;
00484     for (i=0; i<nplayers; i++) {
00485         int s = scoreinfo->playerScore(i);
00486         if ( s > highest ) {
00487             highest = s;
00488             winner = i;
00489         }
00490     }
00491     if ( out >= 0 )
00492         scoreinfo->addScore(out,totalleft);
00493     scoreinfo->setBoldOne(winner);
00494     gameover = TRUE;
00495     done->setEnabled(TRUE);
00496     reset->setEnabled(FALSE);
00497 }
00498 
00499 void WordGame::endTurn()
00500 {
00501     if ( gameover ) {
00502         openGameSelector(namelist);
00503     } else {
00504         if ( board->checkTurn() ) {
00505             if ( board->turnScore() >= 0 ) {
00506                 scoreinfo->addScore(player,board->turnScore());
00507                 board->finalizeTurn();
00508             } else {
00509                 QApplication::beep();
00510             }
00511             nextPlayer();
00512         }
00513     }
00514 }
00515 
00516 void WordGame::resetTurn()
00517 {
00518     board->resetRack();
00519 }
00520 
00521 void WordGame::passTurn()
00522 {
00523     // ######## trade?
00524     nextPlayer();
00525 }
00526 
00527 bool WordGame::refillRack(int i)
00528 {
00529     Rack* r = rack(i);
00530     while ( !bag->isEmpty() && !r->isFull() ) {
00531         r->addTile(bag->takeRandom());
00532     }
00533     return r->count() != 0;
00534 }
00535 
00536 void WordGame::readyRack(int i)
00537 {
00538     Rack* r = rack(i);
00539     racks->raiseWidget(i);
00540     board->setCurrentRack(r);
00541 
00542     done->setEnabled( !r->computerized() );
00543     reset->setEnabled( !r->computerized() );
00544 
00545     if ( r->computerized() ) {
00546         cpu = new ComputerPlayer(board, r);
00547         aiheart->start(0);
00548     }
00549 }
00550 
00551 Rack* WordGame::rack(int i) const
00552 {
00553     return (Rack*)racks->widget(i);
00554 }
00555 
00556 void WordGame::think()
00557 {
00558     if ( !cpu->step() ) {
00559         delete cpu;
00560         cpu = 0;
00561         aiheart->stop();
00562         if ( board->turnScore() < 0 )
00563             passTurn();
00564         else
00565             endTurn();
00566     }
00567 }
00568 
00569 ComputerPlayer::ComputerPlayer(Board* b, Rack* r) :
00570     board(b), rack(r), best(new const Tile*[rack_tiles]),
00571         best_blankvalues(new Tile[rack_tiles])
00572 {
00573     best_score = -1;
00574     across=FALSE;
00575     dict=0;
00576 }
00577 
00578 ComputerPlayer::~ComputerPlayer()
00579 {
00580     delete [] best;
00581     delete [] best_blankvalues;
00582 }
00583 
00584 bool ComputerPlayer::step()
00585 {
00586     const QDawg::Node* root = dict ? Global::dawg("WordGame").root()
00587                                 : Global::fixedDawg().root();
00588     QPoint d = across ? QPoint(1,0) : QPoint(0,1);
00589     const Tile* tiles[99]; // ### max board size
00590     uchar nletter[4095]; // QDawg only handles 0..4095
00591     memset(nletter,0,4096);
00592     for (int i=0; i<rack->count(); i++) {
00593         const Tile* r = rack->tileRef(i);
00594         if ( r->isBlank() )
00595             nletter[0]++;
00596         else
00597             nletter[r->text()[0].unicode()]++;
00598     }
00599     Tile blankvalues[99]; // ### max blanks
00600     findBest(current, d, root, 0, nletter, tiles, 0, blankvalues, 0);
00601     if ( ++current.rx() == board->xTiles() ) {
00602         current.rx() = 0;
00603         if ( ++current.ry() == board->yTiles() ) {
00604             if ( across ) {
00605                 if ( dict == 1 ) {
00606                     if ( best_score >= 0 ) {
00607                         rack->arrangeTiles(best,best_n);
00608                         rack->setBlanks(best_blankvalues);
00609                         board->scoreTurn(best_start, best_n, best_dir);
00610                         board->showTurn();
00611                     }
00612                     return FALSE;
00613                 }
00614                 dict++;
00615                 across = FALSE;
00616                 current = QPoint(0,0);
00617             } else {
00618                 across = TRUE;
00619                 current = QPoint(0,0);
00620             }
00621         }
00622     }
00623     return TRUE;
00624 }
00625 
00626 void ComputerPlayer::findBest(QPoint at, const QPoint& d, const QDawg::Node* node, ulong used, uchar* nletter, const Tile** tiles, int n, Tile* blankvalues, int blused)
00627 {
00628     if ( !node )
00629         return;
00630     QChar l = node->letter();
00631     const Tile* cur = board->tile(at);
00632     if ( cur ) {
00633         if ( cur->text()[0] == l ) {
00634             bool nextok =  board->contains(at+d);
00635             if ( node->isWord() && n && (!nextok || !board->tile(at+d)) )
00636                 noteChoice(tiles,n,d,blankvalues,blused);
00637             if ( nextok )
00638                 findBest(at+d, d, node->jump(), used, nletter, tiles, n, blankvalues, blused);
00639             // #### text()[1]...
00640         }
00641     } else {
00642         if ( nletter[l.unicode()] || nletter[0] ) {
00643             int rc = rack->count();
00644             ulong msk = 1;
00645             for ( int x=0; x<rc; x++ ) {
00646                 if ( !(used&msk) ) {
00647                     const Tile* t = rack->tileRef(x);
00648                     if ( t->isBlank() || t->text() == l ) { // #### multi-char value()s
00649                         bool nextok =  board->contains(at+d);
00650                         tiles[n++] = t;
00651                         if ( t->isBlank() )
00652                             blankvalues[blused++] = Tile(l,0);
00653                         if ( node->isWord() && (!nextok || !board->tile(at+d)) )
00654                             noteChoice(tiles,n,d,blankvalues,blused);
00655                         used |= msk; // mark
00656                         nletter[t->text()[0].unicode()]--;
00657                         if ( nextok )
00658                             findBest(at+d, d, node->jump(), used, nletter, tiles, n, blankvalues, blused);
00659                         n--;
00660                         nletter[t->text()[0].unicode()]++;
00661                         if ( t->isBlank() ) {
00662                             // keep looking
00663                             blused--;
00664                             used &= ~msk; // unmark
00665                         } else {
00666                             break;
00667                         }
00668                     }
00669                 }
00670                 msk <<= 1;
00671             }
00672         }
00673         // #### text()[1]...
00674     }
00675     findBest(at, d, node->next(), used, nletter, tiles, n, blankvalues, blused);
00676 }
00677 
00678 void ComputerPlayer::noteChoice(const Tile** tiles, int n, const QPoint& d, const Tile* blankvalues, int blused)
00679 {
00680     int s = board->score(current, tiles, n, blankvalues, d, TRUE, 0);
00681 /*
00682 if (s>0 || current==QPoint(5,1)){
00683 QString st;
00684 for ( int i=0; i<n; i++ )
00685     st += tiles[i]->text();
00686 odebug << "" << current.x() << "," << current.y() << ": " << st.latin1() << " (" << n << ") for " << s << "" << oendl; 
00687 }
00688 */
00689     if ( s > best_score ) {
00690         int i;
00691         for ( i=0; i<n; i++ )
00692             best[i] = tiles[i];
00693         for ( i=0; i<blused; i++ )
00694             best_blankvalues[i] = blankvalues[i];
00695         best_n = n;
00696         best_blused = blused;
00697         best_score = s;
00698         best_dir = d;
00699         best_start = current;
00700     }
00701 }
00702 
00703 int TileItem::smallWidth()
00704 {
00705     return tile_smallw;
00706 }
00707 
00708 int TileItem::smallHeight()
00709 {
00710     return tile_smallh;
00711 }
00712 
00713 int TileItem::bigWidth()
00714 {
00715     return tile_bigw;
00716 }
00717 
00718 int TileItem::bigHeight()
00719 {
00720     return tile_bigh;
00721 }
00722 
00723 void TileItem::setState( State state )
00724 {
00725     hide();
00726     s = state;
00727     show(); // ### use update() in Qt 3.0
00728 }
00729 
00730 void TileItem::setTile(const Tile& tile)
00731 {
00732     hide();
00733     t = tile;
00734     show(); // ### use update() in Qt 3.0
00735 }
00736 
00737 void TileItem::setBig(bool b)
00738 {
00739     big = b;
00740 }
00741 
00742 void TileItem::drawShape(QPainter& p)
00743 {
00744     static QFont *value_font=0;
00745     static QFont *big_font=0;
00746     static QFont *small_font=0;
00747     if ( !value_font ) {
00748         value_font = new QFont("helvetica",8);
00749         if ( TileItem::bigWidth() < 20 ) {
00750             big_font = new QFont("helvetica",12);
00751             small_font = new QFont("helvetica",8);
00752         } else {
00753             big_font = new QFont("smoothtimes",17);
00754             small_font = new QFont("smoothtimes",10);
00755         }
00756     }
00757 
00758     QRect area(x(),y(),width(),height());
00759     p.setBrush(s == Floating ? yellow/*lightGray*/ : white);
00760     p.drawRect(area);
00761     if ( big ) {
00762         p.setFont(*value_font);
00763         QString n = QString::number(t.value());
00764         int w = p.fontMetrics().width('1');
00765         int h = p.fontMetrics().height();
00766         w *= n.length();
00767         QRect valuearea(x()+width()-w-1,y()+height()-h,w,h);
00768         p.drawText(valuearea,AlignCenter,n);
00769         p.setFont(*big_font);
00770         area = QRect(x(),y()+tile_btweak,width()-4,height()-1);
00771     } else {
00772         p.setFont(*small_font);
00773         area = QRect(x()+1+tile_stweak,y()+1,width(),height()-3);
00774     }
00775     if ( t.value() == 0 )
00776         p.setPen(darkGray);
00777     p.drawText(area,AlignCenter,t.text().upper());
00778 }
00779 
00780 Board::Board(QPixmap bgshapes, int w, int h, QWidget* parent) :
00781     QCanvasView(new QCanvas(bgshapes,w,h, TileItem::smallWidth(), TileItem::smallHeight()),
00782                 parent)
00783 {
00784     setFixedSize(w*TileItem::smallWidth(),h*TileItem::smallHeight());
00785     grid = new TileItem*[w*h];
00786     memset(grid,0,w*h*sizeof(TileItem*));
00787     setFrameStyle(0);
00788     setHScrollBarMode(AlwaysOff);
00789     setVScrollBarMode(AlwaysOff);
00790     current_rack = 0;
00791     shown_n = 0;
00792 }
00793 
00794 Board::~Board()
00795 {
00796     delete canvas();
00797 }
00798 
00799 QSize Board::sizeHint() const
00800 {
00801     return QSize(canvas()->width(),canvas()->height());
00802 }
00803 
00804 void Board::writeConfig(Config& cfg)
00805 {
00806     QStringList t;
00807     int n=canvas()->tilesHorizontally()*canvas()->tilesVertically();
00808     for (int i=0; i<n; i++)
00809         t.append( grid[i] ? grid[i]->tile().key() : QString(".") );
00810     cfg.writeEntry("Board",t,';');
00811 }
00812 
00813 void Board::readConfig(Config& cfg)
00814 {
00815     clear();
00816     QStringList t = cfg.readListEntry("Board",';');
00817     int i=0;
00818     int h=canvas()->tilesHorizontally();
00819     for (QStringList::ConstIterator it=t.begin(); it!=t.end(); ++it) {
00820         if ( *it != "." ) {
00821             QPoint p(i%h,i/h);
00822             setTile(p,Tile(*it));
00823         }
00824         i++;
00825     }
00826     canvas()->update();
00827 }
00828 
00829 void Board::clear()
00830 {
00831     int n=canvas()->tilesHorizontally()*canvas()->tilesVertically();
00832     for (int i=0; i<n; i++) {
00833         delete grid[i];
00834         grid[i]=0;
00835     }
00836 }
00837 
00838 
00839 void Board::setCurrentRack(Rack* r)
00840 {
00841     turn_score = -1;
00842     current_rack = r;
00843 }
00844 
00845 void Board::resetRack()
00846 {
00847     unshowTurn();
00848     canvas()->update();
00849 }
00850 
00851 void Board::contentsMousePressEvent(QMouseEvent* e)
00852 {
00853     dragstart = e->pos();
00854 }
00855 
00856 void Board::contentsMouseMoveEvent(QMouseEvent* e)
00857 {
00858     if ( current_rack && !current_rack->computerized() ) {
00859         QPoint d = e->pos() - dragstart;
00860         if ( d.x() <= 0 && d.y() <= 0 ) {
00861             // None
00862             resetRack();
00863         } else {
00864             int n;
00865             QPoint start=boardPos(dragstart);
00866             QPoint end=boardPos(e->pos());
00867             QPoint diff=end-start;
00868             QPoint dir;
00869             if ( d.x() > d.y() ) {
00870                 n = diff.x()+1;
00871                 dir = QPoint(1,0);
00872             } else {
00873                 n = diff.y()+1;
00874                 dir = QPoint(0,1);
00875             }
00876 
00877             unshowTurn();
00878 
00879             // Subtract existing tiles from n
00880             QPoint t = start;
00881             for ( int i=n; i--; ) {
00882                 if ( contains(t) && tile(t) )
00883                     n--;
00884                 t += dir;
00885             }
00886 
00887             // Move start back to real start
00888             while (contains(start-dir) && tile(start-dir))
00889                 start -= dir;
00890 
00891             scoreTurn(start, n, dir);
00892             showTurn();
00893         }
00894     }
00895 }
00896 
00897 void Board::finalizeTurn()
00898 {
00899     int i=0;
00900     QPoint at = shown_at;
00901     while ( i<shown_n && contains(at) ) {
00902         if ( item(at) && item(at)->state() == TileItem::Floating ) {
00903             current_rack->remove(item(at)->tile());
00904             setTileState(at,TileItem::Firm);
00905             i++;
00906         }
00907         at += shown_step;
00908     }
00909     canvas()->update();
00910 }
00911 
00912 void Board::unshowTurn()
00913 {
00914     int i=0;
00915     QPoint at = shown_at;
00916     while ( i<shown_n && i<current_rack->count() && contains(at) ) {
00917         if ( item(at) && item(at)->state() == TileItem::Floating ) {
00918             unsetTile(at);
00919             i++;
00920         }
00921         at += shown_step;
00922     }
00923 }
00924 
00925 void Board::showTurn()
00926 {
00927     unshowTurn();
00928     QPoint at = shown_at;
00929     int i=0;
00930     while ( i<shown_n && i<current_rack->count() && contains(at) ) {
00931         if ( !tile(at) ) {
00932             Tile t = current_rack->tile(i);
00933             setTile(at,t);
00934             setTileState(at,TileItem::Floating);
00935             i++;
00936         }
00937         at += shown_step;
00938     }
00939     canvas()->update();
00940 }
00941 
00942 int Board::bonussedValue(const QPoint& at, int base, int& all_mult) const
00943 {
00944     int rule = rule_shape[idx(at)]-'0';
00945     int effect = rule_effect[rule];
00946     int mult = effect&Multiplier;
00947     if ( effect & MultiplyAll ) {
00948         all_mult *= mult;
00949         return base;
00950     } else {
00951         return base * mult;
00952     }
00953 }
00954 
00955 bool Board::isStart(const QPoint& at) const
00956 {
00957     int rule = rule_shape[idx(at)]-'0';
00958     int effect = rule_effect[rule];
00959     return effect&Start;
00960 }
00961 
00962 bool Board::checkTurn()
00963 {
00964     if ( current_rack->computerized() )
00965         return TRUE; // computer doesn't cheat, and has already set blanks.
00966 
00967     QPoint at = shown_at;
00968     int n = shown_n;
00969     QPoint d = shown_step;
00970     const Tile* tiles[99];
00971     Tile blankvalues[99];
00972     if ( n > current_rack->count() )
00973         n = current_rack->count();
00974 
00975     QDialog check(this,0,TRUE);
00976     (new QVBoxLayout(&check))->setAutoAdd(TRUE);
00977 
00978     QHBox mw(&check);
00979     new QLabel(tr("Blanks: "),&mw);
00980 
00981     int bl=0;
00982     QLineEdit* le[99];
00983     for (int i=0; i<n; i++) {
00984         tiles[i] = current_rack->tileRef(i);
00985         if ( tiles[i]->isBlank() ) {
00986             QLineEdit *l = new QLineEdit(&mw);
00987             le[bl++] = l;
00988             l->setMaxLength(1);
00989             l->setFixedSize(l->minimumSizeHint());
00990         }
00991     }
00992 
00993     QHBox btns(&check);
00994     connect(new QPushButton(tr("OK"),&btns), SIGNAL(clicked()), &check, SLOT(accept()));
00995     connect(new QPushButton(tr("Cancel"),&btns), SIGNAL(clicked()), &check, SLOT(reject()));
00996 
00997     if ( bl ) {
00998 retry:
00999         if ( !check.exec() ) {
01000             unshowTurn();
01001             canvas()->update();
01002             return FALSE;
01003         }
01004 
01005         for (int b=0; b<bl; b++) {
01006             QString v = le[b]->text();
01007             blankvalues[b]=Tile(v,0);
01008             if ( v.length() != 1 )
01009                 goto retry;
01010         }
01011     }
01012 
01013     QStringList words;
01014     unshowTurn();
01015     turn_score = score(at,tiles,n,blankvalues,d,FALSE,&words);
01016     showTurn();
01017     QStringList to_add;
01018     for (QStringList::Iterator it=words.begin(); it!=words.end(); ++it) {
01019         if ( !Global::fixedDawg().contains(*it)
01020                 && !Global::dawg("WordGame").contains(*it) ) {
01021             switch (QMessageBox::warning(this, tr("Unknown word"),
01022                 tr("<p>The word \"%1\" is not in the dictionary.").arg(*it),
01023                 tr("Add"), tr("Ignore"), tr("Cancel")))
01024             {
01025             case 0:
01026                 // ####### add to wordgame dictionary
01027                 to_add.append(*it);
01028                 break;
01029             case 1:
01030                 break;
01031             case 2:
01032                 unshowTurn();
01033                 canvas()->update();
01034                 return FALSE;
01035             }
01036         }
01037     }
01038     if ( to_add.count() )
01039         Global::addWords("WordGame",to_add);
01040     return TRUE;
01041 }
01042 
01043 void Board::scoreTurn(const QPoint& at, int n, const QPoint& d)
01044 {
01045     unshowTurn();
01046     shown_at = at;
01047     shown_n = n;
01048     shown_step = d;
01049     const Tile* tiles[99];
01050     if ( n > current_rack->count() )
01051         n = current_rack->count();
01052     for (int i=0; i<n; i++)
01053         tiles[i] = current_rack->tileRef(i);
01054     turn_score = score(at,tiles,n,0,d,FALSE,0);
01055     emit temporaryScore(turn_score);
01056 }
01057 
01058 int Board::score(QPoint at, const Tile** tiles, int n, const Tile* blankvalue, const QPoint& d, bool checkdict, QStringList* words) const
01059 {
01060     int total=0;
01061     int totalsidetotal=0;
01062 
01063     // words gets filled with words made
01064 
01065     // mainword==0 ->
01066     // Checks side words, but not main word
01067 
01068     // -1 means words not in dict, or illegally positioned (eg. not connected)
01069 
01070     // text is assumed to fit on board.
01071 
01072     if ( words ) *words=QStringList();
01073 
01074     QPoint otherd(d.y(), d.x());
01075 
01076     int all_mult = 1;
01077     int bl=0;
01078 
01079     bool connected = FALSE;
01080 
01081     QString mainword="";
01082 
01083     if ( contains(at-d) && tile(at-d) ) {
01084         return -1; // preceeding tiles
01085     }
01086 
01087     const Tile* t;
01088     for (int i=0; contains(at) && ((t=tile(at)) || i<n); ) {
01089         if ( t ) {
01090             if ( checkdict || words ) mainword += t->text();
01091             total += t->value();
01092             connected = TRUE;
01093         } else {
01094             QString sideword;
01095             QString tt;
01096             if ( tiles[i]->isBlank() ) {
01097                 if ( blankvalue )
01098                     tt = blankvalue[bl++].text();
01099             } else {
01100                 tt = tiles[i]->text();
01101             }
01102             sideword=tt;
01103             if ( checkdict || words ) mainword += tt;
01104             int side_mult = 1;
01105             int tilevalue = bonussedValue(at,tiles[i]->value(),side_mult);
01106             all_mult *= side_mult;
01107             if ( !connected && isStart(at) )
01108                 connected = TRUE;
01109             total += tilevalue;
01110             int sidetotal = tilevalue;
01111             {
01112                 QPoint side = at-otherd;
01113                 
01114                 while ( contains(side) && (t=tile(side)) ) {
01115                     sidetotal += t->value();
01116                     sideword.prepend(t->text());
01117                     side -= otherd;
01118                 }
01119             }
01120             {
01121                 QPoint side = at+otherd;
01122                 while ( contains(side) && (t=tile(side)) ) {
01123                     sidetotal += t->value();
01124                     sideword.append(t->text());
01125                     side += otherd;
01126                 }
01127             }
01128             if ( sideword.length() > 1 ) {
01129                 if ( words )
01130                     words->append(sideword);
01131                 if ( checkdict && !Global::fixedDawg().contains(sideword)
01132                                && !Global::dawg("WordGame").contains(sideword) )
01133                     return -1;
01134                 totalsidetotal += sidetotal * side_mult;
01135                 connected = TRUE;
01136             }
01137             i++;
01138         }
01139         at += d;
01140     }
01141 
01142     if ( words )
01143         words->append(mainword);
01144     if ( checkdict && !Global::fixedDawg().contains(mainword)
01145                    && !Global::dawg("WordGame").contains(mainword) )
01146         return -1;
01147 
01148     if ( n == rack_tiles )
01149         totalsidetotal += rack_tiles_bonus;
01150 
01151     return connected ? totalsidetotal + total * all_mult : -1;
01152 }
01153 
01154 QPoint Board::boardPos(const QPoint& p) const
01155 {
01156     return QPoint(p.x()/canvas()->tileWidth(), p.y()/canvas()->tileHeight());
01157 }
01158 
01159 void Board::contentsMouseReleaseEvent(QMouseEvent*)
01160 {
01161     if ( current_rack ) {
01162     }
01163 }
01164 
01165 
01166 void Board::setRules(const QString& shapes, const int* effects)
01167 {
01168     rule_shape=shapes; rule_effect=effects;
01169     int i=0;
01170     int maxre=0;
01171     for (int y=0; y<yTiles(); y++) {
01172         for (int x=0; x<xTiles(); x++) {
01173             int re = shapes[i++]-'0';
01174             if ( re > maxre ) maxre = re;
01175             canvas()->setTile(x,y,re);
01176         }
01177     }
01178     rack_tiles_bonus=effects[maxre+1];
01179 }
01180 
01181 void Board::unsetTile(const QPoint& p)
01182 {
01183     delete item(p);
01184     grid[idx(p)] = 0;
01185 }
01186 
01187 void Board::setTile(const QPoint& p, const Tile& t)
01188 {
01189     TileItem* it=item(p);
01190     if ( !it ) {
01191         it = grid[idx(p)] = new TileItem(t,FALSE,canvas());
01192         it->move(p.x()*canvas()->tileWidth(), p.y()*canvas()->tileHeight());
01193         it->show();
01194     } else {
01195         it->setTile(t);
01196     }
01197 }
01198 
01199 Rack::Rack(int ntiles, QWidget* parent) : QCanvasView(
01200         new QCanvas(ntiles*TileItem::bigWidth(),TileItem::bigHeight()),
01201             parent),
01202         item(ntiles)
01203 {
01204     setLineWidth(1);
01205     setFixedHeight(sizeHint().height());
01206     n = 0;
01207     for (int i=0; i<ntiles; i++)
01208         item[i]=0;
01209     setHScrollBarMode(AlwaysOff);
01210     setVScrollBarMode(AlwaysOff);
01211     canvas()->setBackgroundColor(gray);
01212     dragging = 0;
01213 }
01214 
01215 Rack::~Rack()
01216 {
01217     clear();
01218     delete canvas();
01219 }
01220 
01221 QSize Rack::sizeHint() const
01222 {
01223     return QSize(-1,TileItem::bigHeight()+2);
01224 }
01225 
01226 void Rack::clear()
01227 {
01228     for (int i=0; i<n; i++)
01229         delete item[i];
01230     n=0;
01231 }
01232 
01233 void Rack::writeConfig(Config& cfg)
01234 {
01235     QStringList l;
01236     for (int i=0; i<n; i++)
01237         l.append(tile(i).key());
01238     cfg.writeEntry("Tiles",l,';');
01239 }
01240 
01241 void Rack::readConfig(Config& cfg)
01242 {
01243     clear();
01244     int x=0;
01245     QStringList l = cfg.readListEntry("Tiles",';');
01246     for (QStringList::ConstIterator it=l.begin(); it!=l.end(); ++it) {
01247         TileItem *i = new TileItem(Tile(*it),TRUE,canvas());
01248         i->move(x++,0);
01249         i->show();
01250         item[n++] = i;
01251     }
01252     layoutTiles();
01253 }
01254 
01255 static int cmp_tileitem(const void *a, const void *b)
01256 {
01257     const TileItem* ia = *(TileItem**)a;
01258     const TileItem* ib = *(TileItem**)b;
01259     return int(ia->x() - ib->x());
01260 }
01261 
01262 void Rack::layoutTiles()
01263 {
01264     int w = TileItem::bigWidth()+2;
01265 
01266     if ( dragging ) dragging->moveBy(dragging_adj,0);
01267     qsort(item.data(), n, sizeof(TileItem*), cmp_tileitem);
01268     if ( dragging ) dragging->moveBy(-dragging_adj,0);
01269 
01270     for (int i=0; i<n ;i++)
01271         if ( item[i] == dragging ) {
01272             item[i]->setZ(1);
01273         } else {
01274             item[i]->move(i*w, 0);
01275             item[i]->setZ(0);
01276         }
01277     canvas()->update();
01278 }
01279 
01280 void Rack::setBlanks(const Tile* bv)
01281 {
01282     for (int j=0; j<n; j++) {
01283         Tile tt = item[j]->tile();
01284         if ( tt.isBlank() ) {
01285             tt.setText(bv->text());
01286             item[j]->setTile(tt);
01287             bv++;
01288         }
01289     }
01290 }
01291 
01292 bool Rack::arrangeTiles(const Tile** s, int sn)
01293 {
01294     bool could = TRUE;
01295     for (int j=0; j<n; j++) {
01296         Tile tt = item[j]->tile();
01297         int f=-1;
01298         for (int i=0; i<sn && f<0; i++) {
01299             if (s[i] && *s[i] == tt ) {
01300                 s[i]=0;
01301                 f=i;
01302             }
01303         }
01304         if ( f >= 0 ) {
01305             item[j]->move(f-999,0);
01306         } else {
01307             could = FALSE;
01308         }
01309     }
01310     layoutTiles();
01311     return could;
01312 }
01313 
01314 void Rack::addTile(const Tile& t)
01315 {
01316     TileItem *i = new TileItem(t,TRUE,canvas());
01317     i->show();
01318     item[n++] = i;
01319     layoutTiles();
01320 }
01321 
01322 void Rack::remove(Tile t)
01323 {
01324     for (int i=0; i<n ;i++)
01325         if ( item[i]->tile() == t ) {
01326             remove(i);
01327             return;
01328         }
01329 }
01330 
01331 void Rack::remove(int i)
01332 {
01333     delete item[i];
01334     n--;
01335     for (;i<n;i++)
01336         item[i]=item[i+1];
01337     layoutTiles();
01338 }
01339 
01340 void Rack::resizeEvent(QResizeEvent* e)
01341 {
01342     canvas()->resize(width()-frameWidth()*2,height()-frameWidth()*2);
01343     QCanvasView::resizeEvent(e);
01344 }
01345 
01346 void Rack::contentsMousePressEvent(QMouseEvent* e)
01347 {
01348     if ( computerized() )
01349         return;
01350     QCanvasItemList list = canvas()->collisions(e->pos());
01351     if (list.count()) {
01352         dragging = list.first();
01353         dragstart = e->pos()-QPoint(int(dragging->x()),int(dragging->y()));
01354     } else {
01355         dragging = 0;
01356     }
01357 }
01358 
01359 void Rack::contentsMouseMoveEvent(QMouseEvent* e)
01360 {
01361     if ( computerized() )
01362         return;
01363     //int w = TileItem::bigWidth()+2;
01364     if ( dragging ) {
01365         dragging_adj = TileItem::bigWidth()/2;
01366         if ( dragging->x() > e->x()-dragstart.x() )
01367             dragging_adj = -dragging_adj;
01368         dragging->move(e->x()-dragstart.x(),0);
01369         layoutTiles();
01370     }
01371 }
01372 
01373 void Rack::contentsMouseReleaseEvent(QMouseEvent* /*e*/)
01374 {
01375     if ( computerized() )
01376         return;
01377     if ( dragging ) {
01378         dragging=0;
01379         layoutTiles();
01380     }
01381 }
01382 
01383 Tile::Tile(const QString& key)
01384 {
01385     int a=key.find('@');
01386     txt = key.left(a);
01387     val = key.mid(a+1).toInt();
01388     blank = txt.isEmpty();
01389 }
01390 
01391 QString Tile::key() const
01392 {
01393     return txt+"@"+QString::number(val);
01394 }
01395 
01396 Bag::Bag()
01397 {
01398     tiles.setAutoDelete(TRUE);
01399 }
01400 
01401 void Bag::writeConfig(Config& cfg)
01402 {
01403     QStringList t;
01404     for (QListIterator<Tile> it(tiles); it; ++it)
01405         t.append((*it)->key());
01406     cfg.writeEntry("Tiles",t,';');
01407 }
01408 
01409 void Bag::readConfig(Config& cfg)
01410 {
01411     tiles.clear();
01412     QStringList t = cfg.readListEntry("Tiles",';');
01413     for (QStringList::ConstIterator it=t.begin(); it!=t.end(); ++it )
01414         add(Tile(*it));
01415 }
01416 
01417 void Bag::add(const Tile& t)
01418 {
01419     tiles.append(new Tile(t));
01420 }
01421 
01422 Tile Bag::takeRandom()
01423 {
01424     Tile* rp = tiles.take(random()%tiles.count());
01425     Tile r=*rp;
01426     return r;
01427 }
01428 
01429 ScoreInfo::ScoreInfo( QWidget* parent, const char* name, WFlags fl ) :
01430     QLabel("<P>",parent,name,fl)
01431 {
01432     score=0;
01433     msgtimer = new QTimer(this);
01434     connect(msgtimer, SIGNAL(timeout()), this, SLOT(showScores()));
01435     setBackgroundMode( PaletteButton );
01436 }
01437 
01438 ScoreInfo::~ScoreInfo()
01439 {
01440     if ( score ) delete [] score;
01441 }
01442 
01443 void ScoreInfo::writeConfig(Config& cfg)
01444 {
01445     QStringList l;
01446     for (int i=0; i<(int)names.count(); i++)
01447         l.append(QString::number(score[i]));
01448     cfg.writeEntry("Scores",l,';');
01449 }
01450 
01451 void ScoreInfo::readConfig(Config& cfg)
01452 {
01453     QStringList l = cfg.readListEntry("Scores",';');
01454     int i=0;
01455     for (QStringList::ConstIterator it=l.begin(); it!=l.end(); ++it )
01456         score[i++]=(*it).toInt();
01457     showScores();
01458 }
01459 
01460 
01461 QSize ScoreInfo::sizeHint() const
01462 {
01463     return QSize(QLabel::sizeHint().width(),fontMetrics().height());
01464 }
01465 
01466 void ScoreInfo::init(const QStringList& namelist)
01467 {
01468     names = namelist;
01469     if ( score ) delete [] score;
01470     score = new int[names.count()];
01471     memset(score,0,sizeof(int)*names.count());
01472     boldone = -1;
01473     showScores();
01474 }
01475 
01476 void ScoreInfo::addScore(int player, int change)
01477 {
01478     score[player] += change;
01479     showScores();
01480 }
01481 
01482 void ScoreInfo::setBoldOne(int b)
01483 {
01484     boldone=b;
01485     showScores();
01486 }
01487 
01488 void ScoreInfo::showScores()
01489 {
01490     QString r="<p>";
01491     int i=0;
01492     //int spl=(names.count()+1)/2; // 2 lines
01493     for (QStringList::ConstIterator it=names.begin(); it!=names.end(); ) {
01494         if ( i==boldone ) r += "<b>";
01495         QString n = *it;
01496         n.replace(QRegExp(":.*"),"");
01497         r += n;
01498         r += ":";
01499         r += QString::number(score[i]);
01500         if ( i==boldone ) r += "</b>";
01501 
01502         ++i;
01503         ++it;
01504         if ( it != names.end() )
01505             r += " ";
01506     }
01507     setText(r);
01508 }
01509 
01510 void ScoreInfo::showTemporaryScore(int amount)
01511 {
01512     if ( amount < 0 )
01513         setText(tr("<P>Invalid move"));
01514     else
01515         setText(tr("<P>Score: ")+QString::number(amount));
01516     msgtimer->start(3000,TRUE);
01517 }
01518 

Generated on Sat Nov 5 16:17:28 2005 for OPIE by  doxygen 1.4.2