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