- removed local (un)loadshared() stuff and replaced it my a global one, fixes crash...
[supertux.git] / src / title.cpp
1 /*
2   title.c
3   
4   Super Tux - Title Screen
5   
6   by Bill Kendrick
7   bill@newbreedsoftware.com
8   http://www.newbreedsoftware.com/supertux/
9   
10   April 11, 2000 - March 15, 2004
11 */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <unistd.h>
18 #include <SDL.h>
19 #include <SDL_image.h>
20
21 #ifndef WIN32
22 #include <sys/types.h>
23 #include <ctype.h>
24 #endif
25
26 #include "defines.h"
27 #include "globals.h"
28 #include "title.h"
29 #include "screen.h"
30 #include "high_scores.h"
31 #include "menu.h"
32 #include "texture.h"
33 #include "timer.h"
34 #include "setup.h"
35 #include "level.h"
36 #include "gameloop.h"
37 #include "leveleditor.h"
38 #include "scene.h"
39 #include "player.h"
40 #include "math.h"
41 #include "tile.h"
42 #include "resources.h"
43
44 static texture_type bkg_title;
45 static texture_type logo;
46 static texture_type img_choose_subset;
47
48 static bool walking;
49 static Timer random_timer;
50
51 static SDL_Event event;
52 static SDLKey key;
53 static int frame, i;
54 static unsigned int last_update_time;
55 static unsigned int update_time;
56
57 void display_credits();
58
59 void draw_background()
60 {
61   /* Draw the title background: */
62
63   texture_draw_bg(&bkg_title);
64 }
65
66 void draw_demo(GameSession* session, double frame_ratio)
67 {
68   World::set_current(session->get_world());
69   //World* world  = session->get_world();
70   Level* plevel = session->get_level();
71   Player* tux = session->get_world()->get_tux();
72   
73   /* FIXME:
74   // update particle systems
75   std::vector<ParticleSystem*>::iterator p;
76   for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
77     {
78       (*p)->simulate(frame_ratio);
79     }
80
81   // Draw particle systems (background)
82   for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
83     {
84       (*p)->draw(scroll_x, 0, 0);
85     }
86   */
87
88   // Draw interactive tiles:
89   for (int y = 0; y < 15; ++y)
90     {
91       for (int x = 0; x < 21; ++x)
92         {
93           Tile::draw(32*x - fmodf(scroll_x, 32), y * 32,
94                      plevel->ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
95         }
96     }
97
98   global_frame_counter++;
99   tux->key_event(SDLK_RIGHT,DOWN);
100   
101   if(random_timer.check())
102     {
103       if(walking)
104         tux->key_event(SDLK_UP,UP);
105       else
106         tux->key_event(SDLK_UP,DOWN);
107     }
108   else
109     {
110       random_timer.start(rand() % 3000 + 3000);
111       walking = !walking;
112     }
113   
114   // Wrap around at the end of the level back to the beginnig
115   if(plevel->width * 32 - 320 < tux->base.x)
116     {
117       tux->base.x = tux->base.x - (plevel->width * 32 - 640);
118       scroll_x = tux->base.x - 320;
119     }
120
121
122
123   float last_tux_x_pos = tux->base.x;
124   tux->action(frame_ratio);
125
126   // Jump if tux stays in the same position for one loop, ie. if he is
127   // stuck behind a wall
128   if (last_tux_x_pos == tux->base.x)
129     walking = false;
130
131   tux->draw();
132
133   /* DEMO end */
134 }
135
136 /* --- TITLE SCREEN --- */
137 bool title(void)
138 {
139   string_list_type level_subsets;
140   st_subset subset;
141   level_subsets = dsubdirs("/levels", "info");
142   random_timer.init(true);
143
144   walking = true;
145
146   st_pause_ticks_init();
147
148   GameSession session(datadir + "/levels/misc/menu.stl");
149
150   //FIXME:activate_particle_systems();
151
152   /* Reset menu variables */
153   menu_reset();
154   Menu::set_current(main_menu);
155
156   clearscreen(0, 0, 0);
157   updatescreen();
158
159   /* Load images: */
160
161   texture_load(&bkg_title,datadir + "/images/title/background.jpg", IGNORE_ALPHA);
162   texture_load(&logo,datadir + "/images/title/logo.png", USE_ALPHA);
163   texture_load(&img_choose_subset,datadir + "/images/status/choose-level-subset.png", USE_ALPHA);
164
165   /* --- Main title loop: --- */
166   bool done = 0;
167   show_menu = 1;
168   frame = 0;
169
170   /* Draw the title background: */
171   texture_draw_bg(&bkg_title);
172   load_hs();
173
174   update_time = st_get_ticks();
175   random_timer.start(rand() % 2000 + 2000);
176
177   while (!done)
178     {
179       /* Calculate the movement-factor */
180       double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
181       if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
182         frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
183       /* Lower the frame_ratio that Tux doesn't jump to hectically throught the demo. */
184       frame_ratio /= 2;
185
186       /* Handle events: */
187
188       while (SDL_PollEvent(&event))
189         {
190           menu_event(event);
191           if (event.type == SDL_QUIT)
192             {
193               done = true;
194             }
195           else if (event.type == SDL_KEYDOWN)
196             {
197               /* Keypress... */
198               key = event.key.keysym.sym;
199
200               /* Check for menu events */
201               //menu_event(event);
202
203               if (key == SDLK_ESCAPE)
204                 {
205                   /* Escape: Quit: */
206                   done = true;
207                 }
208             }
209         }
210
211       /* Draw the background: */
212       draw_background();
213       draw_demo(&session, frame_ratio);
214       
215       if (current_menu == main_menu)
216         texture_draw(&logo, 160, 30);
217
218       text_draw(&white_small_text, 
219                 " SuperTux " VERSION "\n"
220                 "Copyright (c) 2003 SuperTux Devel Team\n"
221                 "This game comes with ABSOLUTELY NO WARRANTY. This is free software, and you\n"
222                 "are welcome to redistribute it under certain conditions; see the file COPYING\n"
223                 "for details.\n",
224                 0, 420, 0);
225
226       /* Draw the high score: */
227       /*
228         sprintf(str, "High score: %d", hs_score);
229         text_drawf(&gold_text, str, 0, -40, A_HMIDDLE, A_BOTTOM, 1);
230         sprintf(str, "by %s", hs_name);
231         text_drawf(&gold_text, str, 0, -20, A_HMIDDLE, A_BOTTOM, 1);
232       */
233
234       /* Don't draw menu, if quit is true */
235       if(show_menu && !done)
236         menu_process_current();
237
238       if(current_menu == main_menu)
239         {
240           switch (main_menu->check())
241             {
242 #if 0
243             case 0:
244               // Quick Play
245               // FIXME: obsolete
246               done = 0;
247               i = 0;
248               if(level_subsets.num_items != 0)
249                 {
250                   subset.load(level_subsets.item[0]);
251                   while(!done)
252                     {
253                       texture_draw(&img_choose_subset,(screen->w - img_choose_subset.w) / 2, 0);
254                       if(level_subsets.num_items != 0)
255                         {
256                           texture_draw(&subset.image,(screen->w - subset.image.w) / 2 + 25,78);
257                           if(level_subsets.num_items > 1)
258                             {
259                               if(i > 0)
260                                 texture_draw(&arrow_left,(screen->w / 2) - ((subset.title.length()+2)*16)/2,20);
261                               if(i < level_subsets.num_items-1)
262                                 texture_draw(&arrow_right,(screen->w / 2) + ((subset.description.length())*16)/2,20);
263                             }
264                           text_drawf(&gold_text, subset.title.c_str(), 0, 20, A_HMIDDLE, A_TOP, 1);
265                           text_drawf(&gold_text, subset.description.c_str(), 20, -20, A_HMIDDLE, A_BOTTOM, 1);
266                         }
267                       updatescreen();
268                       SDL_Delay(50);
269                       while(SDL_PollEvent(&event) && !done)
270                         {
271                           switch(event.type)
272                             {
273                             case SDL_QUIT:
274                               done = true;
275                               break;
276                             case SDL_KEYDOWN:           // key pressed
277                               // Keypress...
278                               key = event.key.keysym.sym;
279
280                               if(key == SDLK_LEFT)
281                                 {
282                                   if(i > 0)
283                                     {
284                                       --i;
285                                       subset.free();
286                                       subset.load(level_subsets.item[i]);
287                                     }
288                                 }
289                               else if(key == SDLK_RIGHT)
290                                 {
291                                   if(i < level_subsets.num_items -1)
292                                     {
293                                       ++i;
294                                       subset.free();
295                                       subset.load(level_subsets.item[i]);
296                                     }
297                                 }
298                               else if(key == SDLK_SPACE || key == SDLK_RETURN)
299                                 {
300                                   done = true;
301                                   quit = gameloop(subset.name.c_str(),1,ST_GL_PLAY);
302                                   subset.free();
303                                 }
304                               else if(key == SDLK_ESCAPE)
305                                 {
306                                   done = true;
307                                 }
308                               break;
309                             default:
310                               break;
311                             }
312                         }
313                     }
314                 }
315               // reset tux
316               scroll_x = 0;
317               titletux.level_begin();
318               update_time = st_get_ticks();
319               break;
320 #endif
321             case 0:
322               // Start Game, ie. goto the slots menu
323               update_load_save_game_menu(load_game_menu, true);
324               break;
325             case 1:
326               // Contrib Menu
327               break;
328             case 3:
329               done = 1;
330               done = leveleditor(1);
331               break;
332             case 4:
333               display_credits();
334               break;
335             case 5:
336               done = true;
337               break;
338             }
339         }
340       else if(current_menu == options_menu)
341         {
342           process_options_menu();
343         }
344       else if(current_menu == load_game_menu)
345         {
346           if (process_load_game_menu())
347             {
348               // FIXME: shouldn't be needed if GameSession doesn't relay on global variables
349               // reset tux
350               scroll_x = 0;
351               //titletux.level_begin();
352               update_time = st_get_ticks();
353             }
354         }
355       else if(current_menu == contrib_menu)
356         {
357           
358         }
359
360       mouse_cursor->draw();
361       
362       flipscreen();
363
364       /* Set the time of the last update and the time of the current update */
365       last_update_time = update_time;
366       update_time = st_get_ticks();
367
368       /* Pause: */
369       frame++;
370       SDL_Delay(25);
371
372     }
373   /* Free surfaces: */
374
375   texture_free(&bkg_title);
376   texture_free(&logo);
377   string_list_free(&level_subsets);
378
379   /* Return to main! */
380   return done;
381 }
382
383 #define MAX_VEL 10
384 #define SPEED   1
385 #define SCROLL  60
386
387 void display_credits()
388 {
389   int done;
390   int scroll, speed;
391   Timer timer;
392   int n,d;
393   int length;
394   FILE* fi;
395   char temp[1024];
396   string_list_type names;
397   char filename[1024];
398   string_list_init(&names);
399   sprintf(filename,"%s/CREDITS", datadir.c_str());
400   if((fi = fopen(filename,"r")) != NULL)
401     {
402       while(fgets(temp, sizeof(temp), fi) != NULL)
403         {
404           temp[strlen(temp)-1]='\0';
405           string_list_add_item(&names,temp);
406         }
407       fclose(fi);
408     }
409   else
410     {
411       string_list_add_item(&names,"Credits were not found!");
412       string_list_add_item(&names,"Shame on the guy, who");
413       string_list_add_item(&names,"forgot to include them");
414       string_list_add_item(&names,"in your SuperTux distribution.");
415     }
416
417
418   timer.init(SDL_GetTicks());
419   timer.start(50);
420
421   scroll = 0;
422   speed = 2;
423   done = 0;
424
425   n = d = 0;
426
427   length = names.num_items;
428
429   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
430
431   while(done == 0)
432     {
433       /* in case of input, exit */
434       while(SDL_PollEvent(&event))
435         switch(event.type)
436           {
437           case SDL_KEYDOWN:
438             switch(event.key.keysym.sym)
439               {
440               case SDLK_UP:
441                 speed -= SPEED;
442                 break;
443               case SDLK_DOWN:
444                 speed += SPEED;
445                 break;
446               case SDLK_SPACE:
447               case SDLK_RETURN:
448                 if(speed >= 0)
449                   scroll += SCROLL;
450                 break;
451               case SDLK_ESCAPE:
452                 done = 1;
453                 break;
454               default:
455                 break;
456               }
457             break;
458           case SDL_QUIT:
459             done = 1;
460             break;
461           default:
462             break;
463           }
464
465       if(speed > MAX_VEL)
466         speed = MAX_VEL;
467       else if(speed < -MAX_VEL)
468         speed = -MAX_VEL;
469
470       /* draw the credits */
471
472       draw_background();
473
474       text_drawf(&white_big_text, "- Credits -", 0, screen->h-scroll, A_HMIDDLE, A_TOP, 2);
475
476       for(i = 0, n = 0, d = 0; i < length; i++,n++,d++)
477         {
478           if(names.item[i] == "")
479             n--;
480           else
481             {
482               if(names.item[i][0] == ' ')
483                 text_drawf(&white_small_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll-10, A_HMIDDLE, A_TOP, 1);
484               else if(names.item[i][0] == '     ')
485                 text_drawf(&white_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll, A_HMIDDLE, A_TOP, 1);
486               else if(names.item[i+1][0] == '-' || names.item[i][0] == '-')
487                 text_drawf(&white_big_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll, A_HMIDDLE, A_TOP, 3);
488               else
489                 text_drawf(&blue_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll, A_HMIDDLE, A_TOP, 1);
490             }
491         }
492
493       flipscreen();
494
495       if(60+screen->h+(n*18)+(d*18)-scroll < 0 && 20+60+screen->h+(n*18)+(d*18)-scroll < 0)
496         done = 1;
497
498       scroll += speed;
499       if(scroll < 0)
500         scroll = 0;
501
502       SDL_Delay(35);
503
504       if(timer.get_left() < 0)
505         {
506           frame++;
507           timer.start(50);
508         }
509     }
510   string_list_free(&names);
511
512   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
513   show_menu = 1;
514   Menu::set_current(main_menu);
515 }