217ca69ab8137391d712d7b2d26f7bca94181fbd
[supertux.git] / src / gameloop.cpp
1 //  $Id$
2 // 
3 //  SuperTux
4 //  Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
5 //  Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
6 //  Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
7 //
8 //  This program is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU General Public License
10 //  as published by the Free Software Foundation; either version 2
11 //  of the License, or (at your option) any later version.
12 //
13 //  This program is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 //  GNU General Public License for more details.
17 // 
18 //  You should have received a copy of the GNU General Public License
19 //  along with this program; if not, write to the Free Software
20 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21
22 #include <iostream>
23 #include <sstream>
24 #include <cassert>
25 #include <cstdio>
26 #include <cstdlib>
27 #include <cmath>
28 #include <cstring>
29 #include <cerrno>
30 #include <unistd.h>
31 #include <ctime>
32
33 #include "SDL.h"
34
35 #ifndef WIN32
36 #include <sys/types.h>
37 #include <ctype.h>
38 #endif
39
40 #include "defines.h"
41 #include "app/globals.h"
42 #include "gameloop.h"
43 #include "video/screen.h"
44 #include "app/setup.h"
45 #include "high_scores.h"
46 #include "gui/menu.h"
47 #include "badguy.h"
48 #include "sector.h"
49 #include "special.h"
50 #include "player.h"
51 #include "level.h"
52 #include "scene.h"
53 #include "collision.h"
54 #include "tile.h"
55 #include "particlesystem.h"
56 #include "resources.h"
57 #include "background.h"
58 #include "tilemap.h"
59 #include "app/gettext.h"
60 #include "worldmap.h"
61 #include "intro.h"
62 #include "misc.h"
63
64 GameSession* GameSession::current_ = 0;
65
66 GameSession::GameSession(const std::string& levelname_, int mode, bool flip_level_)
67   : level(0), currentsector(0), st_gl_mode(mode),
68     end_sequence(NO_ENDSEQUENCE), levelname(levelname_), flip_level(flip_level_)
69 {
70   current_ = this;
71   
72   global_frame_counter = 0;
73   game_pause = false;
74   fps_fps = 0;
75
76   fps_timer.init(true);            
77   frame_timer.init(true);
78   frame_rate.set_fps(100);
79
80   context = new DrawingContext();
81
82   if(flip_levels_mode)
83     flip_level = true;
84
85   restart_level();
86 }
87
88 void
89 GameSession::restart_level()
90 {
91   game_pause   = false;
92   exit_status  = ES_NONE;
93   end_sequence = NO_ENDSEQUENCE;
94
95   fps_timer.init(true);
96   frame_timer.init(true);
97
98   last_keys.clear();
99
100 #if 0
101   float old_x_pos = -1;
102   if (world)
103     { // Tux has lost a life, so we try to respawn him at the nearest reset point
104       old_x_pos = world->get_tux()->base.x;
105     }
106 #endif
107   
108   delete level;
109   currentsector = 0;
110
111   level = new Level;
112   level->load(levelname);
113   if(flip_level)
114     level->do_vertical_flip();
115   currentsector = level->get_sector("main");
116   if(!currentsector)
117     Termination::abort("Level has no main sector.", "");
118   currentsector->activate("main");
119
120 #if 0 // TODO
121   // Set Tux to the nearest reset point
122   if (old_x_pos != -1)
123     {
124       ResetPoint best_reset_point = { -1, -1 };
125       for(std::vector<ResetPoint>::iterator i = get_level()->reset_points.begin();
126           i != get_level()->reset_points.end(); ++i)
127         {
128           if (i->x < old_x_pos && best_reset_point.x < i->x)
129             best_reset_point = *i;
130         }
131       
132       if (best_reset_point.x != -1)
133         {
134           world->get_tux()->base.x = best_reset_point.x;
135           world->get_tux()->base.y = best_reset_point.y;
136         }
137     }
138 #endif
139     
140   if (st_gl_mode != ST_GL_DEMO_GAME)
141     {
142       if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
143         levelintro();
144     }
145
146   time_left.init(true);
147   start_timers();
148   currentsector->play_music(LEVEL_MUSIC);
149 }
150
151 GameSession::~GameSession()
152 {
153   delete level;
154   delete context;
155 }
156
157 void
158 GameSession::levelintro(void)
159 {
160   SoundManager::get()->halt_music();
161   
162   char str[60];
163
164   DrawingContext context;
165   currentsector->background->draw(context);
166
167   context.draw_text_center(gold_text, level->get_name(), Vector(0, 220),
168       LAYER_FOREGROUND1);
169
170   sprintf(str, "TUX x %d", player_status.lives);
171   context.draw_text_center(white_text, str, Vector(0, 240),
172       LAYER_FOREGROUND1);
173
174   if(level->get_author().size())
175     context.draw_text_center(white_small_text,
176       std::string(_("by ")) + level->get_author(), 
177       Vector(0, 400), LAYER_FOREGROUND1);
178
179
180   if(flip_level)
181     context.draw_text_center(white_text,
182       _("Level Vertically Flipped!"),
183       Vector(0, 310), LAYER_FOREGROUND1);
184
185   context.do_drawing();
186
187   SDL_Event event;
188   wait_for_event(event,1000,3000,true);
189 }
190
191 /* Reset Timers */
192 void
193 GameSession::start_timers()
194 {
195   time_left.start(level->time_left*1000);
196   Ticks::pause_init();
197   frame_rate.start();
198 }
199
200 void
201 GameSession::on_escape_press()
202 {
203   if(currentsector->player->dying || end_sequence != NO_ENDSEQUENCE)
204     return;   // don't let the player open the menu, when he is dying
205   
206   if(game_pause)
207     return;
208
209   if(st_gl_mode == ST_GL_TEST)
210     {
211       exit_status = ES_LEVEL_ABORT;
212     }
213   else if (!Menu::current())
214     {
215       /* Tell Tux that the keys are all down, otherwise
216         it could have nasty bugs, like going allways to the right
217         or whatever that key does */
218       Player& tux = *(currentsector->player);
219       tux.key_event((SDLKey)keymap.jump, UP);
220       tux.key_event((SDLKey)keymap.duck, UP);
221       tux.key_event((SDLKey)keymap.left, UP);
222       tux.key_event((SDLKey)keymap.right, UP);
223       tux.key_event((SDLKey)keymap.fire, UP);
224
225       Menu::set_current(game_menu);
226       Ticks::pause_start();
227     }
228 }
229
230 void
231 GameSession::process_events()
232 {
233   if (end_sequence != NO_ENDSEQUENCE)
234     {
235       Player& tux = *currentsector->player;
236          
237       tux.input.fire  = UP;
238       tux.input.left  = UP;
239       tux.input.right = DOWN;
240       tux.input.down  = UP; 
241
242       if (int(last_x_pos) == int(tux.base.x))
243         tux.input.up    = DOWN; 
244       else
245         tux.input.up    = UP; 
246
247       last_x_pos = tux.base.x;
248
249       SDL_Event event;
250       while (SDL_PollEvent(&event))
251         {
252           /* Check for menu-events, if the menu is shown */
253           if (Menu::current())
254             {
255               Menu::current()->event(event);
256               if(!Menu::current())
257               Ticks::pause_stop();
258             }
259
260           switch(event.type)
261             {
262             case SDL_QUIT:        /* Quit event - quit: */
263               Termination::abort("Received window close", "");
264               break;
265               
266             case SDL_KEYDOWN:     /* A keypress! */
267               {
268                 SDLKey key = event.key.keysym.sym;
269            
270                 switch(key)
271                   {
272                   case SDLK_ESCAPE:    /* Escape: Open/Close the menu: */
273                     on_escape_press();
274                     break;
275                   default:
276                     break;
277                   }
278               }
279           
280             case SDL_JOYBUTTONDOWN:
281               if (event.jbutton.button == joystick_keymap.start_button)
282                 on_escape_press();
283               break;
284             }
285         }
286     }
287   else // normal mode
288     {
289       if(!Menu::current() && !game_pause)
290         Ticks::pause_stop();
291
292       SDL_Event event;
293       while (SDL_PollEvent(&event))
294         {
295           /* Check for menu-events, if the menu is shown */
296           if (Menu::current())
297             {
298               Menu::current()->event(event);
299               if(!Menu::current())
300                 Ticks::pause_stop();
301             }
302           else
303             {
304               Player& tux = *currentsector->player;
305   
306               switch(event.type)
307                 {
308                 case SDL_QUIT:        /* Quit event - quit: */
309                   Termination::abort("Received window close", "");
310                   break;
311
312                 case SDL_KEYDOWN:     /* A keypress! */
313                   {
314                     SDLKey key = event.key.keysym.sym;
315             
316                     if(tux.key_event(key,DOWN))
317                       break;
318
319                     switch(key)
320                       {
321                       case SDLK_ESCAPE:    /* Escape: Open/Close the menu: */
322                         on_escape_press();
323                         break;
324                       default:
325                         break;
326                       }
327                   }
328                   break;
329                 case SDL_KEYUP:      /* A keyrelease! */
330                   {
331                     SDLKey key = event.key.keysym.sym;
332
333                     if(tux.key_event(key, UP))
334                       break;
335
336                     switch(key)
337                       {
338                       case SDLK_a:
339                         if(debug_mode)
340                         {
341                           char buf[160];
342                           snprintf(buf, sizeof(buf), "P: %4.1f,%4.1f",
343                               tux.base.x, tux.base.y);
344                           context->draw_text(white_text, buf,
345                               Vector(0, screen->h - white_text->get_height()),
346                               LAYER_FOREGROUND1);
347                           context->do_drawing();
348                           SDL_Delay(1000);
349                         }
350                         break;
351                       case SDLK_p:
352                         if(!Menu::current())
353                           {
354                             if(game_pause)
355                               {
356                                 game_pause = false;
357                                 Ticks::pause_stop();
358                               }
359                             else
360                               {
361                                 game_pause = true;
362                                 Ticks::pause_start();
363                               }
364                           }
365                         break;
366                       default:
367                         /* Check if chacrater is ASCII */
368                         char ch[2];
369                         if((event.key.keysym.unicode & 0xFF80) == 0)
370                           {
371                           ch[0] = event.key.keysym.unicode & 0x7F;
372                           ch[1] = '\0';
373                           }
374                         last_keys.append(ch);  // add to cheat keys
375                         break;
376                       }
377                   }
378                   break;
379
380                 case SDL_JOYAXISMOTION:
381                   if (event.jaxis.axis == joystick_keymap.x_axis)
382                     {
383                       if (event.jaxis.value < -joystick_keymap.dead_zone)
384                         {
385                           tux.input.left  = DOWN;
386                           tux.input.right = UP;
387                         }
388                       else if (event.jaxis.value > joystick_keymap.dead_zone)
389                         {
390                           tux.input.left  = UP;
391                           tux.input.right = DOWN;
392                         }
393                       else
394                         {
395                           tux.input.left  = DOWN;
396                           tux.input.right = DOWN;
397                         }
398                     }
399                   else if (event.jaxis.axis == joystick_keymap.y_axis)
400                     {
401                       if (event.jaxis.value > joystick_keymap.dead_zone)
402                         tux.input.down = DOWN;
403                       else if (event.jaxis.value < -joystick_keymap.dead_zone)
404                         tux.input.down = UP;
405                       else
406                         tux.input.down = UP;
407                     }
408                   break;
409
410                 case SDL_JOYHATMOTION:
411                   if(event.jhat.value & SDL_HAT_UP) {
412                     tux.input.up = DOWN;
413                     tux.input.down = UP;
414                   } else if(event.jhat.value & SDL_HAT_DOWN) {
415                     tux.input.up = UP;
416                     tux.input.down = DOWN;
417                   } else if(event.jhat.value & SDL_HAT_LEFT) {
418                     tux.input.left = DOWN;
419                     tux.input.right = UP;
420                   } else if(event.jhat.value & SDL_HAT_RIGHT) {
421                     tux.input.left = UP;
422                     tux.input.right = DOWN;
423                   } else if(event.jhat.value == SDL_HAT_CENTERED) {
424                     tux.input.left = UP;
425                     tux.input.right = UP;
426                     tux.input.up = UP;
427                     tux.input.down = UP;
428                   }
429                   break;
430             
431                 case SDL_JOYBUTTONDOWN:
432                   if (event.jbutton.button == joystick_keymap.a_button)
433                     tux.input.up = DOWN;
434                   else if (event.jbutton.button == joystick_keymap.b_button)
435                     tux.input.fire = DOWN;
436                   else if (event.jbutton.button == joystick_keymap.start_button)
437                     on_escape_press();
438                   break;
439                 case SDL_JOYBUTTONUP:
440                   if (event.jbutton.button == joystick_keymap.a_button)
441                     tux.input.up = UP;
442                   else if (event.jbutton.button == joystick_keymap.b_button)
443                     tux.input.fire = UP;
444                   break;
445
446                 default:
447                   break;
448                 }  /* switch */
449             }
450         } /* while */
451     }
452
453 // Cheating words (the goal of this is really for debugging, but could
454 // be used for some cheating)
455 // TODO: this could be implmented in a more elegant and faster way
456 if(!last_keys.empty())
457   {
458   Player &tux = *currentsector->player;
459   if(last_keys.find("grow") != std::string::npos)
460     {
461     tux.grow(false);
462     last_keys.clear();
463     }
464   if(last_keys.find("fire") != std::string::npos)
465     {
466     tux.grow(false);
467     tux.got_power = tux.FIRE_POWER;
468     last_keys.clear();
469     }
470   if(last_keys.find("ice") != std::string::npos)
471     {
472     tux.grow(false);
473     tux.got_power = tux.ICE_POWER;
474     last_keys.clear();
475     }
476   if(last_keys.find("lifeup") != std::string::npos)
477     {
478     player_status.lives++;
479     last_keys.clear();
480     }
481   if(last_keys.find("lifedown") != std::string::npos)
482     {
483     player_status.lives--;
484     last_keys.clear();
485     }
486   if(last_keys.find("invincible") != std::string::npos)
487     {    // be invincle for the rest of the level
488     tux.invincible_timer.start(time_left.get_left());
489     last_keys.clear();
490     }
491   if(last_keys.size() > 15)
492     last_keys.clear();
493   }
494 }
495
496 void
497 GameSession::check_end_conditions()
498 {
499   Player* tux = currentsector->player;
500
501   /* End of level? */
502   Tile* endtile = collision_goal(tux->base);
503
504   if(end_sequence && !endsequence_timer.check())
505     {
506       exit_status = ES_LEVEL_FINISHED;
507       return;
508     }
509   else if(end_sequence == ENDSEQUENCE_RUNNING && endtile && endtile->data >= 1)
510     {
511       end_sequence = ENDSEQUENCE_WAITING;
512     }
513   else if(!end_sequence && endtile && endtile->data == 0)
514     {
515       end_sequence = ENDSEQUENCE_RUNNING;
516       last_x_pos = -1;
517       SoundManager::get()->play_music(level_end_song, 0);
518       endsequence_timer.start(7000); // 5 seconds until we finish the map
519       tux->invincible_timer.start(7000); //FIXME: Implement a winning timer for the end sequence (with special winning animation etc.)
520     }
521   else if (!end_sequence && tux->is_dead())
522     {
523       player_status.bonus = PlayerStatus::NO_BONUS;
524
525       if (player_status.lives < 0)
526         { // No more lives!?
527           exit_status = ES_GAME_OVER;
528         }
529       else
530         { // Still has lives, so reset Tux to the levelstart
531           restart_level();
532         }
533
534       return;
535     }
536 }
537
538 void
539 GameSession::action(double frame_ratio)
540 {
541   if (exit_status == ES_NONE && !currentsector->player->growing_timer.check())
542     {
543       // Update Tux and the World
544       currentsector->action(frame_ratio);
545     }
546
547   // respawning in new sector?
548   if(newsector != "" && newspawnpoint != "") {
549     Sector* sector = level->get_sector(newsector);
550     currentsector = sector;
551     currentsector->activate(newspawnpoint);
552     currentsector->play_music(LEVEL_MUSIC);
553     newsector = newspawnpoint = "";
554   }
555 }
556
557 void 
558 GameSession::draw()
559 {
560   currentsector->draw(*context);
561   drawstatus(*context);
562
563   if(game_pause)
564     {
565       int x = screen->h / 20;
566       for(int i = 0; i < x; ++i)
567         {
568           context->draw_filled_rect(
569               Vector(i % 2 ? (pause_menu_frame * i)%screen->w :
570                 -((pause_menu_frame * i)%screen->w)
571                 ,(i*20+pause_menu_frame)%screen->h),
572               Vector(screen->w,10),
573               Color(20,20,20, rand() % 20 + 1), LAYER_FOREGROUND1+1);
574         }
575       context->draw_filled_rect(
576           Vector(0,0), Vector(screen->w, screen->h),
577           Color(rand() % 50, rand() % 50, rand() % 50, 128), LAYER_FOREGROUND1);
578       context->draw_text_center(blue_text, _("PAUSE - Press 'P' To Play"),
579           Vector(0, 230), LAYER_FOREGROUND1+2);
580
581       char str1[60];
582       char str2[124];
583       sprintf(str1, _("Playing: "));
584       sprintf(str2, level->name.c_str());
585
586       context->draw_text(blue_text, str1,
587           Vector((screen->w - (blue_text->get_text_width(str1) + white_text->get_text_width(str2)))/2, 340),
588           LAYER_FOREGROUND1+2);
589       context->draw_text(white_text, str2,
590           Vector(((screen->w - (blue_text->get_text_width(str1) + white_text->get_text_width(str2)))/2)+blue_text->get_text_width(str1), 340),
591           LAYER_FOREGROUND1+2);
592     }
593
594   if(Menu::current())
595     {
596       Menu::current()->draw(*context);
597       mouse_cursor->draw(*context);
598     }
599
600   context->do_drawing();
601 }
602
603 void
604 GameSession::process_menu()
605 {
606   Menu* menu = Menu::current();
607   if(menu)
608     {
609       menu->action();
610
611       if(menu == game_menu)
612         {
613           switch (game_menu->check())
614             {
615             case MNID_CONTINUE:
616               Ticks::pause_stop();
617               break;
618             case MNID_ABORTLEVEL:
619               Ticks::pause_stop();
620               exit_status = ES_LEVEL_ABORT;
621               break;
622             }
623         }
624       else if(menu == options_menu)
625         {
626           process_options_menu();
627         }
628       else if(menu == load_game_menu )
629         {
630           process_load_game_menu();
631         }
632     }
633 }
634
635 GameSession::ExitStatus
636 GameSession::run()
637 {
638   Menu::set_current(0);
639   current_ = this;
640   
641   int fps_cnt = 0;
642
643   frame_rate.start();
644
645   // Eat unneeded events
646   SDL_Event event;
647   while (SDL_PollEvent(&event)) {}
648
649   draw();
650
651   while (exit_status == ES_NONE)
652     {
653       /* Calculate the movement-factor */
654       double frame_ratio = frame_rate.get();
655
656       if(!frame_timer.check())
657         {
658           frame_timer.start(25);
659           ++global_frame_counter;
660         }
661
662       /* Handle events: */
663       currentsector->player->input.old_fire 
664         = currentsector->player->input.fire;
665
666       process_events();
667       process_menu();
668
669       // Update the world state and all objects in the world
670       // Do that with a constante time-delta so that the game will run
671       // determistic and not different on different machines
672       if(!game_pause && !Menu::current())
673         {
674           // Update the world
675           check_end_conditions();
676           if (end_sequence == ENDSEQUENCE_RUNNING)
677              action(frame_ratio/2);
678           else if(end_sequence == NO_ENDSEQUENCE)
679              action(frame_ratio);
680         }
681       else
682         {
683           ++pause_menu_frame;
684           SDL_Delay(50);
685         }
686
687       draw();
688
689       /* Time stops in pause mode */
690       if(game_pause || Menu::current())
691         {
692           continue;
693         }
694
695       frame_rate.update();
696
697       /* Handle time: */
698       if (!time_left.check() && currentsector->player->dying == DYING_NOT
699               && !end_sequence)
700         currentsector->player->kill(Player::KILL);
701
702       /* Handle music: */
703       if(currentsector->player->invincible_timer.check() && !end_sequence)
704         {
705           currentsector->play_music(HERRING_MUSIC);
706         }
707       /* are we low on time ? */
708       else if (time_left.get_left() < TIME_WARNING && !end_sequence)
709         {
710           currentsector->play_music(HURRYUP_MUSIC);
711         }
712       /* or just normal music? */
713       else if(currentsector->get_music_type() != LEVEL_MUSIC && !end_sequence)
714         {
715           currentsector->play_music(LEVEL_MUSIC);
716         }
717
718       /* Calculate frames per second */
719       if(show_fps)
720         {
721           ++fps_cnt;
722           fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
723
724           if(!fps_timer.check())
725             {
726               fps_timer.start(1000);
727               fps_cnt = 0;
728             }
729         }
730     }
731   
732   return exit_status;
733 }
734
735 void
736 GameSession::respawn(const std::string& sector, const std::string& spawnpoint)
737 {
738   newsector = sector;
739   newspawnpoint = spawnpoint;
740 }
741
742 /* Bounce a brick: */
743 void bumpbrick(float x, float y)
744 {
745   Sector::current()->add_bouncy_brick(Vector(((int)(x + 1) / 32) * 32,
746                          (int)(y / 32) * 32));
747
748   SoundManager::get()->play_sound(IDToSound(SND_BRICK), Vector(x, y), Sector::current()->player->get_pos());
749 }
750
751 /* (Status): */
752 void
753 GameSession::drawstatus(DrawingContext& context)
754 {
755   char str[60];
756   
757   snprintf(str, 60, " %d", player_status.score);
758   context.draw_text(white_text, _("SCORE"), Vector(0, 0), LAYER_FOREGROUND1);
759   context.draw_text(gold_text, str, Vector(96, 0), LAYER_FOREGROUND1);
760
761   if(st_gl_mode == ST_GL_TEST)
762     {
763       context.draw_text(white_text, _("Press ESC To Return"), Vector(0,20),
764           LAYER_FOREGROUND1);
765     }
766
767   if(!time_left.check()) {
768     context.draw_text_center(white_text, _("TIME's UP"), Vector(0, 0),
769         LAYER_FOREGROUND1);
770   } else if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5) {
771     sprintf(str, " %d", time_left.get_left() / 1000 );
772     context.draw_text_center(white_text, _("TIME"),
773         Vector(0, 0), LAYER_FOREGROUND1);
774     context.draw_text_center(gold_text, str,
775         Vector(4*16, 0), LAYER_FOREGROUND1);
776   }
777
778   sprintf(str, " %d", player_status.distros);
779   context.draw_text(white_text, _("COINS"),
780       Vector(screen->w - white_text->get_text_width(_("COINS"))-white_text->get_text_width("   99"), 0),
781         LAYER_FOREGROUND1);
782   context.draw_text(gold_text, str,
783       Vector(screen->w - gold_text->get_text_width(" 99"), 0),LAYER_FOREGROUND1);
784
785   if (player_status.lives >= 5)
786     {
787       sprintf(str, "%dx", player_status.lives);
788       float x = screen->w - gold_text->get_text_width(str) - tux_life->w;
789       context.draw_text(gold_text, str, Vector(x, 20), LAYER_FOREGROUND1);
790       context.draw_surface(tux_life, Vector(screen->w - 16, 20),
791           LAYER_FOREGROUND1);
792     }
793   else
794     {
795       for(int i= 0; i < player_status.lives; ++i)
796         context.draw_surface(tux_life, 
797             Vector(screen->w - tux_life->w*4 +(tux_life->w*i), 20),
798             LAYER_FOREGROUND1);
799     }
800
801   context.draw_text(white_text, _("LIVES"),
802       Vector(screen->w - white_text->get_text_width(_("LIVES")) - white_text->get_text_width("   99"), 20),
803       LAYER_FOREGROUND1);
804
805   if(show_fps)
806     {
807       sprintf(str, "%2.1f", fps_fps);
808       context.draw_text(white_text, "FPS", 
809           Vector(screen->w - white_text->get_text_width("FPS     "), 40),
810           LAYER_FOREGROUND1);
811       context.draw_text(gold_text, str,
812           Vector(screen->w-4*16, 40), LAYER_FOREGROUND1);
813     }
814 }
815
816 void
817 GameSession::drawresultscreen(void)
818 {
819   char str[80];
820
821   DrawingContext context;
822   currentsector->background->draw(context);  
823
824   context.draw_text_center(blue_text, _("Result:"), Vector(0, 200),
825       LAYER_FOREGROUND1);
826
827   sprintf(str, _("SCORE: %d"), player_status.score);
828   context.draw_text_center(gold_text, str, Vector(0, 224), LAYER_FOREGROUND1);
829
830   sprintf(str, _("COINS: %d"), player_status.distros);
831   context.draw_text_center(gold_text, str, Vector(0, 256), LAYER_FOREGROUND1);
832
833   context.do_drawing();
834   
835   SDL_Event event;
836   wait_for_event(event,2000,5000,true);
837 }
838
839 std::string slotinfo(int slot)
840 {
841   std::string tmp;
842   std::string slotfile;
843   std::string title;
844   std::stringstream stream;
845   stream << slot;
846   slotfile = st_save_dir + "/slot" + stream.str() + ".stsg";
847
848   lisp_object_t* savegame = lisp_read_from_file(slotfile.c_str());
849   if (savegame)
850     {
851       LispReader reader(lisp_cdr(savegame));
852       reader.read_string("title", title);
853       lisp_free(savegame);
854     }
855
856   if (access(slotfile.c_str(), F_OK) == 0)
857     {
858       if (!title.empty())
859         tmp = "Slot " + stream.str() + " - " + title;
860       else
861         tmp = "Slot " + stream.str() + " - Savegame";
862     }
863   else
864     tmp = std::string(_("Slot")) + " " + stream.str() + " - " + std::string(_("Free"));
865
866   return tmp;
867 }
868
869 bool process_load_game_menu()
870 {
871   int slot = load_game_menu->check();
872
873   if(slot != -1 && load_game_menu->get_item_by_id(slot).kind == MN_ACTION)
874     {
875       std::stringstream stream;
876       stream << slot;
877       std::string slotfile = st_save_dir + "/slot" + stream.str() + ".stsg";
878
879       if (access(slotfile.c_str(), F_OK) != 0)
880         {
881           draw_intro();
882         }
883
884       // shrink_fade(Point((screen->w/2),(screen->h/2)), 1000);
885       fadeout(256);
886
887       DrawingContext context;
888       context.draw_text_center(white_text, "Loading...",
889                                Vector(0, screen->h/2), LAYER_FOREGROUND1);
890       context.do_drawing();
891
892       WorldMapNS::WorldMap worldmap;
893
894       // Load the game or at least set the savegame_file variable
895       worldmap.loadgame(slotfile);
896
897       worldmap.display();
898
899       Menu::set_current(main_menu);
900
901       Ticks::pause_stop();
902       return true;
903     }
904   else
905     {
906       return false;
907     }
908 }