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