1 /*
2 Copyright (C) 2005 Matthias Braun <matze@braunis.de>
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18 #include <config.h>
19 
20 #include <stdexcept>
21 #include <sstream>
22 #include <iostream>
23 #include <iomanip>
24 #include <typeinfo>
25 #include <physfs.h>
26 #include <stdio.h>
27 #include <time.h>
28 
29 #include "gui/TextureManager.hpp"
30 #include "gui/ComponentLoader.hpp"
31 #include "gui/Component.hpp"
32 #include "gui/Event.hpp"
33 #include "gui/Desktop.hpp"
34 #include "gui/Button.hpp"
35 #include "gui/callback/Callback.hpp"
36 
37 #include "gui_interface/shared_globals.h"
38 #include "lincity/lin-city.h"
39 #include "lincity/fileutil.h"
40 
41 #include "CheckButton.hpp"
42 
43 #include "MainMenu.hpp"
44 #include "Util.hpp"
45 #include "Config.hpp"
46 #include "Sound.hpp"
47 #include "GameView.hpp"
48 #include "MainLincity.hpp"
49 #include "readdir.hpp"
50 
51 #include "tinygettext/gettext.hpp"
52 
53 extern void new_city(int *originx, int *originy, int random_village);
54 
MainMenu()55 MainMenu::MainMenu()
56 {
57     loadMainMenu();
58     switchMenu(mainMenu.get());
59     baseName = "";
60     lastClickTick = 0;
61     doubleClickButtonName = "";
62 }
63 
~MainMenu()64 MainMenu::~MainMenu()
65 {
66 }
67 
68 void
loadMainMenu()69 MainMenu::loadMainMenu()
70 {
71     if(mainMenu.get() == 0) {
72         mainMenu.reset(loadGUIFile("gui/mainmenu.xml"));
73 
74         // connect signals
75         Button* quitButton = getButton(*mainMenu, "QuitButton");
76         quitButton->clicked.connect(
77                 makeCallback(*this, &MainMenu::quitButtonClicked));
78         Button* continueButton = getButton(*mainMenu, "ContinueButton");
79         continueButton->clicked.connect(
80                 makeCallback(*this, &MainMenu::continueButtonClicked));
81         Button* newGameButton = getButton(*mainMenu, "NewGameButton");
82         newGameButton->clicked.connect(
83                 makeCallback(*this, &MainMenu::newGameButtonClicked));
84         Button* loadGameButton = getButton(*mainMenu, "LoadButton");
85         loadGameButton->clicked.connect(
86                 makeCallback(*this, &MainMenu::loadGameButtonClicked));
87         Button* saveGameButton = getButton(*mainMenu, "SaveButton");
88         saveGameButton->clicked.connect(
89                 makeCallback(*this, &MainMenu::saveGameButtonClicked));
90         Button* creditsButton = getButton(*mainMenu, "CreditsButton");
91         creditsButton->clicked.connect(
92                 makeCallback(*this, &MainMenu::creditsButtonClicked));
93         Button* optionsButton = getButton(*mainMenu, "OptionsButton");
94         optionsButton->clicked.connect(
95                 makeCallback(*this, &MainMenu::optionsButtonClicked));
96 
97     }
98 
99     mainMenu->resize(SDL_GetVideoSurface()->w, SDL_GetVideoSurface()->h);
100 }
101 
fillNewGameMenu()102 void MainMenu::fillNewGameMenu()
103 {
104   const std::string buttonNames[]={"File0","File1","File2","File3","File4","File5"};
105 
106   char **files= PHYSFS_enumerateFiles("opening");
107 
108   char **fptr=files;
109 
110   fileMap.clear();
111 
112   for(int i=0;i<6;i++)
113   {
114     CheckButton *button=getCheckButton(*newGameMenu.get(),buttonNames[i]);
115 
116     button->clicked.connect(makeCallback(*this,&MainMenu::selectLoadGameButtonClicked));
117     while(*fptr)
118     {
119       if(std::string(*fptr).find(".scn")!=std::string::npos)
120         break;
121       fptr++;
122     }
123     if(*fptr)
124     {
125       std::string f=*fptr;
126       if(f.length()>5){
127         f=f.substr(0,f.length()-4); // truncate .scn
128       }
129       // save real name
130       fileMap.insert(std::pair<std::string, std::string>(buttonNames[i], f ));
131       // use translated name for caption
132       button->setCaptionText(_(f.c_str()));
133       fptr++;
134     }
135     else
136       button->setCaptionText("");
137   }
138   PHYSFS_freeList(files);
139   return;
140   /* Is there a better way to add filenames to the directory? */
141   _("good_times");
142   _("bad_times");
143   _("Beach");
144   _("extreme_arid");
145   _("extreme_wetland");
146 }
147 
fillLoadMenu(bool save)148 void MainMenu::fillLoadMenu( bool save /*= false*/ )
149 {
150     const std::string buttonNames[]={"File0","File1","File2","File3","File4","File5"};
151 
152     char** rc = PHYSFS_enumerateFiles("/");
153 
154     char* curfile;
155     CheckButton *button;
156 
157     for(int i=0;i<6;i++) {
158     	char* recentfile = NULL;
159         PHYSFS_sint64 t = 0;
160 
161         std::stringstream filestart;
162         filestart << i+1 << "_";
163         if( save ){
164             button = getCheckButton(*saveGameMenu.get(),buttonNames[i]);
165         } else {
166             button = getCheckButton(*loadGameMenu.get(),buttonNames[i]);
167         }
168         //make sure Button is connected only once
169         button->clicked.clear();
170         if( save )
171             button->clicked.connect(makeCallback(*this,&MainMenu::selectSaveGameButtonClicked));
172         else {
173             button->clicked.connect(makeCallback(*this,&MainMenu::selectLoadGameButtonClicked));
174         }
175         for(char** i = rc; *i != 0; i++){
176             curfile = *i;
177             if(std::string( curfile ).find( filestart.str() ) == 0 ) {
178                 // && !( curfile->d_type & DT_DIR  ) ) is not portable. So
179                 // don't create a directoy named 2_ in a savegame-directory or
180                 // you can no longer load from slot 2.
181     	        if (t == 0) {
182                     recentfile = curfile;
183                     t = PHYSFS_getLastModTime(recentfile);
184               } else {
185                     if (PHYSFS_getLastModTime(curfile) > t) {
186 #ifdef DEBUG
187                         fprintf(stderr," %s is more recent than previous %s\n",
188                                           curfile, recentfile);
189 #endif
190                         recentfile = curfile;
191                         t = PHYSFS_getLastModTime(recentfile);
192                     }
193                 }
194             }
195         }
196 #ifdef DEBUG
197         fprintf(stderr,"Most recent file: %s\n\n",recentfile);
198 #endif
199 
200         if(t != 0) {
201             std::string f= recentfile;
202             button->setCaptionText(f);
203         } else {
204             button->setCaptionText(_("empty"));
205         }
206     }
207 }
208 
209 void
loadNewGameMenu()210 MainMenu::loadNewGameMenu()
211 {
212     if(newGameMenu.get() == 0) {
213         newGameMenu.reset(loadGUIFile("gui/newgame.xml"));
214 
215         // connect signals
216         Button* startButton = getButton(*newGameMenu, "StartButton");
217         startButton->clicked.connect(
218                 makeCallback(*this, &MainMenu::newGameStartButtonClicked));
219         Button* backButton = getButton(*newGameMenu, "BackButton");
220         backButton->clicked.connect(
221                 makeCallback(*this, &MainMenu::newGameBackButtonClicked));
222         Button* startBareButton = getButton(*newGameMenu, "StartBareButton");
223         startBareButton->clicked.connect(
224                 makeCallback(*this, &MainMenu::newGameStartBareButtonClicked));
225         Button* startVillageButton = getButton(*newGameMenu, "StartVillageButton");
226         startVillageButton->clicked.connect(
227                 makeCallback(*this, &MainMenu::newGameStartVillageClicked));
228         fillNewGameMenu();
229     }
230 
231     newGameMenu->resize(SDL_GetVideoSurface()->w, SDL_GetVideoSurface()->h);
232 }
233 
234 void
loadCreditsMenu()235 MainMenu::loadCreditsMenu()
236 {
237     if(creditsMenu.get() == 0) {
238         creditsMenu.reset(loadGUIFile("gui/credits.xml"));
239         Button* backButton = getButton(*creditsMenu, "BackButton");
240         backButton->clicked.connect(
241                 makeCallback(*this, &MainMenu::creditsBackButtonClicked));
242     }
243 
244     creditsMenu->resize(SDL_GetVideoSurface()->w, SDL_GetVideoSurface()->h);
245 }
246 
247 void
loadOptionsMenu()248 MainMenu::loadOptionsMenu()
249 {
250     if(optionsMenu.get() == 0) {
251         optionsMenu.reset(loadGUIFile("gui/options.xml"));
252         CheckButton* currentCheckButton = getCheckButton(*optionsMenu, "BackgroundMusic");
253         currentCheckButton->clicked.connect( makeCallback(*this, &MainMenu::optionsMenuButtonClicked));
254         currentCheckButton = getCheckButton(*optionsMenu, "SoundFX");
255         currentCheckButton->clicked.connect( makeCallback(*this, &MainMenu::optionsMenuButtonClicked));
256         currentCheckButton = getCheckButton(*optionsMenu, "Fullscreen");
257         currentCheckButton->clicked.connect( makeCallback(*this, &MainMenu::optionsMenuButtonClicked));
258         currentCheckButton = getCheckButton(*optionsMenu, "MusicVolumePlus");
259         currentCheckButton->clicked.connect( makeCallback(*this, &MainMenu::optionsMenuButtonClicked));
260         currentCheckButton = getCheckButton(*optionsMenu, "MusicVolumeMinus");
261         currentCheckButton->clicked.connect( makeCallback(*this, &MainMenu::optionsMenuButtonClicked));
262         currentCheckButton = getCheckButton(*optionsMenu, "FXVolumePlus");
263         currentCheckButton->clicked.connect( makeCallback(*this, &MainMenu::optionsMenuButtonClicked));
264         currentCheckButton = getCheckButton(*optionsMenu, "FXVolumeMinus");
265         currentCheckButton->clicked.connect( makeCallback(*this, &MainMenu::optionsMenuButtonClicked));
266         currentCheckButton = getCheckButton(*optionsMenu, "TrackPrev");
267         currentCheckButton->clicked.connect( makeCallback(*this, &MainMenu::optionsMenuButtonClicked));
268         currentCheckButton = getCheckButton(*optionsMenu, "TrackNext");
269         currentCheckButton->clicked.connect( makeCallback(*this, &MainMenu::optionsMenuButtonClicked));
270 
271         Button* currentButton = getButton(*optionsMenu, "BackButton");
272         currentButton->clicked.connect( makeCallback(*this, &MainMenu::creditsBackButtonClicked));
273     }
274     //adjust checkbutton-states
275     if( getConfig()->musicEnabled ){
276         getCheckButton(*optionsMenu, "BackgroundMusic")->check();
277     } else {
278         getCheckButton(*optionsMenu, "BackgroundMusic")->uncheck();
279     }
280     if( getConfig()->soundEnabled ){
281         getCheckButton(*optionsMenu, "SoundFX")->check();
282     } else {
283         getCheckButton(*optionsMenu, "SoundFX")->uncheck();
284     }
285     if( getConfig()->useFullScreen ){
286         getCheckButton(*optionsMenu, "Fullscreen")->check();
287     } else {
288         getCheckButton(*optionsMenu, "Fullscreen")->uncheck();
289     }
290     //current background track
291     musicParagraph = getParagraph( *optionsMenu, "musicParagraph");
292     musicParagraph->setText(getConfig()->playSongName);
293 
294     optionsMenu->resize(SDL_GetVideoSurface()->w, SDL_GetVideoSurface()->h);
295 }
296 
297 void
loadLoadGameMenu()298 MainMenu::loadLoadGameMenu()
299 {
300     if(loadGameMenu.get() == 0) {
301         loadGameMenu.reset(loadGUIFile("gui/loadgame.xml"));
302 
303         // connect signals
304         Button* loadButton = getButton(*loadGameMenu, "LoadButton");
305         loadButton->clicked.connect(
306                 makeCallback(*this, &MainMenu::loadGameLoadButtonClicked));
307         Button* backButton = getButton(*loadGameMenu, "BackButton");
308         backButton->clicked.connect(
309                 makeCallback(*this, &MainMenu::loadGameBackButtonClicked));
310     }
311 
312     // fill in file-names into slots
313     fillLoadMenu();
314     loadGameMenu->resize(SDL_GetVideoSurface()->w, SDL_GetVideoSurface()->h);
315 }
316 
317 void
loadSaveGameMenu()318 MainMenu::loadSaveGameMenu()
319 {
320     if(saveGameMenu.get() == 0) {
321         saveGameMenu.reset(loadGUIFile("gui/savegame.xml"));
322 
323         // connect signals
324         Button* saveButton = getButton(*saveGameMenu, "SaveButton");
325         saveButton->clicked.connect(
326                 makeCallback(*this, &MainMenu::loadGameSaveButtonClicked));
327         Button* backButton = getButton(*saveGameMenu, "BackButton");
328         backButton->clicked.connect(
329                 makeCallback(*this, &MainMenu::loadGameBackButtonClicked));
330         // fill in file-names into slots
331         fillLoadMenu( true );
332     }
333 
334     saveGameMenu->resize(SDL_GetVideoSurface()->w, SDL_GetVideoSurface()->h);
335 }
336 
337 
338 void
selectLoadGameButtonClicked(CheckButton * button,int i)339 MainMenu::selectLoadGameButtonClicked(CheckButton* button, int i){
340     selectLoadSaveGameButtonClicked( button , i,  false );
341 }
342 
343 void
selectSaveGameButtonClicked(CheckButton * button,int i)344 MainMenu::selectSaveGameButtonClicked(CheckButton* button, int i){
345     selectLoadSaveGameButtonClicked( button , i, true );
346 }
347 
348 void
selectLoadSaveGameButtonClicked(CheckButton * button,int,bool save)349 MainMenu::selectLoadSaveGameButtonClicked(CheckButton* button , int, bool save )
350 {
351     std::string fc=button->getCaptionText();
352     if( newGameMenu.get()==currentMenu ) {
353         std::map<std::string, std::string>::iterator iter;
354         iter = fileMap.find( button->getName() );
355         if( iter != fileMap.end() ){
356             fc = iter->second;
357         }
358     }
359 
360     std::string file="";
361 
362     /* I guess this should be the proper way of selecting in the menu.
363        Everytime we check a new button the last one gets unchecked.
364        If the button checked is an empty one, nothing should be opened
365        Could be done the other way around: the first time an existing item
366        is selected in the menu, an empty one could never be checked again.
367        Anyway I don't think both should be checked, when an empty is checked
368        after an existing one.
369     */
370 
371     const std::string bs[]={"File0","File1","File2","File3","File4","File5",""};
372     for(int i=0;std::string(bs[i]).length();i++) {
373         CheckButton *b=getCheckButton(*currentMenu,bs[i]);
374         if(b->getName()!=button->getName()){
375             b->uncheck();
376         } else {
377             b->check();
378         }
379     }
380 
381     if( !fc.length()) {
382         mFilename = "";
383         return;
384     }
385 
386     baseName = fc;
387     if(newGameMenu.get()==currentMenu ) {
388         file=std::string("opening/")+fc+".scn";
389     } else {
390         file=fc;
391     }
392 
393     mFilename="";
394     if(newGameMenu.get()!=currentMenu) {
395         slotNr = 1 + atoi(
396                 const_cast<char*>(button->getName().substr(4).c_str()) );
397         if( file.length() == 0){
398             mFilename = "";
399             return;
400         }
401     }
402 
403     mFilename+=file;
404     Uint32 now = SDL_GetTicks();
405 
406     //doubleclick on Filename loads File
407     if( ( fc == doubleClickButtonName ) &&  ( !save ) &&
408             ( now - lastClickTick < doubleClickTime ) ) {
409 
410         lastClickTick = 0;
411         doubleClickButtonName = "";
412         if( newGameMenu.get() == currentMenu ) {
413             //load scenario
414             newGameStartButtonClicked( 0 );
415         } else {
416             //load game
417             loadGameLoadButtonClicked( 0 );
418         }
419     } else {
420         lastClickTick = now;
421         doubleClickButtonName = fc;
422     }
423 }
424 
optionsMenuButtonClicked(CheckButton * button,int)425 void MainMenu::optionsMenuButtonClicked( CheckButton* button, int ){
426     std::string buttonName = button->getName();
427     if( buttonName == "BackgroundMusic"){
428         getSound()->playSound("Click");
429         getSound()->enableMusic( !getConfig()->musicEnabled );
430     } else if( buttonName == "MusicVolumePlus"){
431         int newVolume = getConfig()->musicVolume + 5;
432         if( newVolume > 100 ){
433            newVolume = 100;
434         }
435         if( getConfig()->musicVolume != newVolume ){
436             getSound()->setMusicVolume( newVolume );
437             getSound()->playSound("Click");
438         }
439     } else if( buttonName == "MusicVolumeMinus"){
440         int newVolume = getConfig()->musicVolume -5;
441         if( newVolume < 0 ){
442            newVolume = 0;
443         }
444         if( getConfig()->musicVolume != newVolume ){
445             getSound()->setMusicVolume( newVolume );
446             getSound()->playSound("Click");
447         }
448     } else if( buttonName == "SoundFX"){
449         getConfig()->soundEnabled = !getConfig()->soundEnabled;
450         getSound()->playSound("Click");
451     } else if( buttonName == "FXVolumePlus"){
452         int newVolume = getConfig()->soundVolume + 5;
453         if( newVolume > 100 ){
454            newVolume = 100;
455         }
456         if( getConfig()->soundVolume != newVolume ){
457             getSound()->setSoundVolume( newVolume );
458             getSound()->playSound("Click");
459         }
460     } else if( buttonName == "FXVolumeMinus"){
461         int newVolume = getConfig()->soundVolume - 5;
462         if( newVolume < 0 ){
463            newVolume = 0;
464         }
465         if( getConfig()->soundVolume != newVolume ){
466             getSound()->setSoundVolume( newVolume );
467             getSound()->playSound("Click");
468         }
469     } else if( buttonName == "Fullscreen"){
470         getSound()->playSound("Click");
471         getConfig()->useFullScreen = !getConfig()->useFullScreen;
472         if( getConfig()->restartOnChangeScreen ){
473             quitState = RESTART;
474             running = false;
475         } else {
476             initVideo(getConfig()->videoX, getConfig()->videoY);
477             loadOptionsMenu();
478         }
479     } else if( buttonName == "TrackPrev"){
480         changeTrack(false);
481     } else if( buttonName == "TrackNext"){
482         changeTrack(true);
483     } else {
484         std::cerr << "MainMenu::optionsMenuButtonClicked " << buttonName << " unknown Button!\n";
485     }
486 }
487 
488 void
changeTrack(bool next)489 MainMenu::changeTrack( bool next)
490 {
491     std::string filename;
492     std::string directory = "music/";
493     std::string fullname;
494     std::string currentname = getConfig()->playSongName;
495     std::string prevname = currentname;
496     std::string nextname = currentname;
497 
498     bool hit = false;
499 
500     char **files= PHYSFS_enumerateFiles(directory.c_str());
501     char **fptr=files;
502     while(*fptr)
503     {
504         fullname = directory;
505         fullname.append( *fptr );
506         filename.assign( *fptr );
507 
508         if(!PHYSFS_isDirectory(fullname.c_str())){
509             if( filename == currentname ){
510                 hit = true;
511             } else if ( !hit ){
512                 prevname = filename;
513             } else {
514                 nextname = filename;
515                 break;
516             }
517         }
518         fptr++;
519     }
520     PHYSFS_freeList(files);
521 
522     if(next){
523         if( nextname != currentname){
524             getSound()->playSound("Click");
525             getSound()->playMusic(nextname);
526         }
527     } else {
528         if( prevname != currentname){
529             getSound()->playSound("Click");
530             getSound()->playMusic(prevname);
531         }
532     }
533     musicParagraph->setText(getConfig()->playSongName);
534 }
535 void
quitButtonClicked(Button *)536 MainMenu::quitButtonClicked(Button* )
537 {
538     getSound()->playSound( "Click" );
539     quitState = QUIT;
540     running = false;
541 }
542 
543 void
switchMenu(Component * newMenu)544 MainMenu::switchMenu(Component* newMenu)
545 {
546     currentMenu = dynamic_cast<Desktop*> (newMenu);
547     if(!currentMenu)
548         throw std::runtime_error("Menu Component is not a Desktop");
549 }
550 
551 void
creditsButtonClicked(Button *)552 MainMenu::creditsButtonClicked(Button* )
553 {
554     getSound()->playSound( "Click" );
555     loadCreditsMenu();
556     switchMenu(creditsMenu.get());
557 }
558 
559 void
optionsButtonClicked(Button *)560 MainMenu::optionsButtonClicked(Button* )
561 {
562     getSound()->playSound( "Click" );
563     loadOptionsMenu();
564     switchMenu(optionsMenu.get());
565 }
566 
567 void
continueButtonClicked(Button *)568 MainMenu::continueButtonClicked(Button* )
569 {
570     getSound()->playSound( "Click" );
571     quitState = INGAME;
572     running = false;
573 }
574 
575 void
newGameButtonClicked(Button *)576 MainMenu::newGameButtonClicked(Button* )
577 {
578     getSound()->playSound( "Click" );
579     loadNewGameMenu();
580     switchMenu(newGameMenu.get());
581 }
582 
583 void
loadGameButtonClicked(Button *)584 MainMenu::loadGameButtonClicked(Button* )
585 {
586     getSound()->playSound( "Click" );
587     loadLoadGameMenu();
588     switchMenu(loadGameMenu.get());
589 }
590 
591 void
saveGameButtonClicked(Button *)592 MainMenu::saveGameButtonClicked(Button* )
593 {
594     getSound()->playSound( "Click" );
595     loadSaveGameMenu();
596     switchMenu(saveGameMenu.get());
597 }
598 
599 void
creditsBackButtonClicked(Button *)600 MainMenu::creditsBackButtonClicked(Button* )
601 {
602     getSound()->playSound("Click");
603     loadMainMenu();
604     switchMenu(mainMenu.get());
605 }
606 
607 void
newGameStartButtonClicked(Button *)608 MainMenu::newGameStartButtonClicked(Button* )
609 {
610     getSound()->playSound( "Click" );
611     if( loadCityNG( mFilename ) ){
612     	strcpy (given_scene, baseName.c_str());
613         quitState = INGAME;
614         running = false;
615     }
616     mFilename = "empty"; //don't erase scenarios later
617 }
618 
619 void
newGameStartBareButtonClicked(Button *)620 MainMenu::newGameStartBareButtonClicked(Button* )
621 {
622     getSound()->playSound( "Click" );
623     new_city( &main_screen_originx, &main_screen_originy, 0 );
624     GameView* gv = getGameView();
625     if( gv ){ gv->readOrigin(); }
626     quitState = INGAME;
627     running = false;
628 }
629 
630 void
newGameStartVillageClicked(Button *)631 MainMenu::newGameStartVillageClicked(Button* )
632 {
633     getSound()->playSound( "Click" );
634     new_city( &main_screen_originx, &main_screen_originy, 1 );
635     GameView* gv = getGameView();
636     if( gv ){ gv->readOrigin(); }
637     quitState = INGAME;
638     running = false;
639 }
640 
641 void
newGameBackButtonClicked(Button *)642 MainMenu::newGameBackButtonClicked(Button* )
643 {
644     getSound()->playSound( "Click" );
645     loadMainMenu();
646     switchMenu(mainMenu.get());
647 }
648 
649 void
loadGameBackButtonClicked(Button *)650 MainMenu::loadGameBackButtonClicked(Button* )
651 {
652     getSound()->playSound( "Click" );
653     loadMainMenu();
654     switchMenu(mainMenu.get());
655 }
656 
657 void
gotoMainMenu()658 MainMenu::gotoMainMenu()
659 {
660     getSound()->playSound( "Click" );
661     loadMainMenu();
662     switchMenu(mainMenu.get());
663 }
664 
665 void
loadGameLoadButtonClicked(Button *)666 MainMenu::loadGameLoadButtonClicked(Button *)
667 {
668     getSound()->playSound( "Click" );
669     if( loadCityNG( mFilename ) ){
670         quitState = INGAME;
671         running = false;
672     }
673 }
674 
675 void
loadGameSaveButtonClicked(Button *)676 MainMenu::loadGameSaveButtonClicked(Button *)
677 {
678     getSound()->playSound( "Click" );
679     if( file_exists( const_cast<char*>(mFilename.c_str()) ) ){
680         std::cout << "remove( " << mFilename << ")\n";
681         remove( mFilename.c_str() );
682     }
683     /* Build filename */
684     std::stringstream newStart;
685     newStart << slotNr << "_Y";
686     newStart << std::setfill('0') << std::setw(5);
687     fprintf(stderr,"total_time %i\n",total_time);
688     newStart << total_time/1200;
689     newStart << "_Tech";
690     newStart << std::setfill('0') << std::setw(3);
691     newStart << tech_level/10000;
692     newStart << "_Cash";
693     if (total_money >= 0)
694     	newStart << "+";
695     else
696     	newStart << "-";
697     newStart << std::setfill('0') << std::setw(3);
698     int money = abs(total_money);
699     if (money > 1000000000)
700         newStart << money/1000000000 << "G";
701     else if (money > 1000000)
702         newStart << money/1000000 << "M";
703     else  if(money > 1000)
704         newStart << money/1000 << "K";
705     else
706         newStart << money/1 << "_";
707 
708     newStart << "_P";
709     newStart << std::setfill('0') << std::setw(5);
710     newStart << housed_population + people_pool;
711     std::string newFilename( newStart.str() );
712     saveCityNG( newFilename );
713     fillLoadMenu( true );
714 }
715 
716 
717 MainState
run()718 MainMenu::run()
719 {
720     SDL_Event event;
721     running = true;
722     quitState = QUIT;
723     Uint32 ticks = SDL_GetTicks();
724 
725     int frame = 0;
726     while(running) {
727         while(SDL_PollEvent(&event)) {
728             switch(event.type) {
729                 case SDL_VIDEORESIZE:
730                     initVideo(event.resize.w, event.resize.h);
731                     currentMenu->resize(event.resize.w, event.resize.h);
732                     break;
733                 case SDL_MOUSEMOTION:
734                 case SDL_MOUSEBUTTONUP:
735                 case SDL_MOUSEBUTTONDOWN:
736                 case SDL_KEYDOWN:{
737                     Event gui_event(event);
738                     currentMenu->event(gui_event);
739                     break;
740                 }
741                 case SDL_KEYUP: {
742                     Event gui_event(event);
743                     //In menu ESC as well as ^c exits the game.
744                     //might come in handy if video-mode is not working as expected.
745                     if( ( gui_event.keysym.sym == SDLK_ESCAPE ) ||
746                         ( gui_event.keysym.sym == SDLK_c && ( gui_event.keysym.mod & KMOD_CTRL) ) ){
747                         running = false;
748                         quitState = QUIT;
749                         break;
750                     }
751                     currentMenu->event(gui_event);
752                     break;
753                 }
754                 case SDL_VIDEOEXPOSE:
755                     currentMenu->resize( currentMenu->getWidth(), currentMenu->getHeight() );
756                     break;
757                 case SDL_ACTIVEEVENT:
758                     if( event.active.gain == 1 ){
759                         currentMenu->resize( currentMenu->getWidth(), currentMenu->getHeight() );
760                     }
761                     break;
762                 case SDL_QUIT:
763                     running = false;
764                     quitState = QUIT;
765                     break;
766                 default:
767                     break;
768             }
769         }
770 
771         SDL_Delay(10); // give the CPU time to relax... (we are in main menu)
772 
773         if(currentMenu->needsRedraw()) {
774             currentMenu->draw(*painter);
775             flipScreenBuffer();
776         }
777 
778         frame++;
779         if(SDL_GetTicks() - ticks > 1000) {
780 #ifdef DEBUG_FPS
781             printf("FPS: %d.\n", frame);
782 #endif
783             frame = 0;
784             ticks = SDL_GetTicks();
785         }
786     }
787 
788     return quitState;
789 }
790