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