00001 #include <stdio.h>
00002 #include <stdlib.h>
00003
00004 #include <time.h>
00005 #include <sys/timeb.h>
00006
00007 #include <SDL/SDL.h>
00008 #include <SDL/SDL_gfxPrimitives.h>
00009
00010 #include "constants.h"
00011
00012 #include "sound.h"
00013 #include "menu.h"
00014 #include "help.h"
00015 #include "game.h"
00016 #include "terrain.h"
00017 #include "random.h"
00018 #include "sfcave.h"
00019 #include "font.h"
00020 #include "settings.h"
00021 #include "util.h"
00022
00023 #include "sfcave_game.h"
00024 #include "gates_game.h"
00025 #include "fly_game.h"
00026
00027 void start( int argc, char *argv[] )
00028 {
00029 SFCave *app = new SFCave( argc, argv );
00030 app->mainEventLoop();
00031 delete app;
00032 }
00033
00034 #ifdef __cplusplus
00035 extern "C"
00036 #endif
00037 int main(int argc, char *argv[])
00038 {
00039 start( argc, argv );
00040 return 0;
00041 }
00042
00043
00044 SFCave :: SFCave( int argc, char *argv[] )
00045 {
00046 setupOK = false;
00047
00048
00049 string diff = loadSetting( "GameDifficulty", "Easy" );
00050 string game = loadSetting( "GameType", "SFCave" );
00051 musicPath = loadSetting( "MusicPath", SOUND_PATH );
00052 musicType = loadSetting( "MusicType", "mod,ogg" );
00053 bool soundOn = loadBoolSetting( "SoundOn", true );
00054 bool musicOn = loadBoolSetting( "MusicOn", true );
00055 if ( musicPath[musicPath.size()-1] != '/' )
00056 musicPath += "/";
00057 printf( "musicPath %s\n", musicPath.c_str() );
00058
00059
00060 initSDL( argc, argv );
00061
00062
00063 if ( !FontHandler::init() )
00064 {
00065 printf( "Unable to initialise fonts!\n" );
00066 return;
00067 }
00068
00069
00070 if ( !SoundHandler :: init() )
00071 printf("Unable to open audio!\n");
00072
00073 SoundHandler :: setSoundsOn( soundOn );
00074 SoundHandler :: setMusicOn( musicOn );
00075
00076 currentGame = Game::createGame( this, WIDTH, HEIGHT, game, diff );
00077 if ( !currentGame )
00078 currentGame = new SFCaveGame( this, WIDTH, HEIGHT, 0 );
00079 currentGame->setSeed(-1);
00080
00081
00082 menu = new Menu( this );
00083
00084
00085 help = new Help( this );
00086
00087 maxFPS = 50;
00088 showFps = false;
00089
00090 setupOK = true;
00091 }
00092
00093 SFCave :: ~SFCave()
00094 {
00095 if ( currentGame )
00096 delete currentGame;
00097
00098 if ( menu )
00099 delete menu;
00100
00101 if ( help )
00102 delete help;
00103
00104 SDL_FreeSurface( screen );
00105 FontHandler::cleanUp();
00106 SoundHandler :: cleanUp();
00107
00108 SDL_Quit();
00109 }
00110
00111
00112 void SFCave :: initSDL( int argc, char *argv[] )
00113 {
00114 const SDL_VideoInfo *info;
00115 Uint8 video_bpp;
00116 Uint32 videoflags;
00117
00118
00119 if ( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0 ) {
00120 fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
00121 exit(1);
00122 }
00123
00124 video_bpp = 16;
00125
00126 if ( !SDL_VideoModeOK(WIDTH, HEIGHT, video_bpp, SDL_DOUBLEBUF) )
00127 printf( "No double buffering\n" );
00128
00129 videoflags = SDL_HWSURFACE | SDL_SRCALPHA;
00130 while ( argc > 1 )
00131 {
00132 --argc;
00133 if ( strcmp(argv[argc-1], "-bpp") == 0 )
00134 {
00135 video_bpp = atoi(argv[argc]);
00136 --argc;
00137 }
00138 else if ( strcmp(argv[argc], "-hw") == 0 )
00139 {
00140 videoflags |= SDL_HWSURFACE;
00141 }
00142 else if ( strcmp(argv[argc], "-warp") == 0 )
00143 {
00144 videoflags |= SDL_HWPALETTE;
00145 }
00146 else if ( strcmp(argv[argc], "-fullscreen") == 0 )
00147 {
00148 videoflags |= SDL_FULLSCREEN;
00149 }
00150 else if ( strcmp(argv[argc], "-h") == 0 )
00151 {
00152 fprintf(stderr,
00153 "Usage: %s [-bpp N] [-warp] [-hw] [-fullscreen]\n",
00154 argv[0]);
00155 exit(1);
00156 }
00157 }
00158
00159
00160 if ( (screen = SDL_SetVideoMode( WIDTH,HEIGHT,video_bpp,videoflags )) == NULL )
00161 {
00162 printf( "Couldn't set %ix%i video mode: %s\n",WIDTH,HEIGHT,SDL_GetError() );
00163 exit(2);
00164 }
00165
00166
00167
00168
00169
00170 SDL_WM_SetCaption("SFCave","SFCave");
00171 }
00172
00173 void SFCave :: mainEventLoop()
00174 {
00175 if ( !setupOK )
00176 return;
00177
00178
00179 finish = false;
00180 state = 0;
00181 state = STATE_CRASHED;
00182 changeState( STATE_MENU );
00183
00184 FPS = 0;
00185 actualFPS = 0;
00186 time1 = 0;
00187
00188 limitFPS = true;
00189 while ( !finish )
00190 {
00191
00192 calcFPS();
00193
00194 SDL_FillRect( screen, 0, 0 );
00195
00196 handleGameState( );
00197
00198 SDL_Flip( screen );
00199
00200 if ( limitFPS )
00201 FPSDelay();
00202 else
00203 SDL_Delay( 5 );
00204
00205 handleEvents();
00206 }
00207 }
00208
00209
00210 void SFCave :: handleGameState()
00211 {
00212 switch( state )
00213 {
00214 case STATE_MENU:
00215 SDL_FillRect( screen, 0, 0 );
00216 menu->draw( screen );
00217 break;
00218 case STATE_HELP:
00219 SDL_FillRect( screen, 0, 0 );
00220 help->update();
00221 help->draw( screen );
00222 break;
00223 case STATE_NEWGAME:
00224 currentGame->setReplay( false );
00225 currentGame->init();
00226 changeState( STATE_PLAYING );
00227 break;
00228
00229 case STATE_REPLAY:
00230 currentGame->setReplay( true );
00231 currentGame->init();
00232 changeState( STATE_PLAYING );
00233 break;
00234
00235 case STATE_PLAYING:
00236 case STATE_CRASHING:
00237 case STATE_CRASHED:
00238 currentGame->update( state );
00239 currentGame->draw( screen );
00240 break;
00241
00242 case STATE_QUIT:
00243 finish = true;
00244 break;
00245 }
00246 }
00247
00248 void SFCave :: handleEvents()
00249 {
00250 SDL_Event event;
00251
00252
00253 while ( SDL_PollEvent(&event) )
00254 {
00255 switch (event.type)
00256 {
00257 case SDL_KEYDOWN:
00258 case SDL_KEYUP:
00259 {
00260
00261 if ( event.key.keysym.sym == SDLK_ESCAPE )
00262 {
00263 finish = true;
00264 break;
00265 }
00266
00267 if ( state == STATE_MENU )
00268 {
00269 int rc = menu->handleKeys( event.key );
00270 if ( rc != -1 )
00271 handleMenuSelect( rc );
00272 }
00273 else if ( state == STATE_HELP )
00274 {
00275 help->handleKeys( event.key );
00276 }
00277 else if ( state == STATE_CRASHED )
00278 {
00279 if ( event.type == SDL_KEYDOWN )
00280 {
00281 if ( event.key.keysym.sym == SDLK_UP ||
00282 event.key.keysym.sym == SDLK_DOWN ||
00283 event.key.keysym.sym == SDLK_SPACE )
00284 changeState( STATE_NEWGAME );
00285 else if ( event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == 0 )
00286 {
00287 changeState( STATE_MENU );
00288 menu->resetToTopMenu();
00289 }
00290 else if ( event.key.keysym.sym == SDLK_r )
00291 {
00292 changeState( STATE_REPLAY );
00293 }
00294 else if ( event.key.keysym.sym == SDLK_s )
00295 {
00296 SoundHandler :: playSound( SND_EXPLOSION );
00297 }
00298 }
00299 }
00300 else
00301 {
00302 switch ( event.key.keysym.sym )
00303 {
00304 case SDLK_f:
00305 if ( event.type == SDL_KEYDOWN )
00306 showFps = !showFps;
00307 break;
00308 case SDLK_l:
00309 if ( event.type == SDL_KEYDOWN )
00310 limitFPS = !limitFPS;
00311 break;
00312
00313 default:
00314 currentGame->handleKeys( event.key );
00315 break;
00316 }
00317 }
00318
00319 break;
00320 }
00321
00322 case SDL_QUIT:
00323 finish = true;
00324 break;
00325 default:
00326 break;
00327 }
00328 }
00329 }
00330
00331 void SFCave :: changeState( int s )
00332 {
00333 if ( state != s )
00334 currentGame->stateChanged( state, s );
00335
00336 if ( state == STATE_MENU && s == STATE_HELP )
00337 help->init();
00338 if ( state == STATE_CRASHED && s == STATE_MENU )
00339 {
00340 SoundHandler :: stopMusic( true );
00341
00342 string musicFile = chooseRandomFile( musicPath, musicType );
00343 SoundHandler :: setMusicVolume( 128 );
00344 SoundHandler :: playMusic( musicFile );
00345 }
00346 else if ( state == STATE_MENU && (s == STATE_NEWGAME || s == STATE_REPLAY) )
00347 {
00348 SoundHandler :: stopMusic( );
00349
00350
00351 string musicFile = INGAME_MUSIC;
00352 SoundHandler :: playMusic( musicFile );
00353 SoundHandler :: setMusicVolume( 25 );
00354 }
00355
00356 state = s;
00357 }
00358
00359
00360 void SFCave :: handleMenuSelect( int menuId )
00361 {
00362 switch( menuId )
00363 {
00364 case MENU_STARTGAME:
00365 changeState( STATE_NEWGAME );
00366 break;
00367
00368 case MENU_HELP:
00369 changeState( STATE_HELP );
00370 break;
00371
00372 case MENU_QUIT:
00373 changeState( STATE_QUIT );
00374 break;
00375
00376 case MENU_PLAY_REPLAY:
00377 if ( currentGame->isReplayAvailable() )
00378 changeState( STATE_REPLAY );
00379 else
00380 setMenuStatusText( "No replay available yet" );
00381 break;
00382
00383 case MENU_LOAD_REPLAY:
00384 {
00385 string replayFile = getHomeDir() + "/" + currentGame->getGameName() + ".replay";
00386
00387 currentGame->loadReplay( replayFile );
00388
00389 break;
00390 }
00391
00392 case MENU_SAVE_REPLAY:
00393 {
00394
00395 if ( currentGame->isReplayAvailable() )
00396 {
00397 string replayFile = getHomeDir() + "/" + currentGame->getGameName() + ".replay";
00398
00399 currentGame->saveReplay( replayFile );
00400 }
00401 else
00402 setMenuStatusText( "No replay available yet" );
00403
00404 break;
00405 }
00406 case MENU_CLEAR_SCORES:
00407 break;
00408
00409 case MENU_GAME_SFCAVE:
00410 if ( currentGame->getGameName() != "SFCave" )
00411 {
00412 int diff = currentGame->getDifficulty();
00413 delete currentGame;
00414 currentGame = new SFCaveGame( this, WIDTH, HEIGHT, 0 );
00415 currentGame->setDifficulty( diff );
00416
00417 saveSetting( "GameType", "SFCave" );
00418 }
00419 break;
00420
00421 case MENU_GAME_GATES:
00422 if ( currentGame->getGameName() != "Gates" )
00423 {
00424 int diff = currentGame->getDifficulty();
00425 delete currentGame;
00426 currentGame = new GatesGame( this, WIDTH, HEIGHT, 0 );
00427 currentGame->setDifficulty( diff );
00428
00429 saveSetting( "GameType", "Gates" );
00430 }
00431 break;
00432 break;
00433
00434 case MENU_GAME_FLY:
00435 if ( currentGame->getGameName() != "Fly" )
00436 {
00437 int diff = currentGame->getDifficulty();
00438 delete currentGame;
00439 currentGame = new FlyGame( this, WIDTH, HEIGHT, 0 );
00440 currentGame->setDifficulty( diff );
00441
00442 saveSetting( "GameType", "Fly" );
00443 }
00444 break;
00445
00446 case MENU_DIFFICULTY_EASY:
00447 currentGame->setDifficulty( MENU_DIFFICULTY_EASY );
00448 saveSetting( "GameDifficulty", "Easy" );
00449 break;
00450
00451 case MENU_DIFFICULTY_NORMAL:
00452 currentGame->setDifficulty( MENU_DIFFICULTY_NORMAL );
00453 saveSetting( "GameDifficulty", "Medium" );
00454 break;
00455
00456 case MENU_DIFFICULTY_HARD:
00457 currentGame->setDifficulty( MENU_DIFFICULTY_HARD );
00458 saveSetting( "GameDifficulty", "Hard" );
00459 break;
00460
00461 case MENU_DIFFICULTY_CUSTOM:
00462 currentGame->setDifficulty( MENU_DIFFICULTY_CUSTOM );
00463 saveSetting( "GameDifficulty", "Custom" );
00464 break;
00465
00466 case MENU_SOUND_ON:
00467 SoundHandler :: setSoundsOn( true );
00468 saveSetting( "SoundOn", "true" );
00469 break;
00470
00471 case MENU_SOUND_OFF:
00472 SoundHandler :: setSoundsOn( false );
00473 saveSetting( "SoundOn", "false" );
00474 break;
00475
00476 case MENU_MUSIC_ON:
00477 SoundHandler :: setMusicOn( true );
00478 saveSetting( "MusicOn", "true" );
00479 break;
00480
00481 case MENU_MUSIC_OFF:
00482 SoundHandler :: setMusicOn( false );
00483 saveSetting( "MusicOn", "false" );
00484 break;
00485
00486 case MENU_CUSTOM_THRUST:
00487 customPlayerMenuVal = PLAYER_THRUST;
00488 origValue = currentGame->getPlayer()->getValue( customPlayerMenuVal );
00489 setMenuStatusText( currentGame->getPlayer()->getValueString( customPlayerMenuVal ) );
00490 break;
00491 case MENU_CUSTOM_GRAVITY:
00492 customPlayerMenuVal = PLAYER_GRAVITY;
00493 origValue = currentGame->getPlayer()->getValue( customPlayerMenuVal );
00494 setMenuStatusText( currentGame->getPlayer()->getValueString( customPlayerMenuVal ) );
00495 break;
00496 case MENU_CUSTOM_MAXSPEEDUP:
00497 customPlayerMenuVal = PLAYER_MAX_SPEED_UP;
00498 origValue = currentGame->getPlayer()->getValue( customPlayerMenuVal );
00499 setMenuStatusText( currentGame->getPlayer()->getValueString( customPlayerMenuVal ) );
00500 break;
00501 case MENU_CUSTOM_MAXSPEEDDOWN:
00502 customPlayerMenuVal = PLAYER_MAX_SPEED_DOWN;
00503 origValue = currentGame->getPlayer()->getValue( customPlayerMenuVal );
00504 setMenuStatusText( currentGame->getPlayer()->getValueString( customPlayerMenuVal ) );
00505 break;
00506 case MENU_CUSTOM_INCREASE:
00507 currentGame->getPlayer()->incValue( customPlayerMenuVal );
00508 setMenuStatusText( currentGame->getPlayer()->getValueString( customPlayerMenuVal ) );
00509 break;
00510 case MENU_CUSTOM_DECREASE:
00511 currentGame->getPlayer()->decValue( customPlayerMenuVal );
00512 setMenuStatusText( currentGame->getPlayer()->getValueString( customPlayerMenuVal ) );
00513 break;
00514 case MENU_CUSTOM_SAVE:
00515 {
00516
00517 string key = currentGame->getGameName() + "_custom_player_" + currentGame->getPlayer()->getValueTypeString( customPlayerMenuVal );
00518 saveSetting( key, currentGame->getPlayer()->getValue( customPlayerMenuVal ) );
00519
00520 break;
00521 }
00522 case MENU_CUSTOM_CANCEL:
00523 currentGame->getPlayer()->setValue( customPlayerMenuVal, origValue );
00524 break;
00525
00526 default:
00527 break;
00528 }
00529 }
00530
00531 void SFCave :: setMenuStatusText( string statusText )
00532 {
00533 menu->setStatusText( statusText );
00534 }
00535
00536
00537 void SFCave :: saveSetting( string key, string val )
00538 {
00539 Settings cfg( "sfcave-sdl" );
00540 cfg.writeSetting( key, val );
00541 }
00542
00543 void SFCave :: saveSetting( string key, int val )
00544 {
00545 Settings cfg( "sfcave-sdl" );
00546 cfg.writeSetting( key, val );
00547 }
00548
00549 void SFCave :: saveSetting( string key, long val )
00550 {
00551 Settings cfg( "sfcave-sdl" );
00552 cfg.writeSetting( key, val );
00553 }
00554
00555 void SFCave :: saveSetting( string key, double val )
00556 {
00557 Settings cfg( "sfcave-sdl" );
00558 cfg.writeSetting( key, val );
00559 }
00560
00561 string SFCave :: loadSetting( string key, string defaultVal )
00562 {
00563 string val;
00564 Settings cfg( "sfcave-sdl" );
00565 cfg.readSetting( key, val );
00566
00567 if ( val == "" )
00568 val = defaultVal;
00569
00570 return val;
00571 }
00572
00573 bool SFCave :: loadBoolSetting( string key, bool defaultVal )
00574 {
00575 bool val = defaultVal;
00576 Settings cfg( "sfcave-sdl" );
00577 cfg.readSetting( key, val );
00578
00579 return val;
00580 }
00581
00582 int SFCave :: loadIntSetting( string key, int defaultVal )
00583 {
00584 int val = defaultVal;
00585 Settings cfg( "sfcave-sdl" );
00586 cfg.readSetting( key, val );
00587
00588 return val;
00589 }
00590
00591 double SFCave :: loadDoubleSetting( string key, double defaultVal )
00592 {
00593 double val = defaultVal;
00594 Settings cfg( "sfcave-sdl" );
00595 cfg.readSetting( key, val );
00596
00597 return val;
00598 }
00599
00600
00601 void SFCave :: calcFPS()
00602 {
00603 struct timeb tp;
00604 ftime( &tp );
00605 start =(tp.time%10000)*10000 + tp.millitm;
00606 if ( start - time1 >= 1000 )
00607 {
00608 actualFPS = FPS;
00609 FPS = 0;
00610 time1 = start;
00611 }
00612 else
00613 FPS ++;
00614 }
00615
00616 void SFCave :: FPSDelay()
00617 {
00618 struct timeb tp;
00619
00620 ftime( &tp );
00621 end = abs((tp.time%10000)*10000 + tp.millitm);
00622 if ( end-start < (1000/maxFPS) )
00623 {
00624 if ( (1000/maxFPS)-(end-start) > 500 )
00625 {
00626
00627 printf( "WARNING WILL ROBINSON! delay = %ld - start %ld, end %ld\n", (1000/maxFPS)-(end-start), start, end );
00628 SDL_Delay( 5 );
00629 }
00630 else
00631 SDL_Delay((1000/maxFPS)-(end-start) );
00632 }
00633 }