Back to index

supertuxkart  0.5+dfsg1
main.cpp
Go to the documentation of this file.
00001 // $Id: main.cpp 2111 2008-05-31 07:04:30Z cosmosninja $
00002 //
00003 //  SuperTuxKart - a fun racing game with go-kart
00004 //  Copyright (C) 2004-2005 Steve Baker <sjbaker1@airmail.net>
00005 //  Copyright (C) 2006 Joerg Henrichs, Steve Baker
00006 //
00007 //  This program is free software; you can redistribute it and/or
00008 //  modify it under the terms of the GNU General Public License
00009 //  as published by the Free Software Foundation; either version 2
00010 //  of the License, or (at your option) any later version.
00011 //
00012 //  This program is distributed in the hope that it will be useful,
00013 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 //  GNU General Public License for more details.
00016 //
00017 //  You should have received a copy of the GNU General Public License
00018 //  along with this program; if not, write to the Free Software
00019 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00020 
00021 #ifdef __APPLE__
00022 // Necessary for Macs when using SDL without Xwindows: this include
00023 // will rename main to SDLmain, and a new main program will be linked
00024 // in from the library, causing a correct framework to be set up
00025 #  include "SDL/SDL.h"
00026 #endif
00027 
00028 #ifdef WIN32
00029 #  ifdef __CYGWIN__
00030 #    include <unistd.h>
00031 #  endif
00032 #  include <windows.h>
00033 #  ifdef _MSC_VER
00034 #    include <io.h>
00035 #    include <direct.h>
00036 #  endif
00037 #else
00038 #  include <unistd.h>
00039 #endif
00040 #include <stdexcept>
00041 #include <cstdio>
00042 #include <string>
00043 #include <sstream>
00044 #include <algorithm>
00045 
00046 #include "user_config.hpp"
00047 #include "unlock_manager.hpp"
00048 #include "track_manager.hpp"
00049 #include "track.hpp"
00050 #include "kart_properties_manager.hpp"
00051 #include "kart.hpp"
00052 #include "projectile_manager.hpp"
00053 #include "race_manager.hpp"
00054 #include "file_manager.hpp"
00055 #include "loader.hpp"
00056 #include "game_manager.hpp"
00057 #include "widget_manager.hpp"
00058 #include "material_manager.hpp"
00059 #include "sdldrv.hpp"
00060 #include "callback_manager.hpp"
00061 #include "history.hpp"
00062 #include "herring_manager.hpp"
00063 #include "attachment_manager.hpp"
00064 #include "sound_manager.hpp"
00065 #include "stk_config.hpp"
00066 #include "translation.hpp"
00067 #include "highscore_manager.hpp"
00068 #include "gui/menu_manager.hpp"
00069 #include "scene.hpp"
00070 
00071 // Only needed for bullet debug!
00072 #ifdef __APPLE__
00073 #  include <GLUT/glut.h>
00074 #else
00075 #  include <GL/glut.h>
00076 #endif
00077 
00078 void cmdLineHelp (char* invocation)
00079 {
00080     fprintf ( stdout,
00081     "Usage: %s [OPTIONS]\n\n"
00082     "Run SuperTuxKart, a racing game with go-kart that features"
00083     " the Tux and friends.\n\n"
00084     "Options:\n"
00085     "  -N,  --no-start-screen  Quick race\n"
00086     "  -t,  --track NAME       Start at track NAME (see --list-tracks)\n"
00087     "       --stk-config FILE  use ./data/FILE instead of ./data/stk_config.data\n"
00088     "  -l,  --list-tracks      Show available tracks\n"
00089     "  -k,  --numkarts NUM     Number of karts on the racetrack\n"
00090     "       --kart NAME        Use kart number NAME (see --list-karts)\n"
00091     "       --list-karts       Show available karts\n"
00092     "       --laps N           Define number of laps to N\n"
00093     "       --mode N           N=1 novice, N=2 driver, N=3 racer\n"
00094     "  --players n             Define number of players to between 1 and 4.\n"
00095     //FIXME     "  --reverse               Enable reverse mode\n"
00096     //FIXME     "  --mirror                Enable mirror mode (when supported)\n"
00097     "       --herring STYLE    Use STYLE as your herring style\n"
00098     "  -f,  --fullscreen       Fullscreen display\n"
00099     "  -w,  --windowed         Windowed display (default)\n"
00100     "  -s,  --screensize WxH   Set the screen size (e.g. 320x200)\n"
00101     "  -v,  --version          Show version\n"
00102     // should not be used by unaware users:
00103     // "  --profile            Enable automatic driven profile mode for 20 seconds\n"
00104     // "  --profile=n          Enable automatic driven profile mode for n seconds\n"
00105     // "                       if n<0 --> (-n) = number of laps to drive
00106     // "  --history            Replay history file 'history.dat'\n"
00107     "  --log=terminal          Write messages to screen\n"
00108     "  --log=file              Write messages/warning to log files stdout.log/stderr.log\n"
00109     "  -h,  --help             Show this help\n"
00110     "\n"
00111     "You can visit SuperTuxKart's homepage at "
00112     "http://supertuxkart.sourceforge.net\n\n", invocation
00113     );
00114 }   // cmdLineHelp
00115 
00116 //=============================================================================
00117 int handleCmdLine(int argc, char **argv)
00118 {
00119     int n;
00120     for(int i=1; i<argc; i++)
00121     {
00122         if(argv[i][0] != '-') continue;
00123         if ( !strcmp(argv[i], "--help"    ) ||
00124              !strcmp(argv[i], "-help"     ) ||
00125              !strcmp(argv[i], "--help" ) ||
00126              !strcmp(argv[i], "-help" ) ||
00127              !strcmp(argv[i], "-h")       )
00128         {
00129             cmdLineHelp(argv[0]);
00130             return 0;
00131         }
00132         else if(!strcmp(argv[i], "--keyboard-debug"))
00133         {
00134             user_config->m_keyboard_debug=true;
00135         }
00136         else if(sscanf(argv[i], "--track-debug=%d",&n)==1)
00137         {
00138             user_config->m_track_debug=n;
00139         }
00140         else if(!strcmp(argv[i], "--track-debug"))
00141         {
00142             user_config->m_track_debug=1;
00143         }
00144         else if(!strcmp(argv[i], "--bullet-debug"))
00145         {
00146             user_config->m_bullet_debug=1;
00147         }
00148         else if( (!strcmp(argv[i], "--kart") && i+1<argc ))
00149         {
00150             std::string filename=file_manager->getKartFile(std::string(argv[i+1])+".tkkf");
00151             if(filename!="")
00152             {
00153                 race_manager->setPlayerKart(0, argv[i+1]);
00154                 fprintf ( stdout, "You choose to use kart '%s'.\n", argv[i+1] ) ;
00155             }
00156             else
00157             {
00158                    fprintf(stdout, "Kart '%s' not found, ignored.\n",
00159                               argv[i+1]);
00160             }
00161         }
00162         else if( (!strcmp(argv[i], "--mode") && i+1<argc ))
00163         {
00164             switch (atoi(argv[i+1]))
00165             {
00166             case 1:
00167                 race_manager->setDifficulty(RaceManager::RD_EASY);
00168                 break;
00169             case 2:
00170                 // FIXME: no medium AI atm race_manager->setDifficulty(RaceManager::RD_MEDIUM);
00171                 race_manager->setDifficulty(RaceManager::RD_HARD);
00172                 break;
00173             case 3:
00174                 race_manager->setDifficulty(RaceManager::RD_HARD);
00175                 break;
00176             }
00177         }
00178         else if( (!strcmp(argv[i], "--track") || !strcmp(argv[i], "-t"))
00179                  && i+1<argc                                              )
00180         {
00181             if (!unlock_manager->isLocked(argv[i+1]))
00182             {
00183                 race_manager->setTrack(argv[i+1]);
00184                 fprintf ( stdout, "You choose to start in track: %s.\n", argv[i+1] ) ;
00185             }
00186             else 
00187             {
00188                 fprintf(stdout, "Track %s has not been unlocked yet. \n", argv[i+1]);
00189                 fprintf(stdout, "Use --list-tracks to list available tracks.\n\n");
00190                 return 0;
00191             }    
00192         }
00193         else if( (!strcmp(argv[i], "--stk-config")) && i+1<argc )
00194         {
00195             stk_config->load(file_manager->getConfigFile(argv[i+1]));
00196             fprintf ( stdout, "STK config will be read from %s.\n", argv[i+1] ) ;
00197         }
00198         else if( (!strcmp(argv[i], "--numkarts") || !strcmp(argv[i], "-k")) &&
00199                  i+1<argc )
00200         {
00201             user_config->m_karts = atoi(argv[i+1]);
00202             if(user_config->m_karts>stk_config->m_max_karts) {
00203                 fprintf(stdout, "Number of karts reset to maximum number %d\n",
00204                                   stk_config->m_max_karts);
00205                 user_config->m_karts = stk_config->m_max_karts;
00206             }
00207             race_manager->setNumKarts(user_config->m_karts );
00208             fprintf ( stdout, "%d karts will be used.\n", user_config->m_karts);
00209             i++;
00210         }
00211         else if( !strcmp(argv[i], "--list-tracks") || !strcmp(argv[i], "-l") )
00212         {
00213 
00214             fprintf ( stdout, "  Available tracks:\n" );
00215             for (size_t i = 0; i != track_manager->getTrackCount(); i++)
00216             {
00217                 const Track *track = track_manager->getTrack(i);
00218                 if (!unlock_manager->isLocked(track->getIdent()))
00219                 {
00220                     fprintf ( stdout, "\t%10s: %s\n",
00221                               track->getIdent().c_str(),
00222                               track->getName());
00223                 }
00224             }    
00225 
00226             fprintf ( stdout, "Use --track N to choose track.\n\n");
00227             delete track_manager;
00228             track_manager = 0;
00229 
00230             return 0;
00231         }
00232         else if( !strcmp(argv[i], "--list-karts") )
00233         {
00234             bool dont_load_models=true;
00235             kart_properties_manager->loadKartData(dont_load_models) ;
00236 
00237             fprintf ( stdout, "  Available karts:\n" );
00238             for (unsigned int i = 0; NULL != kart_properties_manager->getKartById(i); i++)
00239             {
00240                 const KartProperties* KP= kart_properties_manager->getKartById(i);
00241                 fprintf (stdout, "\t%10s: %s\n", KP->getIdent(), KP->getName().c_str());
00242             }
00243             fprintf ( stdout, "\n" );
00244 
00245             return 0;
00246         }
00247         else if (    !strcmp(argv[i], "--no-start-screen")
00248                      || !strcmp(argv[i], "-N")                )
00249         {
00250             user_config->m_no_start_screen = true;
00251             //FIXME} else if ( !strcmp(argv[i], "--reverse") ) {
00252             //FIXME:fprintf ( stdout, "Enabling reverse mode.\n" ) ;
00253             //FIXME:raceSetup.reverse = 1;
00254         }
00255         else if ( !strcmp(argv[i], "--mirror") )
00256         {
00257 #ifdef SSG_BACKFACE_COLLISIONS_SUPPORTED
00258             fprintf ( stdout, "Enabling mirror mode.\n" ) ;
00259             //raceSetup.mirror = 1;
00260 #else
00261             //raceSetup.mirror = 0 ;
00262 #endif
00263 
00264         }
00265         else if ( !strcmp(argv[i], "--laps") && i+1<argc )
00266         {
00267             fprintf ( stdout, "You choose to have %d laps.\n", atoi(argv[i+1]) ) ;
00268             race_manager->setNumLaps(atoi(argv[i+1]));
00269         }
00270         /* FIXME:
00271         else if ( !strcmp(argv[i], "--players") && i+1<argc ) {
00272           raceSetup.numPlayers = atoi(argv[i+1]);
00273 
00274           if ( raceSetup.numPlayers < 0 || raceSetup.numPlayers > 4) {
00275         fprintf ( stderr,
00276         "You choose an invalid number of players: %d.\n",
00277         raceSetup.numPlayers );
00278         cmdLineHelp(argv[0]);
00279         return 0;
00280           }
00281           fprintf ( stdout, "You choose to have %d players.\n", atoi(argv[i+1]) ) ;
00282         }
00283         */
00284 #if !defined(WIN32) && !defined(__CYGWIN)
00285         else if ( !strcmp(argv[i], "--fullscreen") || !strcmp(argv[i], "-f"))
00286         {
00287             // Check that current res is not blacklisted
00288             std::ostringstream o;
00289               o << user_config->m_width << "x" << user_config->m_height;
00290               std::string res = o.str();
00291             if (std::find(user_config->m_blacklist_res.begin(), 
00292               user_config->m_blacklist_res.end(),res) == user_config->m_blacklist_res.end())         
00293               user_config->m_fullscreen = true;
00294               else 
00295                      fprintf ( stdout, "Resolution %s has been blacklisted, so it is not available!\n", res.c_str());
00296         }
00297         else if ( !strcmp(argv[i], "--windowed") || !strcmp(argv[i], "-w"))
00298         {
00299             user_config->m_fullscreen = false;
00300         }
00301 #endif
00302         else if ( !strcmp(argv[i], "--screensize") || !strcmp(argv[i], "-s") )
00303         {
00304             //Check if fullscreen and new res is blacklisted
00305             int width, height;
00306             if (sscanf(argv[i+1], "%dx%d", &width, &height) == 2)
00307             {
00308               std::ostringstream o;
00309                      o << width << "x" << height;
00310                      std::string res = o.str();
00311                 if (!user_config->m_fullscreen || std::find(user_config->m_blacklist_res.begin(), 
00312                        user_config->m_blacklist_res.end(),res) == user_config->m_blacklist_res.end())
00313                 {
00314                      user_config->m_prev_width = user_config->m_width = width;
00315                             user_config->m_prev_height = user_config->m_height = height;
00316                      fprintf ( stdout, "You choose to be in %dx%d.\n", user_config->m_width,
00317                       user_config->m_height );
00318                      }
00319                      else
00320                             fprintf ( stdout, "Resolution %s has been blacklisted, so it is not available!\n", res.c_str());
00321             }
00322             else
00323             {
00324                 fprintf(stderr, "Error: --screensize argument must be given as WIDTHxHEIGHT\n");
00325                 exit(EXIT_FAILURE);
00326             }
00327         }
00328         else if( !strcmp(argv[i], "--version") ||  !strcmp(argv[i], "-v") )
00329         {
00330 #ifdef VERSION
00331             fprintf ( stdout, "SuperTuxKart, %s.\n", VERSION ) ;
00332 #endif
00333 #ifdef SVNVERSION
00334             fprintf ( stdout, "SuperTuxKart, SVN revision number '%s'.\n", SVNVERSION ) ;
00335 #endif
00336             return 0;
00337         }
00338         else if( !strcmp(argv[i], "--log=terminal"))
00339         {
00340             user_config->m_log_errors=false;
00341         }
00342         else if( !strcmp(argv[i], "--log=file"))
00343         {
00344             user_config->m_log_errors=true;
00345         }else if( sscanf(argv[i], "--profile=%d",  &n)==1)
00346         {
00347             user_config->m_profile=n;
00348            if(n<0) 
00349            {
00350                 fprintf(stdout,"Profiling %d laps\n",-n);
00351                 race_manager->setNumLaps(-n);
00352            }
00353            else
00354             {
00355                printf("Profiling: %d seconds.\n",user_config->m_profile);
00356                 race_manager->setNumLaps   (999999); // profile end depends on time
00357             }
00358         }
00359         else if( !strcmp(argv[i], "--profile") )
00360         {
00361             user_config->m_profile=20;
00362         }
00363         else if( !strcmp(argv[i], "--history") )
00364         {
00365             user_config->m_replay_history=true;
00366         }
00367         else if( !strcmp(argv[i], "--herring") && i+1<argc )
00368         {
00369             herring_manager->setUserFilename(argv[i+1]);
00370         }
00371         else
00372         {
00373             fprintf ( stderr, "Invalid parameter: %s.\n\n", argv[i] );
00374             cmdLineHelp(argv[0]);
00375             return 0;
00376         }
00377     }   // for i <argc
00378     if(user_config->m_profile)
00379     {
00380         user_config->setSFX(UserConfig::UC_DISABLE);  // Disable sound effects 
00381         user_config->setMusic(UserConfig::UC_DISABLE);// and music when profiling
00382     }
00383 
00384     return 1;
00385 }   /* handleCmdLine */
00386 
00387 //=============================================================================
00388 void InitTuxkart()
00389 {
00390     file_manager            = new FileManager();
00391     translations            = new Translations();
00392     loader                  = new Loader();
00393     loader->setCreateStateCallback(getAppState);
00394     // unlock manager is needed when reading the config file
00395     unlock_manager          = new UnlockManager();
00396     user_config             = new UserConfig();
00397     sound_manager           = new SoundManager();
00398 
00399     // The order here can be important, e.g. KartPropertiesManager needs
00400     // defaultKartProperties.
00401     history                 = new History              ();
00402     material_manager        = new MaterialManager      ();
00403     track_manager           = new TrackManager         ();
00404     stk_config              = new STKConfig            ();
00405     kart_properties_manager = new KartPropertiesManager();
00406     projectile_manager      = new ProjectileManager    ();
00407     collectable_manager     = new CollectableManager   ();
00408     callback_manager        = new CallbackManager      ();
00409     herring_manager         = new HerringManager       ();
00410     attachment_manager      = new AttachmentManager    ();
00411     highscore_manager       = new HighscoreManager     ();
00412     track_manager->loadTrackList();
00413     sound_manager->addMusicToTracks();
00414 
00415     stk_config->load(file_manager->getConfigFile("stk_config.data"));
00416     race_manager            = new RaceManager          ();
00417     // default settings for Quickstart
00418     race_manager->setNumPlayers(1);
00419     race_manager->setNumLaps   (3);
00420     race_manager->setRaceMode  (RaceManager::RM_QUICK_RACE);
00421     race_manager->setDifficulty(RaceManager::RD_HARD);
00422 }
00423 
00424 //=============================================================================
00425 
00426 int main(int argc, char *argv[] ) 
00427 {
00428     try {
00429         glutInit(&argc, argv);
00430         InitTuxkart();
00431 
00432         //handleCmdLine() needs InitTuxkart() so it can't be called first
00433         if(!handleCmdLine(argc, argv)) exit(0);
00434         
00435         if (user_config->m_log_errors) //Enable logging of stdout and stderr to logfile
00436         {
00437             std::string logoutfile = file_manager->getLogFile("stdout.log");
00438             std::string logerrfile = file_manager->getLogFile("stderr.log");
00439             std::cout << "Error messages and other text output will be logged to " ;
00440             std::cout << logoutfile << " and "<<logerrfile;
00441             if(freopen (logoutfile.c_str(),"w",stdout)!=stdout)
00442             {
00443                 fprintf(stderr, "Can not open log file '%s'. Writing to stdout instead.\n",
00444                         logoutfile.c_str());
00445             }
00446             if(freopen (logerrfile.c_str(),"w",stderr)!=stderr)
00447             {
00448                 fprintf(stderr, "Can not open log file '%s'. Writing to stderr instead.\n",
00449                         logerrfile.c_str());
00450             }
00451         }
00452         
00453         //FIXME: this needs a better organization
00454         inputDriver = new SDLDriver ();
00455         ssgInit () ;
00456         
00457         game_manager = new GameManager ();
00458         // loadMaterials needs ssgLoadTextures (internally), which can
00459         // only be called after ssgInit (since this adds the actual file_manager)
00460         // so this next call can't be in InitTuxkart. And InitPlib needs
00461         // config, which gets defined in InitTuxkart, so swapping those two
00462         // calls is not possible either ... so loadMaterial has to be done here :(
00463         material_manager        -> loadMaterial       ();
00464         kart_properties_manager -> loadKartData       ();
00465         projectile_manager      -> loadData           ();
00466         collectable_manager     -> loadCollectables   ();
00467         herring_manager         -> loadDefaultHerrings();
00468         attachment_manager      -> loadModels         ();
00469         scene = new Scene();
00470 
00471         //For some reason, calling this before the material loading screws
00472         //the background picture.
00473         fntInit();
00474         init_fonts();
00475 
00476         widget_manager   = new WidgetManager;
00477         menu_manager->switchToMainMenu();
00478 
00479         // Replay a race
00480         // =============
00481         if(user_config->m_replay_history)
00482         {
00483             // This will setup the race manager etc.
00484             history->Load();
00485             race_manager->startNew();
00486             game_manager->run();
00487             // well, actually run() will never return, since
00488             // it exits after replaying history (see history::GetNextDT()).
00489             // So the next line is just to make this obvious here!
00490             exit(-3);
00491         }
00492         
00493         // Not replaying
00494         // =============
00495         if(!user_config->m_profile)
00496         {
00497             if(user_config->m_no_start_screen)
00498             {
00499                 // Quickstart (-N)
00500                 // ===============
00501                 // all defaults are set in InitTuxkart()
00502                 race_manager->startNew();
00503             }
00504         }
00505         else  // profile
00506         {
00507 
00508             // Profiling
00509             // =========
00510             race_manager->setNumPlayers(1);
00511             race_manager->setPlayerKart(0, kart_properties_manager->getKart("tuxkart")->getIdent());
00512             race_manager->setRaceMode  (RaceManager::RM_QUICK_RACE);
00513             race_manager->setDifficulty(RaceManager::RD_HARD);
00514             race_manager->startNew();
00515         }
00516         game_manager->run();
00517 
00518     }  // try
00519     catch (std::exception &e)
00520     {
00521         fprintf(stderr,e.what());
00522         fprintf(stderr,"\nAborting SuperTuxKart\n");
00523     }
00524 
00525     /* Program closing...*/
00526 
00527     if (user_config->m_crashed) user_config->m_crashed = false;
00528     user_config->saveConfig();
00529     delete inputDriver;
00530     
00531     if (user_config->m_log_errors) //close logfiles
00532     {
00533         fclose(stderr);
00534         fclose(stdout);
00535     }
00536 
00537     delete highscore_manager;
00538     delete_fonts();
00539 
00540     return 0 ;
00541 }
00542