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