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