Back to index

extremetuxracer  0.5beta
event_race_select.cpp
Go to the documentation of this file.
00001 /* 
00002  * PPRacer 
00003  * Copyright (C) 2004-2005 Volker Stroebel <volker@planetpenguin.de>
00004  *
00005  * Copyright (C) 1999-2001 Jasmin F. Patry
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 
00022 #include "event_race_select.h"
00023 
00024 #include "game_config.h"
00025 
00026 #include "ppgltk/font.h"
00027 #include "ppgltk/audio/audio.h"
00028 
00029 #include "course_load.h"
00030 #include "textures.h"
00031 #include "joystick.h"
00032 
00033 #include "stuff.h"
00034 #include "game_mgr.h"
00035 #include "player.h"
00036 
00037 #include <iostream>
00038 
00039 static std::list<CourseData>::iterator curElem;
00040 
00041 EventRaceSelect::EventRaceSelect()
00042 {
00043     pp::Vec2d pos(0,0);
00044 
00045        mp_titleLbl = new pp::Label(pos, "heading", _("Select a race"));
00046        mp_titleLbl->alignment.center();
00047        mp_titleLbl->alignment.middle();   
00048        
00049        
00050     mp_backBtn = new pp::Button(pos,
00051                            pp::Vec2d(150, 40), 
00052                            "button_label", 
00053                            _("Back") );
00054     mp_backBtn->setHilitFontBinding( "button_label_hilit" );
00055     mp_backBtn->signalClicked.Connect(pp::CreateSlot(this,&EventRaceSelect::back));
00056 
00057     mp_startBtn = new pp::Button(pos,
00058                             pp::Vec2d(150, 40),
00059                             "button_label",
00060                             _("Race!") );
00061     mp_startBtn->setHilitFontBinding( "button_label_hilit" );
00062     mp_startBtn->setDisabledFontBinding( "button_label_disabled" );
00063        mp_startBtn->signalClicked.Connect(pp::CreateSlot(this,&EventRaceSelect::start));
00064 
00065        if ( GameMode::prevmode != GAME_OVER ) {
00066               curElem = gameMgr->getCurrentCup().raceList.begin();
00067     } else {
00068               if( gameMgr->wasRaceWon() ){
00069                      if(curElem != --gameMgr->getCurrentCup().raceList.end()){
00070                             curElem++;
00071                      }
00072               }
00073     }
00074 
00075        mp_raceListbox = new pp::Listbox<CourseData>(pos,
00076                                pp::Vec2d(460, 44),
00077                                "listbox_item",
00078                                gameMgr->getCurrentCup().raceList);
00079     mp_raceListbox->setCurrentItem( curElem );
00080        mp_raceListbox->signalChange.Connect(pp::CreateSlot(this,&EventRaceSelect::listboxItemChange));
00081     // Create text area 
00082      
00083     mp_descTa = new pp::Textarea( pos,
00084                             pp::Vec2d(312, 107),
00085                             "race_description",
00086                             "" );
00087        mp_descTa->setText( (*curElem).description.c_str() );
00088 
00089 // Create preview
00090 
00091        mp_previewSSBtn = new pp::SSButton( pos, pp::Vec2d(132,99), 1);
00092        handlePreview( (*curElem).course.c_str() );
00093        mp_previewSSBtn->signalClicked.Connect(pp::CreateSlot(this,&EventRaceSelect::start));
00094 
00095     // Create state buttons - only if practicing or if cup_complete
00096     
00097        mp_conditionsSSBtn = NULL;
00098        mp_windSSBtn = NULL;
00099        mp_snowSSBtn = NULL;
00100        mp_mirrorSSBtn = NULL;
00101     
00102     updateStates();
00103 
00104     play_music( "start_screen" );
00105 }
00106 
00107 EventRaceSelect::~EventRaceSelect()
00108 {
00109        delete mp_titleLbl;
00110        delete mp_backBtn;
00111        delete mp_startBtn;
00112        delete mp_raceListbox;
00113        delete mp_previewSSBtn;
00114        delete mp_conditionsSSBtn;
00115        delete mp_snowSSBtn;
00116        delete mp_windSSBtn;
00117        delete mp_mirrorSSBtn;
00118        delete mp_descTa;
00119 }
00120 
00121 void
00122 EventRaceSelect::loop(float timeStep)
00123 {
00124        update_audio();
00125 
00126     set_gl_options( GUI );
00127 
00128     clear_rendering_context();
00129 
00130     UIMgr.setupDisplay();
00131 
00132        // todo: detect wether the cours is windy
00133        // in the meantime we always set windy to true
00134        drawSnow(timeStep, true);
00135        
00136     theme.drawMenuDecorations();
00137 
00138     setWidgetPositionsAndDrawDecorations();
00139 
00140     UIMgr.draw();
00141 
00142     reshape( getparam_x_resolution(), getparam_y_resolution() );
00143 
00144     winsys_swap_buffers();
00145 }
00146 
00147 void
00148 EventRaceSelect::setWidgetPositionsAndDrawDecorations()
00149 {
00150     int w = getparam_x_resolution();
00151     int h = getparam_y_resolution();
00152     int box_width, box_height, box_max_y;
00153     int x_org, y_org;
00154     GLuint texobj;
00155 
00156     // set the dimensions of the box in which all widgets should fit
00157     box_width = 460;
00158     box_height = 310;
00159     box_max_y = h - 128;
00160 
00161     x_org = w/2 - box_width/2;
00162     y_org = h/2 - box_height/2;
00163     if ( y_org + box_height > box_max_y ) {
00164        y_org = box_max_y - box_height;
00165     }
00166 
00167     mp_backBtn->setPosition(pp::Vec2d( x_org + 131 - mp_backBtn->getWidth()/2.0,
00168                     42 ) );
00169 
00170     mp_startBtn->setPosition(pp::Vec2d( x_org + 343 - mp_startBtn->getWidth()/2.0,
00171                     42 ) );
00172 
00173        mp_raceListbox->setPosition(pp::Vec2d( x_org,y_org + 221 ) );
00174 
00175        mp_descTa->setPosition(pp::Vec2d( x_org,y_org + 66 ) );
00176     
00177        // Draw tux life icons
00178        int i;
00179        
00180        glPushMatrix();
00181        {
00182 
00183            glTranslatef( x_org + box_width - 4*36 + 4,
00184                        y_org + 181,
00185                        0 );
00186            
00187            check_assertion( INIT_NUM_LIVES == 4, 
00188                           "Assumption about number of lives invalid -- "
00189                           "need to recode this part" );
00190 
00191            if ( !get_texture_binding( "tux_life", &texobj ) ) {
00192               texobj = 0;
00193            }
00194 
00195            glBindTexture( GL_TEXTURE_2D, texobj );
00196 
00197            for ( i=0; i<4; i++ ) {
00198               pp::Vec2d ll, ur;
00199               if ( players[0].getLives() > i ) {
00200                   ll = pp::Vec2d( 0, 0.5 );
00201                   ur = pp::Vec2d( 1, 1 );
00202               } else {
00203                   ll = pp::Vec2d( 0, 0 );
00204                   ur = pp::Vec2d( 1, 0.5 );
00205               }
00206               glBegin( GL_QUADS );
00207               {
00208                   glTexCoord2f( ll.x, ll.y );
00209                   glVertex2f( 0, 0 );
00210 
00211                   glTexCoord2f( ur.x, ll.y );
00212                   glVertex2f( 32, 0 );
00213 
00214                   glTexCoord2f( ur.x, ur.y );
00215                   glVertex2f( 32, 32 );
00216 
00217                   glTexCoord2f( ll.x, ur.y );
00218                   glVertex2f( 0, 32 );
00219               }
00220               glEnd();
00221 
00222               glTranslatef( 36, 0, 0 );
00223            }
00224        }
00225        glPopMatrix();
00226     
00227     // Draw other stuff
00228        
00229        mp_titleLbl->setPosition(pp::Vec2d(x_org + box_width/2.0,y_org + 310));
00230        
00231        // Draw text indicating race requirements (if race not completed), 
00232     //   or results in race if race completed.
00233     drawStatusMsg( x_org, y_org, box_width, box_height );
00234 
00235     // Draw preview
00236        mp_previewSSBtn->setPosition(pp::Vec2d( x_org+box_width-136, y_org+70 ));
00237        
00238        //std::list<CourseData>::iterator elem;
00239        //elem = mp_raceListbox->getCurrentItem();
00240 
00241     glDisable( GL_TEXTURE_2D );
00242 
00243     glColor4f( 1.0, 1.0, 1.0, 1.0 );
00244     glBegin( GL_QUADS );
00245     {
00246               glVertex2f( x_org+box_width-140, y_org+66 );
00247               glVertex2f( x_org+box_width, y_org+66 );
00248               glVertex2f( x_org+box_width, y_org+66+107 );
00249               glVertex2f( x_org+box_width-140, y_org+66+107 );
00250     }
00251     glEnd();
00252 
00253     glEnable( GL_TEXTURE_2D );
00254 /* Old preview system
00255     if ( !get_texture_binding( (*elem).course.c_str(), &texobj ) ) {
00256        if ( !get_texture_binding( "no_preview", &texobj ) ) {
00257            texobj = 0;
00258        }
00259     }
00260 
00261     glBindTexture( GL_TEXTURE_2D, texobj );
00262 
00263     glBegin( GL_QUADS );
00264     {
00265        glTexCoord2d( 0, 0);
00266        glVertex2f( x_org+box_width-136, y_org+70 );
00267 
00268        glTexCoord2d( 1, 0);
00269        glVertex2f( x_org+box_width-4, y_org+70 );
00270 
00271        glTexCoord2d( 1, 1);
00272        glVertex2f( x_org+box_width-4, y_org+70+99 );
00273 
00274        glTexCoord2d( 0, 1);
00275        glVertex2f( x_org+box_width-136, y_org+70+99 );
00276     }
00277     glEnd();
00278 */
00279 }
00280 
00281 void
00282 EventRaceSelect::drawStatusMsg( int x_org, int y_org, int box_width, int box_height )
00283 {
00284     const char *msg;
00285     char buff[BUFF_LEN];
00286     bool draw_stats = true; 
00287        
00288        switch(state){
00289               case DEAD:
00290                      msg = _("You don't have any lives left.");
00291               draw_stats = false;
00292                      break;
00293               
00294               case RACEWON:
00295                      msg = _("Race won! Your result:"); 
00296                      break;
00297               
00298               case PLAYABLE:
00299                      msg = _("Needed to advance:");
00300                      break;
00301               
00302               case UNPLAYABLE:
00303                      msg = _("You can't enter this race yet.");
00304                      draw_stats = false;
00305                      break;
00306               default:
00307                      msg = "";
00308                      draw_stats = false;
00309                      break;
00310        }
00311               
00312        pp::Font *font = pp::Font::get("race_requirements");
00313        pp::Font *labelfont = pp::Font::get("race_requirements_label");
00314        
00315        labelfont->draw(msg,pp::Vec2d(x_org,y_org + 200));
00316        
00317        if ( draw_stats ) {
00318               int minutes;
00319               int seconds;
00320               int hundredths;
00321 
00322               pp::Vec2d pos(x_org,y_org + 184);
00323               
00324               getTimeComponents( m_data.time, minutes, seconds, hundredths );
00325               
00326               const char* string = _("Time:");
00327               labelfont->draw(string, pos);
00328               pos.x+=labelfont->advance(string) + 5;
00329               
00330               sprintf( buff, _("%02d:%02d.%02d"),minutes, seconds, hundredths);
00331               font->draw(buff, pos);
00332               
00333               pos.x+=75;
00334               string = _("Herring:");
00335               labelfont->draw(string, pos);
00336               pos.x+=labelfont->advance(string) + 5;
00337 
00338               sprintf( buff, "%03d", m_data.herring ); 
00339               font->draw(buff, pos);
00340               
00341               pos.x+=40;    
00342               string = _("Score:");
00343               labelfont->draw(string, pos);
00344               pos.x+=labelfont->advance(string) + 5;
00345        
00346               sprintf( buff, "%06d", m_data.score );
00347               font->draw(buff, pos);
00348        
00349        }
00350               
00351        const char* string = _("Contributed by:");
00352        pp::Vec2d pos(x_org,y_org+50);
00353        labelfont->draw(string,pos);
00354        pos.x += labelfont->advance(string) + 5;
00355               
00356        if(!(*curElem).contributed.empty()){
00357               font->draw((*curElem).contributed.c_str(),pos);         
00358        }else{
00359               font->draw(_("Unknown"),pos);
00360        }      
00361 }
00362 
00363 
00364 void
00365 EventRaceSelect::updateStates()
00366 {
00367        //mp_startBtn->setSensitive( true );
00368        if ( players[0].getLives() <= 0 ) {
00369               state=DEAD;
00370               mp_startBtn->setSensitive( false );
00371               mp_previewSSBtn->setSensitive( false );
00372        } else {
00373               m_data.won=false;
00374               players[0].getCupCourseData(
00375                             std::string(gameMgr->getCurrentEvent().name),
00376                             std::string(gameMgr->getCurrentCup().name),
00377                             std::string((*curElem).name),
00378                             m_data);
00379        
00380               if(m_data.won){
00381                      state=RACEWON;
00382                      mp_startBtn->setSensitive( false );
00383                      mp_previewSSBtn->setSensitive( false );
00384               }else{
00385                      
00386                      difficulty_level_t d = gameMgr->difficulty;
00387                      m_data.time = (*curElem).time_req[d];
00388                      m_data.herring = (*curElem).herring_req[d];
00389                      m_data.score = int((*curElem).score_req[d]);
00390 
00391                      if(curElem==gameMgr->getCurrentCup().raceList.begin()){
00392                             state=PLAYABLE;
00393                             mp_startBtn->setSensitive( true );
00394                             mp_previewSSBtn->setSensitive( true );
00395                      }else{
00396                             PlayerCourseData prev;
00397                             curElem--;
00398                             players[0].getCupCourseData(
00399                                    std::string(gameMgr->getCurrentEvent().name),
00400                                    std::string(gameMgr->getCurrentCup().name),
00401                                    std::string((*curElem).name),
00402                                    prev);
00403                             curElem++;
00404                             
00405                             if(prev.won){
00406                                    state=PLAYABLE;
00407                                    mp_startBtn->setSensitive( true );
00408                                    mp_previewSSBtn->setSensitive( true );
00409                             } else {
00410                                    state=UNPLAYABLE;
00411                                    mp_startBtn->setSensitive( false );
00412                                    mp_previewSSBtn->setSensitive( false );
00413                             }
00414                      }
00415               }
00416        }
00417 }
00418 
00419 void
00420 EventRaceSelect::back()
00421 {
00422     gameMgr->setRaceHasToBeRetried(false);
00423        set_game_mode( EVENT_SELECT );
00424     UIMgr.setDirty();
00425 }
00426 
00427 void
00428 EventRaceSelect::start()
00429 {
00430     if(mp_startBtn->getSensitive()) {
00431            mp_startBtn->setHighlight( true );
00432            loop( 0 );
00433               gameMgr->setCurrentRace(curElem);
00434 
00435            set_game_mode( LOADING );
00436     }
00437 }
00438 
00439 
00440 void
00441 EventRaceSelect::listboxItemChange()
00442 {
00443        curElem = mp_raceListbox->getCurrentItem();
00444        mp_descTa->setText( (*curElem).description.c_str() );
00445        handlePreview( (*curElem).course.c_str() );
00446        updateStates();
00447        UIMgr.setDirty();
00448 }
00449 
00450 void
00451 EventRaceSelect::handlePreview(const char* preview)
00452 {
00453        GLuint texobj;
00454        if ( get_texture_binding( preview, &texobj ) ) 
00455               mp_previewSSBtn->setStateImage(0, preview, pp::Vec2d(0.0, 0.0), pp::Vec2d(1.0, 1.0), pp::Color::white);  
00456        else
00457               mp_previewSSBtn->setStateImage(0, "no_preview", pp::Vec2d(0.0, 0.0), pp::Vec2d(1.0, 1.0), pp::Color::white);
00458        
00459 }
00460 
00461 bool
00462 EventRaceSelect::keyPressEvent(SDLKey key)
00463 {
00464        switch (key){
00465               case SDLK_UP:
00466               case SDLK_LEFT:
00467                      mp_raceListbox->gotoPrevItem();
00468               return true;
00469               case SDLK_RIGHT:
00470               case SDLK_DOWN:
00471                      mp_raceListbox->gotoNextItem();
00472               return true;
00473               case SDLK_RETURN:
00474               mp_startBtn->simulateMouseClick();
00475                      UIMgr.setDirty();
00476                      return true;
00477               case SDLK_ESCAPE:
00478               mp_backBtn->simulateMouseClick();
00479                      UIMgr.setDirty();
00480                      return true;
00481               case 'c': 
00482               mp_conditionsSSBtn->simulateMouseClick();
00483               return true;
00484               case 'w': 
00485               mp_windSSBtn->simulateMouseClick();
00486               return true;
00487               case 'm':
00488               mp_mirrorSSBtn->simulateMouseClick();
00489               return true;
00490               default:
00491                      return false;
00492        }      
00493 }