729851b8187651c2f1e7f32053876a8c9c5ccfdc
[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 #if 0
249             case 0:
250               // Quick Play
251               // FIXME: obsolete
252               done = 0;
253               i = 0;
254               if(level_subsets.num_items != 0)
255                 {
256                   subset.load(level_subsets.item[0]);
257                   while(!done)
258                     {
259                       texture_draw(&img_choose_subset,(screen->w - img_choose_subset.w) / 2, 0);
260                       if(level_subsets.num_items != 0)
261                         {
262                           texture_draw(&subset.image,(screen->w - subset.image.w) / 2 + 25,78);
263                           if(level_subsets.num_items > 1)
264                             {
265                               if(i > 0)
266                                 texture_draw(&arrow_left,(screen->w / 2) - ((subset.title.length()+2)*16)/2,20);
267                               if(i < level_subsets.num_items-1)
268                                 texture_draw(&arrow_right,(screen->w / 2) + ((subset.description.length())*16)/2,20);
269                             }
270                           text_drawf(&gold_text, subset.title.c_str(), 0, 20, A_HMIDDLE, A_TOP, 1);
271                           text_drawf(&gold_text, subset.description.c_str(), 20, -20, A_HMIDDLE, A_BOTTOM, 1);
272                         }
273                       updatescreen();
274                       SDL_Delay(50);
275                       while(SDL_PollEvent(&event) && !done)
276                         {
277                           switch(event.type)
278                             {
279                             case SDL_QUIT:
280                               done = 1;
281                               quit = 1;
282                               break;
283                             case SDL_KEYDOWN:           // key pressed
284                               // Keypress...
285                               key = event.key.keysym.sym;
286
287                               if(key == SDLK_LEFT)
288                                 {
289                                   if(i > 0)
290                                     {
291                                       --i;
292                                       subset.free();
293                                       subset.load(level_subsets.item[i]);
294                                     }
295                                 }
296                               else if(key == SDLK_RIGHT)
297                                 {
298                                   if(i < level_subsets.num_items -1)
299                                     {
300                                       ++i;
301                                       subset.free();
302                                       subset.load(level_subsets.item[i]);
303                                     }
304                                 }
305                               else if(key == SDLK_SPACE || key == SDLK_RETURN)
306                                 {
307                                   done = true;
308                                   quit = gameloop(subset.name.c_str(),1,ST_GL_PLAY);
309                                   subset.free();
310                                 }
311                               else if(key == SDLK_ESCAPE)
312                                 {
313                                   done = true;
314                                 }
315                               break;
316                             default:
317                               break;
318                             }
319                         }
320                     }
321                 }
322               // reset tux
323               scroll_x = 0;
324               titletux.level_begin();
325               update_time = st_get_ticks();
326               break;
327 #endif
328             case 0:
329               // Start Game, ie. goto the slots menu
330               update_load_save_game_menu(load_game_menu, true);
331               break;
332             case 1:
333               // Contrib Menu
334               break;
335             case 3:
336               done = 1;
337               quit = leveleditor(1);
338               break;
339             case 4:
340               display_credits();
341               break;
342             case 5:
343               quit = 1;
344               break;
345             }
346         }
347       else if(current_menu == options_menu)
348         {
349           process_options_menu();
350         }
351       else if(current_menu == load_game_menu)
352         {
353           if (process_load_game_menu())
354             {
355               // reset tux
356               scroll_x = 0;
357               titletux.level_begin();
358               update_time = st_get_ticks();
359             }
360         }
361       else if(current_menu == contrib_menu)
362         {
363           
364         }
365
366       mouse_cursor->draw();
367       
368       flipscreen();
369
370       /* Set the time of the last update and the time of the current update */
371       last_update_time = update_time;
372       update_time = st_get_ticks();
373
374       /* Pause: */
375       frame++;
376       SDL_Delay(25);
377
378     }
379   /* Free surfaces: */
380
381   texture_free(&bkg_title);
382   texture_free(&logo);
383   string_list_free(&level_subsets);
384
385   /* Return to main! */
386
387   return(quit);
388 }
389
390 #define MAX_VEL 10
391 #define SPEED   1
392 #define SCROLL  60
393
394 void display_credits()
395 {
396   int done;
397   int scroll, speed;
398   timer_type timer;
399   int n,d;
400   int length;
401   FILE* fi;
402   char temp[1024];
403   string_list_type names;
404   char filename[1024];
405   string_list_init(&names);
406   sprintf(filename,"%s/CREDITS", datadir.c_str());
407   if((fi = fopen(filename,"r")) != NULL)
408     {
409       while(fgets(temp, sizeof(temp), fi) != NULL)
410         {
411           temp[strlen(temp)-1]='\0';
412           string_list_add_item(&names,temp);
413         }
414       fclose(fi);
415     }
416   else
417     {
418       string_list_add_item(&names,"Credits were not found!");
419       string_list_add_item(&names,"Shame on the guy, who");
420       string_list_add_item(&names,"forgot to include them");
421       string_list_add_item(&names,"in your SuperTux distribution.");
422     }
423
424
425   timer_init(&timer, SDL_GetTicks());
426   timer_start(&timer, 50);
427
428   scroll = 0;
429   speed = 2;
430   done = 0;
431
432   n = d = 0;
433
434   length = names.num_items;
435
436   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
437
438   while(done == 0)
439     {
440       /* in case of input, exit */
441       while(SDL_PollEvent(&event))
442         switch(event.type)
443           {
444           case SDL_KEYDOWN:
445             switch(event.key.keysym.sym)
446               {
447               case SDLK_UP:
448                 speed -= SPEED;
449                 break;
450               case SDLK_DOWN:
451                 speed += SPEED;
452                 break;
453               case SDLK_SPACE:
454               case SDLK_RETURN:
455                 if(speed >= 0)
456                   scroll += SCROLL;
457                 break;
458               case SDLK_ESCAPE:
459                 done = 1;
460                 break;
461               default:
462                 break;
463               }
464             break;
465           case SDL_QUIT:
466             done = 1;
467             break;
468           default:
469             break;
470           }
471
472       if(speed > MAX_VEL)
473         speed = MAX_VEL;
474       else if(speed < -MAX_VEL)
475         speed = -MAX_VEL;
476
477       /* draw the credits */
478
479       draw_background();
480
481       text_drawf(&white_big_text, "- Credits -", 0, screen->h-scroll, A_HMIDDLE, A_TOP, 2);
482
483       for(i = 0, n = 0, d = 0; i < length; i++,n++,d++)
484         {
485           if(names.item[i] == "")
486             n--;
487           else
488             {
489               if(names.item[i][0] == ' ')
490                 text_drawf(&white_small_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll-10, A_HMIDDLE, A_TOP, 1);
491               else if(names.item[i][0] == '     ')
492                 text_drawf(&white_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll, A_HMIDDLE, A_TOP, 1);
493               else if(names.item[i+1][0] == '-' || names.item[i][0] == '-')
494                 text_drawf(&white_big_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll, A_HMIDDLE, A_TOP, 3);
495               else
496                 text_drawf(&blue_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll, A_HMIDDLE, A_TOP, 1);
497             }
498         }
499
500       flipscreen();
501
502       if(60+screen->h+(n*18)+(d*18)-scroll < 0 && 20+60+screen->h+(n*18)+(d*18)-scroll < 0)
503         done = 1;
504
505       scroll += speed;
506       if(scroll < 0)
507         scroll = 0;
508
509       SDL_Delay(35);
510
511       if(timer_get_left(&timer) < 0)
512         {
513           frame++;
514           timer_start(&timer, 50);
515         }
516     }
517   string_list_free(&names);
518
519   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
520   show_menu = 1;
521   Menu::set_current(main_menu);
522 }