00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <math.h>
00004 #include <time.h>
00005
00006 #include <opie2/oapplicationfactory.h>
00007 #include <qpe/qpeapplication.h>
00008 #include <qpe/config.h>
00009 #include <qpe/global.h>
00010
00011 #include <qdir.h>
00012
00013 #include "helpwindow.h"
00014 #include "sfcave.h"
00015
00016 #define CAPTION "SFCave 1.13 by AndyQ"
00017
00018 #define UP_THRUST 0.6
00019 #define NO_THRUST 0.8
00020 #define MAX_DOWN_THRUST 4.0
00021 #define MAX_UP_THRUST -3.5
00022
00023
00024 #define STATE_BOSS 0
00025 #define STATE_RUNNING 1
00026 #define STATE_CRASHING 2
00027 #define STATE_CRASHED 3
00028 #define STATE_NEWGAME 4
00029 #define STATE_MENU 5
00030 #define STATE_REPLAY 6
00031
00032
00033 #define MENU_MAIN_MENU 0
00034 #define MENU_OPTIONS_MENU 1
00035 #define MENU_REPLAY_MENU 2
00036
00037
00038 #define MENU_START_GAME 0
00039 #define MENU_REPLAY 1
00040 #define MENU_OPTIONS 2
00041 #define MENU_HELP 3
00042 #define MENU_QUIT 4
00043
00044
00045 #define MENU_GAME_TYPE 0
00046 #define MENU_GAME_DIFFICULTY 1
00047 #define MENU_CLEAR_HIGHSCORES 2
00048 #define MENU_BACK 3
00049
00050
00051 #define MENU_REPLAY_START 0
00052 #define MENU_REPLAY_LOAD 1
00053 #define MENU_REPLAY_SAVE 2
00054 #define MENU_REPLAY_BACK 3
00055
00056
00057 #define NR_GAME_DIFFICULTIES 3
00058 #define NR_GAME_TYPES 3
00059
00060 #define DIFICULTY_EASY 0
00061 #define DIFICULTY_NORMAL 1
00062 #define DIFICULTY_HARD 2
00063 #define EASY "Easy"
00064 #define NORMAL "Normal"
00065 #define HARD "Hard"
00066
00067 #define SFCAVE_GAME_TYPE 0
00068 #define GATES_GAME_TYPE 1
00069 #define FLY_GAME_TYPE 2
00070 #define SFCAVE_GAME "SFCave"
00071 #define GATES_GAME "Gates"
00072 #define FLY_GAME "Fly"
00073 #define CURRENT_GAME_TYPE gameTypes[currentGameType]
00074 #define CURRENT_GAME_DIFFICULTY difficultyOption[currentGameDifficulty];
00075
00076 QString SFCave::dificultyOption[] = { EASY, NORMAL, HARD };
00077 QString SFCave::gameTypes[] = { SFCAVE_GAME, GATES_GAME, FLY_GAME };
00078
00079 QString SFCave::menuOptions[NR_MENUS][MAX_MENU_OPTIONS] = { { "Start Game", "Replays", "Options", "Help", "Quit", "", "", "" },
00080 { "Game Type - %s", "Game Difficulty - %s", "Clear High Scores for this game", "Back", "", "", "", "" },
00081 { "Play Reply", "Load Replay", "Save Replay", "Back", "", "", "", "" } };
00082
00083 int SFCave::nrMenuOptions[NR_MENUS] = { 5, 4, 4 };
00084 int SFCave ::currentMenuOption[NR_MENUS] = { 0, 0, 0 };
00085
00086 #define UP_THRUST 0.6
00087 #define NO_THRUST 0.8
00088 #define MAX_DOWN_THRUST 4.0
00089 #define MAX_UP_THRUST -3.5
00090 double SFCave::UpThrustVals[3][3] = {{ 0.6, 0.6, 0.6 },
00091 { 0.6, 0.6, 0.8 },
00092 { 0.4, 0.7, 1.0 } };
00093
00094 double SFCave::DownThrustVals[3][3] = {{ 0.8, 0.8, 0.8 },
00095 { 0.8, 0.8, 1.0 },
00096 { 0.4, 0.7, 1.0 } };
00097
00098 double SFCave::MaxUpThrustVals[3][3] = {{ -3.5, -3.5, -3.5 },
00099 { -3.5, -4.0, -5.0 },
00100 { -3.5, -4.0, -5.0 } };
00101
00102 double SFCave::MaxDownThrustVals[3][3] = {{ 4.0, 4.0, 4.0 },
00103 { 4.0, 5.0, 5.5 },
00104 { 3.5, 4.0, 5.0 } };
00105
00106 int SFCave::flyEasyScores[7][3] = { { 0, 10, 5 },
00107 { 10, 20, 3 },
00108 { 20, 30, 2 },
00109 { 30, 40, 1 },
00110 { 50, 70, -2 },
00111 { 70, 300, -5 },
00112 { -1, -1, -1 } };
00113 int SFCave::flyNormalScores[7][3] = { { 0, 10, 5 },
00114 { 10, 20, 3 },
00115 { 20, 30, 2 },
00116 { 30, 40, 1 },
00117 { 50, 70, -2 },
00118 { 70, 300, -5 },
00119 { -1, -1, -1 } };
00120 int SFCave::flyHardScores[7][3] = { { 0, 20, 5 },
00121 { 20, 40, 3 },
00122 { 40, 100, 1 },
00123 { 100, 150, -2 },
00124 { 150, 300, -5 },
00125 { -1, -1, -1 } };
00126
00127 int SFCave::initialGateGaps[] = { 75, 50, 25 };
00128
00129
00130 #define FLYSCORES( x, y ) (*(flyScores + ((x)*3) + y))
00131 bool movel;
00132
00133
00134 OPIE_EXPORT_APP( Opie::Core::OApplicationFactory<SFCave> )
00135
00136 SFCave :: SFCave( QWidget *w, const char *name, WFlags fl )
00137 : QMainWindow( w, name, fl )
00138
00139 {
00140 showMaximized();
00141 movel = true;
00142 int spd = 3;
00143
00144
00145 replayIt = 0;
00146
00147 replayFile = Global::applicationFileName("sfcave", "replay");
00148
00149 sWidth = width();
00150 sHeight = height();
00151 segSize = sWidth/(MAPSIZE-1)+1;
00152
00153 currentMenuNr = 0;
00154 currentGameType = 0;
00155 currentGameDifficulty = 0;
00156
00157 setCaption( CAPTION );
00158 showScoreZones = false;
00159
00160 #ifdef QWS
00161 Config cfg( "sfcave" );
00162 cfg.setGroup( "settings" );
00163 QString key = "highScore_";
00164
00165 for ( int i = 0 ; i < 3 ; ++i )
00166 {
00167 for ( int j = 0 ; j < 3 ; ++j )
00168 highestScore[i][j] = cfg.readNumEntry( key + gameTypes[i] + "_" + dificultyOption[j], 0 );
00169 }
00170
00171 currentGameType = cfg.readNumEntry( "gameType", 0 );
00172 currentGameDifficulty = cfg.readNumEntry( "difficulty", 0 );
00173 #endif
00174 speed = spd;
00175 press = false;
00176 showEyeCandy = false;
00177
00178 offscreen = new QPixmap( sWidth, sHeight );
00179 offscreen->fill( Qt::black );
00180
00181
00182 crashLineLength = -1;
00183 state = STATE_MENU;
00184 prevState = STATE_MENU;
00185
00186 gameTimer = new QTimer( this, "game timer" );
00187 connect( gameTimer, SIGNAL( timeout() ),
00188 this, SLOT( run() ) );
00189
00190 QTimer::singleShot(0, this, SLOT(start()));
00191 }
00192
00193 SFCave :: ~SFCave()
00194 {
00195 }
00196
00197 void SFCave :: start()
00198 {
00199 gameTimer->start( 10 );
00200
00201 }
00202
00203 void SFCave :: setSeed( int seed )
00204 {
00205 if ( seed == -1 )
00206 currentSeed = ((unsigned long) time((time_t *) NULL));
00207 else
00208 currentSeed = seed;
00209 PutSeed( currentSeed );
00210 }
00211
00212 int SFCave :: nextInt( int range )
00213 {
00214 int val = (int)(Random( ) * range);
00215
00216 return val;
00217
00218 }
00219
00220 void SFCave :: setUp()
00221 {
00222 score = 0;
00223 offset = 0;
00224 nrFrames = 0;
00225 dir = 1;
00226 thrust = 0;
00227 startScoring = false;
00228 press = false;
00229
00230 if ( CURRENT_GAME_TYPE == SFCAVE_GAME )
00231 {
00232 thrustUp = UpThrustVals[SFCAVE_GAME_TYPE][currentGameDifficulty];;
00233 noThrust = DownThrustVals[SFCAVE_GAME_TYPE][currentGameDifficulty];;
00234 maxUpThrust = MaxUpThrustVals[SFCAVE_GAME_TYPE][currentGameDifficulty];;
00235 maxDownThrust = MaxDownThrustVals[SFCAVE_GAME_TYPE][currentGameDifficulty];;
00236
00237 if ( currentGameDifficulty == DIFICULTY_EASY )
00238 gateDistance = 100;
00239 else if ( currentGameDifficulty == DIFICULTY_NORMAL )
00240 gateDistance = 60;
00241 else
00242 gateDistance = 40;
00243 }
00244 else if ( CURRENT_GAME_TYPE == GATES_GAME )
00245 {
00246 thrustUp = UpThrustVals[GATES_GAME_TYPE][currentGameDifficulty];;
00247 noThrust = DownThrustVals[GATES_GAME_TYPE][currentGameDifficulty];;
00248 maxUpThrust = MaxUpThrustVals[GATES_GAME_TYPE][currentGameDifficulty];;
00249 maxDownThrust = MaxDownThrustVals[GATES_GAME_TYPE][currentGameDifficulty];;
00250 gateDistance = 75;
00251 nextGate = nextInt( 50 ) + gateDistance;
00252 }
00253 else
00254 {
00255 thrustUp = UpThrustVals[FLY_GAME_TYPE][currentGameDifficulty];
00256 noThrust = DownThrustVals[FLY_GAME_TYPE][currentGameDifficulty];
00257 maxUpThrust = MaxUpThrustVals[FLY_GAME_TYPE][currentGameDifficulty];
00258 maxDownThrust = MaxDownThrustVals[FLY_GAME_TYPE][currentGameDifficulty];
00259
00260 if ( currentGameDifficulty == DIFICULTY_EASY )
00261 flyScores = (int*)flyEasyScores;
00262 else if ( currentGameDifficulty == DIFICULTY_NORMAL )
00263 flyScores = (int*)flyNormalScores;
00264 else
00265 flyScores = (int*)flyHardScores;
00266 }
00267
00268 crashLineLength = 0;
00269 lastGateBottomY = 0;
00270
00271 user.setRect( 50, sWidth/2, 4, 4 );
00272
00273 blockWidth = 20;
00274 blockHeight = 70;
00275 gapHeight = initialGateGaps[currentGameDifficulty];
00276
00277 for ( int i = 0 ; i < TRAILSIZE ; ++i )
00278 {
00279 trail[i].setX( -1 );
00280 trail[i].setY( 0 );
00281 }
00282
00283 if ( CURRENT_GAME_TYPE != FLY_GAME )
00284 {
00285 maxHeight = 50;
00286
00287 mapTop[0] = (int)(nextInt(50)) + 5;
00288 mapBottom[0] = (int)(nextInt(50)) + 5;
00289 for ( int i = 1 ; i < MAPSIZE ; ++i )
00290 setPoint( i );
00291 }
00292 else
00293 {
00294 maxHeight = 100;
00295
00296 for ( int i = 0 ; i < MAPSIZE ; ++i )
00297 mapBottom[i] = sHeight - 10;
00298 }
00299 for ( int i = 0 ; i < BLOCKSIZE ; ++i )
00300 blocks[i].setY( -1 );
00301
00302 }
00303
00304 void SFCave :: run()
00305 {
00306 switch ( state )
00307 {
00308 case STATE_MENU:
00309 displayMenu();
00310 break;
00311 case STATE_NEWGAME:
00312 setSeed( -1 );
00313 setUp();
00314 draw();
00315 state = STATE_RUNNING;
00316 replay = false;
00317 replayList.clear();
00318 break;
00319 case STATE_REPLAY:
00320 setSeed( currentSeed );
00321 setUp();
00322 draw();
00323 state = STATE_RUNNING;
00324 replay = true;
00325 if ( replayIt )
00326 delete replayIt;
00327 replayIt = new QListIterator<int>( replayList );
00328 break;
00329 case STATE_BOSS:
00330 drawBoss();
00331 break;
00332
00333 case STATE_CRASHING:
00334 case STATE_CRASHED:
00335 press = false;
00336 draw();
00337 break;
00338
00339 case STATE_RUNNING:
00340 {
00341 if ( nrFrames % 2 == 0 )
00342 handleKeys();
00343
00344
00345 nrFrames ++;
00346
00347 if ( replay )
00348 {
00349 while( replayIt->current() && *(replayIt->current()) == nrFrames )
00350 {
00351 press = !press;
00352 ++(*replayIt);
00353 }
00354 }
00355
00356 if ( CURRENT_GAME_TYPE == SFCAVE_GAME )
00357 handleGameSFCave();
00358 else if ( CURRENT_GAME_TYPE == GATES_GAME )
00359 handleGameGates();
00360 else if ( CURRENT_GAME_TYPE == FLY_GAME )
00361 handleGameFly();
00362
00363 draw();
00364 break;
00365 }
00366 }
00367 }
00368
00369 void SFCave :: handleGameSFCave()
00370 {
00371
00372 if ( nrFrames % 5 == 0 )
00373 score ++;
00374
00375 if ( nrFrames % 500 == 0 )
00376 {
00377 if ( maxHeight < sHeight - 100 )
00378 {
00379 maxHeight += 10;
00380
00381
00382 if ( maxHeight > sHeight - 150 )
00383 blockHeight -= 5;
00384 }
00385 }
00386
00387 if ( nrFrames % gateDistance == 0 )
00388 addBlock();
00389
00390 if ( checkCollision() )
00391 {
00392 if ( score > highestScore[currentGameType][currentGameDifficulty] )
00393 {
00394 highestScore[currentGameType][currentGameDifficulty] = score;
00395 saveScore();
00396 }
00397 state = STATE_CRASHING;
00398 }
00399 else
00400 {
00401 moveLandscape();
00402 }
00403
00404 }
00405
00406
00407 void SFCave :: handleGameGates()
00408 {
00409
00410 if ( nrFrames % 5 == 0 )
00411 score ++;
00412
00413
00414 if ( nrFrames >= nextGate )
00415 {
00416 nextGate = nrFrames + nextInt( 50 ) + gateDistance;
00417 addGate();
00418 }
00419
00420 if ( nrFrames % 500 == 0 )
00421 {
00422 if ( gapHeight > 75 )
00423 gapHeight -= 5;
00424 }
00425
00426 if ( checkCollision() )
00427 {
00428 if ( score > highestScore[currentGameType][currentGameDifficulty] )
00429 {
00430 highestScore[currentGameType][currentGameDifficulty] = score;
00431 saveScore();
00432 }
00433 state = STATE_CRASHING;
00434 }
00435 else
00436 {
00437 moveLandscape();
00438 }
00439
00440 }
00441
00442 void SFCave :: handleGameFly()
00443 {
00444 int diff = mapBottom[10] - user.y();
00445
00446 if ( nrFrames % 4 == 0 )
00447 {
00448 if ( !startScoring )
00449 {
00450 if ( diff < 40 )
00451 startScoring = true;
00452 }
00453
00454 if ( startScoring )
00455 {
00456
00457
00458
00459
00460 for ( int i = 0 ; i < 10 && FLYSCORES( i, 0 ) != -1 ; ++i )
00461 {
00462 if ( FLYSCORES( i, 0 ) <= diff && FLYSCORES(i, 1 ) > diff )
00463 {
00464 score += FLYSCORES( i, 2 );
00465 break;
00466 }
00467 }
00468 }
00469 }
00470
00471 if ( checkFlyGameCollision() )
00472 {
00473 if ( score > highestScore[currentGameType][currentGameDifficulty] )
00474 {
00475 highestScore[currentGameType][currentGameDifficulty] = score;
00476 saveScore();
00477 }
00478 state = STATE_CRASHING;
00479 }
00480 else
00481 {
00482 moveFlyGameLandscape();
00483 }
00484 }
00485
00486 bool SFCave :: checkFlyGameCollision()
00487 {
00488 if ( (user.y() + user.width()) >= mapBottom[11] )
00489 return true;
00490
00491 return false;
00492 }
00493
00494 void SFCave :: moveFlyGameLandscape()
00495 {
00496 offset++;
00497
00498 if ( offset >= segSize )
00499 {
00500 offset = 0;
00501 for ( int i = 0 ; i < MAPSIZE-speed ; ++i )
00502 mapBottom[i] = mapBottom[i+speed];
00503
00504 for ( int i = speed ; i > 0 ; --i )
00505 setFlyPoint( MAPSIZE-i );
00506 }
00507 }
00508
00509 void SFCave :: setFlyPoint( int point )
00510 {
00511 static int fly_difficulty_levels[] = { 5, 10, 15 };
00512 if ( nextInt(100) >= 75 )
00513 dir *= -1;
00514
00515 int prevPoint = mapBottom[point-1];
00516
00517 int nextPoint = prevPoint + (dir * nextInt( fly_difficulty_levels[currentGameDifficulty] ) );
00518
00519 if ( nextPoint > sHeight )
00520 {
00521 nextPoint = sHeight;
00522 dir *= -1;
00523 }
00524 else if ( nextPoint < maxHeight )
00525 {
00526 nextPoint = maxHeight;
00527 dir *= 1;
00528 }
00529
00530 mapBottom[point] = nextPoint;
00531 }
00532
00533 bool SFCave :: checkCollision()
00534 {
00535 if ( (user.y() + user.width()) >= mapBottom[11] || user.y() <= mapTop[11] )
00536 return true;
00537
00538 for ( int i = 0 ; i < BLOCKSIZE ; ++i )
00539 {
00540 if ( blocks[i].y() != -1 )
00541 {
00542 if ( blocks[i].intersects( user ) )
00543 return true;
00544 }
00545 }
00546 return false;
00547 }
00548
00549 void SFCave :: moveLandscape()
00550 {
00551 offset++;
00552
00553 if ( offset >= segSize )
00554 {
00555 offset = 0;
00556 for ( int i = 0 ; i < MAPSIZE-speed ; ++i )
00557 {
00558 mapTop[i] = mapTop[i+speed];
00559 mapBottom[i] = mapBottom[i+speed];
00560 }
00561
00562 for ( int i = speed ; i > 0 ; --i )
00563 setPoint( MAPSIZE-i );
00564 }
00565
00566 for ( int i = 0 ; i < BLOCKSIZE ; ++i )
00567 {
00568 if ( blocks[i].y() != -1 )
00569 {
00570 blocks[i].moveBy( -speed, 0 );
00571 if ( blocks[i].x() + blocks[i].width() < 0 )
00572 blocks[i].setY( -1 );
00573 }
00574 }
00575 }
00576
00577 void SFCave :: addBlock()
00578 {
00579 for ( int i = 0 ; i < BLOCKSIZE ; ++i )
00580 {
00581 if ( blocks[i].y() == -1 )
00582 {
00583 int x = sWidth;
00584
00585 int y = mapTop[50] + (int)(nextInt(mapBottom[50] - mapTop[50] - blockHeight));
00586
00587 blocks[i].setRect( x, y, blockWidth, blockHeight );
00588
00589 break;
00590 }
00591 }
00592 }
00593
00594 void SFCave :: addGate()
00595 {
00596 for ( int i = 0 ; i < BLOCKSIZE ; ++i )
00597 {
00598 if ( blocks[i].y() == -1 )
00599 {
00600 int x1 = sWidth;
00601 int y1 = mapTop[50];
00602 int b1Height = nextInt(mapBottom[50] - mapTop[50] - gapHeight);
00603
00604
00605 if ( b1Height - 100 > lastGateBottomY )
00606 b1Height -= 25;
00607 else if ( b1Height + 100 < lastGateBottomY )
00608 b1Height += 25;
00609 lastGateBottomY = b1Height;
00610
00611
00612 int x2 = sWidth;
00613 int y2 = y1 + b1Height + gapHeight;
00614 int b2Height = mapBottom[50] - y2;
00615
00616
00617 blocks[i].setRect( x1, y1, blockWidth, b1Height );
00618 blocks[i+1].setRect( x2, y2, blockWidth, b2Height );
00619
00620 break;
00621 }
00622 }
00623 }
00624
00625 void SFCave :: setPoint( int point )
00626 {
00627 if ( nextInt(100) >= 80 )
00628 dir *= -1;
00629
00630 mapTop[point] = mapTop[point-1] + (dir * nextInt( 5 ) );
00631 if ( mapTop[point] < 0 )
00632 {
00633 mapTop[point] = 0;
00634 dir *= -1;
00635 }
00636 else if ( mapTop[point] >= maxHeight )
00637 {
00638 mapTop[point] = maxHeight;
00639 dir *= -1;
00640 }
00641
00642
00643 mapBottom[point] = sHeight - (maxHeight - mapTop[point]);
00644 }
00645
00646 void SFCave :: drawBoss()
00647 {
00648 offscreen->fill( Qt::black );
00649
00650 bitBlt( this, 0, 0, offscreen, 0, 0, sWidth, sHeight, Qt::CopyROP, true );
00651 }
00652
00653 void SFCave :: draw()
00654 {
00655
00656 offscreen->fill( Qt::black );
00657
00658 QPainter p( offscreen );
00659 QFontMetrics fm = p.fontMetrics();
00660 p.setPen( Qt::white );
00661
00662 for ( int i = 0 ; i < MAPSIZE -3; ++i )
00663 {
00664
00665 if ( CURRENT_GAME_TYPE != FLY_GAME )
00666 p.drawLine( (i*segSize) - (offset*speed), mapTop[i], ((i+1)*segSize)-(offset*speed), mapTop[i+1] );
00667
00668 p.drawLine( (i*segSize) - (offset*speed), mapBottom[i], ((i+1)*segSize)-(offset*speed), mapBottom[i+1] );
00669
00670 if ( CURRENT_GAME_TYPE == FLY_GAME && showScoreZones )
00671 {
00672 p.setPen( Qt::blue );
00673 for ( int j = 1 ; j < 10 && FLYSCORES( j, 0 ) != -1 ; ++j )
00674 {
00675 if ( FLYSCORES( j, 2 ) < 0 )
00676 p.setPen( Qt::red );
00677
00678 p.drawLine( (i*segSize) - (offset*speed), mapBottom[i]-FLYSCORES( j, 0 ), ((i+1)*segSize)-(offset*speed), mapBottom[i+1]-FLYSCORES( j, 0 ) );
00679 }
00680
00681 p.setPen( Qt::white );
00682 }
00683 }
00684
00685
00686
00687
00688
00689
00690
00691 p.drawRect( user );
00692
00693
00694 for ( int i = 0 ; i < TRAILSIZE ; ++i )
00695 if ( trail[i].x() >= 0 )
00696 {
00697 if ( showEyeCandy )
00698 p.setPen( Qt::white.light((int)(100.0-3*(user.x()/100.0)* (user.x()-trail[i].x())) ) );
00699 p.drawRect( trail[i].x(), trail[i].y(), 2, 2 );
00700 }
00701
00702 p.setPen( Qt::white );
00703
00704 for ( int i = 0 ; i < BLOCKSIZE ; ++i )
00705 if ( blocks[i].y() != -1 )
00706 {
00707 p.fillRect( blocks[i], Qt::black );
00708 p.drawRect( blocks[i] );
00709 }
00710
00711
00712 QString s;
00713 s.sprintf( "score %06d high score %06d", score, highestScore[currentGameType][currentGameDifficulty] );
00714 p.drawText( 5, 10, s );
00715
00716
00717 if ( state == STATE_CRASHING || state == STATE_CRASHED )
00718 {
00719
00720
00721 if ( crashLineLength != -1 )
00722 {
00723 for ( int i = 0 ; i < 36 ; ++i )
00724 {
00725 int x = (int)(user.x() + (crashLineLength+nextInt(10)) * cos( (M_PI/180) * (10.0 * i) ) );
00726 int y = (int)(user.y() + (crashLineLength+nextInt(10)) * sin( (M_PI/180) * (10.0 * i) ) ); p.drawLine( user.x(), user.y(), x, y );
00727 }
00728 }
00729
00730 if ( state == STATE_CRASHING && crashLineLength >= 15 )
00731 state = STATE_CRASHED;
00732
00733 if ( state == STATE_CRASHED )
00734 {
00735 QString text = "Press up or down to start";
00736 p.drawText( (sWidth/2) - (fm.width( text )/2), 120, text );
00737
00738 text = "Press OK for menu";
00739 p.drawText( (sWidth/2) - (fm.width( text )/2), 135, text );
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750 }
00751 else
00752 crashLineLength ++;
00753 }
00754
00755 p.end();
00756 bitBlt( this, 0, 0, offscreen, 0, 0, sWidth, sHeight, Qt::CopyROP, true );
00757
00758 }
00759
00760 void SFCave :: handleKeys()
00761 {
00762
00763 bool done = false;
00764 for ( int i = 0 ; i < TRAILSIZE ; ++i )
00765 {
00766 if ( trail[i].x() < 0 )
00767 {
00768 if ( !done )
00769 {
00770 trail[i].setX( user.x() - 5 );
00771 trail[i].setY( user.y() );
00772 done = true;
00773 }
00774 }
00775 else
00776 {
00777 trail[i].setX( trail[i].x() - (2) );
00778 }
00779 }
00780
00781 if ( speed <= 3 )
00782 {
00783 if ( press )
00784 thrust -= thrustUp;
00785 else
00786 thrust += noThrust;
00787
00788 if ( thrust > maxDownThrust )
00789 thrust = maxDownThrust;
00790 else if ( thrust < maxUpThrust )
00791 thrust = maxUpThrust;
00792 }
00793 else
00794 {
00795 if ( press )
00796 thrust -= 0.5;
00797 else
00798 thrust += 0.8;
00799
00800 if ( thrust > 5.0 )
00801 thrust = 5.0;
00802 else if ( thrust < -3.5 )
00803 thrust = -3.5;
00804 }
00805 user.moveBy( 0, (int)thrust );
00806 }
00807
00808 void SFCave :: keyPressEvent( QKeyEvent *e )
00809 {
00810 if ( state == STATE_MENU )
00811 handleMenuKeys( e );
00812 else
00813 {
00814 switch( e->key() )
00815 {
00816 case Qt::Key_Up:
00817 case Qt::Key_F9:
00818 case Qt::Key_Space:
00819 if ( state == STATE_RUNNING )
00820 {
00821 if ( !replay && !press )
00822 {
00823 press = true;
00824 replayList.append( new int( nrFrames ) );
00825 }
00826 }
00827 else if ( state == STATE_CRASHED )
00828 {
00829 if ( e->key() == Key_Up )
00830 state = STATE_NEWGAME;
00831 }
00832
00833 break;
00834 case Qt::Key_M:
00835 case Qt::Key_Return:
00836 case Qt::Key_Enter:
00837 if ( state == STATE_CRASHED )
00838 {
00839 state = STATE_MENU;
00840 currentMenuNr = 0;
00841 currentMenuOption[currentMenuNr] = 0;
00842 }
00843 break;
00844
00845 case Qt::Key_Z:
00846 showScoreZones = !showScoreZones;
00847 break;
00848
00849 default:
00850 e->ignore();
00851 break;
00852 }
00853 }
00854 }
00855
00856 void SFCave :: keyReleaseEvent( QKeyEvent *e )
00857 {
00858 if ( state == STATE_MENU )
00859 {
00860 }
00861 else
00862 {
00863 switch( e->key() )
00864 {
00865 case Qt::Key_F9:
00866 case Qt::Key_Space:
00867 case Qt::Key_Up:
00868 if ( state == STATE_RUNNING )
00869 {
00870 if ( !replay && press )
00871 {
00872 press = false;
00873 replayList.append( new int( nrFrames ) );
00874 }
00875 }
00876 break;
00877
00878 case Qt::Key_E:
00879 showEyeCandy = !showEyeCandy;
00880 break;
00881
00882 case Qt::Key_R:
00883 if ( state == STATE_CRASHED )
00884 state = STATE_REPLAY;
00885 break;
00886
00887 case Qt::Key_Down:
00888 if ( state == STATE_CRASHED )
00889 state = STATE_NEWGAME;
00890 break;
00891
00892 case Qt::Key_S:
00893 if ( state == STATE_CRASHED )
00894 saveReplay();
00895 break;
00896
00897 case Qt::Key_L:
00898 if ( state == STATE_CRASHED )
00899 loadReplay();
00900 break;
00901 default:
00902 e->ignore();
00903 break;
00904 }
00905 }
00906
00907 }
00908
00909
00910 void SFCave :: saveScore()
00911 {
00912 #ifdef QWS
00913 Config cfg( "sfcave" );
00914 cfg.setGroup( "settings" );
00915 QString key = "highScore_";
00916
00917 cfg.writeEntry( key + gameTypes[currentGameType] + "_" + dificultyOption[currentGameDifficulty], highestScore[currentGameType][currentGameDifficulty] );
00918 key += CURRENT_GAME_TYPE;
00919 cfg.writeEntry( key, highestScore[currentGameType] );
00920 #endif
00921 }
00922
00923 void SFCave :: saveReplay()
00924 {
00925 FILE *out;
00926 out = fopen( QFile::encodeName(replayFile).data(), "w" );
00927 if ( !out )
00928 {
00929 printf( "Couldn't write to %s\n", QFile::encodeName(replayFile).data() );
00930 return;
00931 }
00932
00933
00934
00935 QString val;
00936 val.sprintf( "%d %d %d ", currentSeed, currentGameType, currentGameDifficulty );
00937
00938 QListIterator<int> it( replayList );
00939 while( it.current() )
00940 {
00941 QString tmp;
00942 tmp.sprintf( "%d ", (*it.current()) );
00943 val += tmp;
00944
00945 ++it;
00946 }
00947 val += "\n";
00948
00949 QString line;
00950 line.sprintf( "%d\n", val.length() );
00951 fwrite( (const char *)line, 1, line.length(), out );
00952
00953 fwrite( (const char *)val, 1, val.length(), out );
00954
00955 fclose( out );
00956
00957 printf( "Replay saved to %s\n", QFile::encodeName(replayFile).data() );
00958
00959 }
00960
00961 void SFCave :: loadReplay()
00962 {
00963 FILE *in = fopen( QFile::encodeName(replayFile).data() , "r" );
00964
00965 if ( in == 0 )
00966 {
00967 printf( "Couldn't load replay file!\n" );
00968 return;
00969 }
00970
00971
00972 char line[10+1];
00973 fgets( line, 10, in );
00974
00975 int length = -1;
00976 sscanf( line, "%d", &length );
00977 char *data = new char[length+1];
00978
00979 fread( data, 1, length, in );
00980
00981
00982 QString sep = " ";
00983 QStringList list = QStringList::split( sep, QString( data ) );
00984
00985
00986 QStringList::Iterator it = list.begin();
00987 currentSeed = (*it).toInt();
00988 ++it;
00989 currentGameType = (*it).toInt();
00990 ++it;
00991 currentGameDifficulty = (*it).toInt();
00992 ++it;
00993
00994 replayList.clear();
00995 for ( ; it != list.end(); ++it )
00996 {
00997 int v = (*it).toInt();
00998 replayList.append( new int( v ) );
00999 }
01000
01001 delete data;
01002
01003 fclose( in );
01004
01005 printf( "Replay loaded from %s\n", QFile::encodeName(replayFile).data() );
01006 }
01007
01008
01009
01010 void SFCave :: handleMenuKeys( QKeyEvent *e )
01011 {
01012 switch( e->key() )
01013 {
01014 case Qt::Key_Down:
01015 currentMenuOption[currentMenuNr] ++;
01016 if ( menuOptions[currentMenuNr][currentMenuOption[currentMenuNr]] == "" )
01017 currentMenuOption[currentMenuNr] = 0;
01018 break;
01019 case Qt::Key_Up:
01020 currentMenuOption[currentMenuNr] --;
01021 if ( currentMenuOption[currentMenuNr] < 0 )
01022 currentMenuOption[currentMenuNr] = nrMenuOptions[currentMenuNr]-1;
01023 break;
01024
01025 case Qt::Key_Left:
01026 if ( currentMenuNr == MENU_OPTIONS_MENU )
01027 {
01028 if ( currentMenuOption[currentMenuNr] == MENU_GAME_TYPE )
01029 {
01030 currentGameType --;
01031 if ( currentGameType < 0 )
01032 currentGameType = NR_GAME_TYPES - 1;
01033 }
01034 else if ( currentMenuOption[currentMenuNr] == MENU_GAME_DIFFICULTY )
01035 {
01036 currentGameDifficulty --;
01037 if ( currentGameDifficulty < 0 )
01038 currentGameDifficulty = NR_GAME_DIFFICULTIES - 1;
01039 }
01040 }
01041 break;
01042
01043 case Qt::Key_Right:
01044 if ( currentMenuNr == MENU_OPTIONS_MENU )
01045 {
01046 if ( currentMenuOption[currentMenuNr] == MENU_GAME_TYPE )
01047 {
01048 currentGameType ++;
01049 if ( currentGameType == NR_GAME_TYPES )
01050 currentGameType = 0;
01051 }
01052 else if ( currentMenuOption[currentMenuNr] == MENU_GAME_DIFFICULTY )
01053 {
01054 currentGameDifficulty ++;
01055 if ( currentGameDifficulty == NR_GAME_DIFFICULTIES )
01056 currentGameDifficulty = 0;
01057 }
01058 }
01059 break;
01060
01061 case Qt::Key_Space:
01062 case Qt::Key_Return:
01063 case Qt::Key_Enter:
01064 dealWithMenuSelection();
01065 break;
01066 }
01067 }
01068
01069 void SFCave :: displayMenu()
01070 {
01071 offscreen->fill( Qt::black );
01072
01073 QPainter p( offscreen );
01074 p.setPen( Qt::white );
01075
01076 QFont f( "Helvetica", 16 );
01077 p.setFont( f );
01078
01079 QFontMetrics fm = p.fontMetrics();
01080
01081 QString text = "SFCave";
01082 p.drawText( (sWidth/2) - (fm.width( text )/2), 60, text );
01083
01084 text = "Written by Andy Qua";
01085 p.drawText( (sWidth/2) - (fm.width( text )/2), 85, text );
01086
01087
01088 int pos = 140;
01089 for ( int i = 0 ; menuOptions[currentMenuNr][i] != "" ; ++i, pos += 25 )
01090 {
01091 if ( currentMenuOption[currentMenuNr] == i )
01092 p.setPen( Qt::yellow );
01093 else
01094 p.setPen( Qt::white );
01095
01096 QString text;
01097 if ( menuOptions[currentMenuNr][i].find( "%s" ) != -1 )
01098 {
01099 QString val;
01100 if ( i == MENU_GAME_TYPE )
01101 val = gameTypes[currentGameType];
01102 else
01103 val = dificultyOption[currentGameDifficulty];
01104
01105 text.sprintf( (const char *)menuOptions[currentMenuNr][i], (const char *)val );
01106 }
01107 else
01108 text = menuOptions[currentMenuNr][i];
01109
01110 p.drawText( (sWidth/2) - (fm.width( text )/2), pos, text );
01111 }
01112
01113 p.end();
01114 bitBlt( this, 0, 0, offscreen, 0, 0, sWidth, sHeight, Qt::CopyROP, true );
01115 }
01116
01117 void SFCave :: dealWithMenuSelection()
01118 {
01119 switch( currentMenuNr )
01120 {
01121 case MENU_MAIN_MENU:
01122 {
01123 switch( currentMenuOption[currentMenuNr] )
01124 {
01125 case MENU_START_GAME:
01126 state = STATE_NEWGAME;
01127 break;
01128
01129 case MENU_REPLAY:
01130 currentMenuNr = MENU_REPLAY_MENU;
01131 currentMenuOption[currentMenuNr] = 0;
01132 break;
01133
01134 case MENU_OPTIONS:
01135 currentMenuNr = MENU_OPTIONS_MENU;
01136 currentMenuOption[currentMenuNr] = 0;
01137 break;
01138
01139 case MENU_HELP:
01140 {
01141
01142 HelpWindow *win = new HelpWindow( );
01143 QPEApplication::showWidget( win );
01144 break;
01145 }
01146
01147 case MENU_QUIT:
01148 QApplication::exit();
01149 break;
01150 }
01151
01152 break;
01153 }
01154
01155 case MENU_OPTIONS_MENU:
01156 {
01157 switch( currentMenuOption[currentMenuNr] )
01158 {
01159 case MENU_GAME_TYPE:
01160 break;
01161
01162 case MENU_GAME_DIFFICULTY:
01163 break;
01164
01165 case MENU_CLEAR_HIGHSCORES:
01166 for ( int i = 0 ; i < 3 ; ++i )
01167 highestScore[currentGameType][i] = 0;
01168 break;
01169
01170 case MENU_BACK:
01171 currentMenuNr = MENU_MAIN_MENU;
01172
01173 #ifdef QWS
01174 Config cfg( "sfcave" );
01175 cfg.setGroup( "settings" );
01176 cfg.writeEntry( "difficulty", currentGameDifficulty );
01177 cfg.writeEntry( "gameType", currentGameType );
01178 #endif
01179 break;
01180 }
01181
01182 break;
01183 }
01184
01185 case MENU_REPLAY_MENU:
01186 {
01187 switch( currentMenuOption[currentMenuNr] )
01188 {
01189 case MENU_REPLAY_START:
01190 if ( currentSeed != 0 )
01191 state = STATE_REPLAY;
01192
01193 break;
01194
01195 case MENU_REPLAY_LOAD:
01196 loadReplay();
01197 break;
01198
01199 case MENU_REPLAY_SAVE:
01200 saveReplay();
01201 break;
01202
01203 case MENU_REPLAY_BACK:
01204 currentMenuNr = MENU_MAIN_MENU;
01205 break;
01206
01207 }
01208 }
01209 }
01210 }
01211