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