- introduced mriceblock (at least a bit)
[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       texture_draw(&logo, 160, 30);
221       text_draw(&white_small_text, 
222                 " SuperTux " VERSION "\n"
223                 "Copyright (c) 2003 SuperTux Devel Team\n"
224                 "This game comes with ABSOLUTELY NO WARRANTY. This is free software, and you\n"
225                 "are welcome to redistribute it under certain conditions; see the file COPYING\n"
226                 "for details.\n",
227                 0, 420, 0);
228
229       /* Draw the high score: */
230       /*
231       sprintf(str, "High score: %d", hs_score);
232       text_drawf(&gold_text, str, 0, -40, A_HMIDDLE, A_BOTTOM, 1);
233       sprintf(str, "by %s", hs_name);
234       text_drawf(&gold_text, str, 0, -20, A_HMIDDLE, A_BOTTOM, 1);
235       */
236
237       /* Don't draw menu, if quit is true */
238       if(show_menu && !quit)
239         menu_process_current();
240
241       if(current_menu == main_menu)
242         {
243           switch (main_menu->check())
244             {
245             case 2:
246               done = 0;
247               i = 0;
248               if(level_subsets.num_items != 0)
249                 {
250                   subset.load(level_subsets.item[0]);
251                   while(!done)
252                     {
253                       texture_draw(&img_choose_subset,(screen->w - img_choose_subset.w) / 2, 0);
254                       if(level_subsets.num_items != 0)
255                         {
256                           texture_draw(&subset.image,(screen->w - subset.image.w) / 2 + 25,78);
257                           if(level_subsets.num_items > 1)
258                             {
259                               if(i > 0)
260                                 texture_draw(&arrow_left,(screen->w / 2) - ((subset.title.length()+2)*16)/2,20);
261                               if(i < level_subsets.num_items-1)
262                                 texture_draw(&arrow_right,(screen->w / 2) + ((subset.description.length())*16)/2,20);
263                             }
264                           text_drawf(&gold_text, subset.title.c_str(), 0, 20, A_HMIDDLE, A_TOP, 1);
265                           text_drawf(&gold_text, subset.description.c_str(), 20, -20, A_HMIDDLE, A_BOTTOM, 1);
266                         }
267                       updatescreen();
268                       SDL_Delay(50);
269                       while(SDL_PollEvent(&event) && !done)
270                         {
271                           switch(event.type)
272                             {
273                             case SDL_QUIT:
274                               done = 1;
275                               quit = 1;
276                               break;
277                             case SDL_KEYDOWN:           // key pressed
278                               /* Keypress... */
279
280                               key = event.key.keysym.sym;
281
282                               if(key == SDLK_LEFT)
283                                 {
284                                   if(i > 0)
285                                     {
286                                       --i;
287                                       subset.free();
288                                       subset.load(level_subsets.item[i]);
289                                     }
290                                 }
291                               else if(key == SDLK_RIGHT)
292                                 {
293                                   if(i < level_subsets.num_items -1)
294                                     {
295                                       ++i;
296                                       subset.free();
297                                       subset.load(level_subsets.item[i]);
298                                     }
299                                 }
300                               else if(key == SDLK_SPACE || key == SDLK_RETURN)
301                                 {
302                                   done = true;
303                                   quit = gameloop(subset.name.c_str(),1,ST_GL_PLAY);
304                                   subset.free();
305                                 }
306                               else if(key == SDLK_ESCAPE)
307                                 {
308                                   done = true;
309                                 }
310                               break;
311                             default:
312                               break;
313                             }
314                         }
315                     }
316                 }
317               // reset tux
318               scroll_x = 0;
319               titletux.level_begin();
320               update_time = st_get_ticks();
321               break;
322             case 3:
323               update_load_save_game_menu(load_game_menu, true);
324               break;
325             case 5:
326               done = 1;
327               quit = leveleditor(1);
328               break;
329             case 6:
330               display_credits();
331               break;
332             case 8:
333               quit = 1;
334               break;
335             }
336         }
337       else if(current_menu == options_menu)
338         {
339           process_options_menu();
340         }
341       else if(current_menu == load_game_menu)
342         {
343           process_save_load_game_menu(false);
344         }
345
346       mouse_cursor->draw();
347       
348       flipscreen();
349
350       /* Set the time of the last update and the time of the current update */
351       last_update_time = update_time;
352       update_time = st_get_ticks();
353
354       /* Pause: */
355       frame++;
356       SDL_Delay(25);
357
358     }
359   /* Free surfaces: */
360
361   texture_free(&bkg_title);
362   texture_free(&logo);
363   string_list_free(&level_subsets);
364
365   /* Return to main! */
366
367   return(quit);
368 }
369
370 #define MAX_VEL 10
371 #define SPEED   1
372 #define SCROLL  60
373
374 void display_credits()
375 {
376   int done;
377   int scroll, speed;
378   timer_type timer;
379   int n,d;
380   int length;
381   FILE* fi;
382   char temp[1024];
383   string_list_type names;
384   char filename[1024];
385   string_list_init(&names);
386   sprintf(filename,"%s/CREDITS", datadir.c_str());
387   if((fi = fopen(filename,"r")) != NULL)
388     {
389       while(fgets(temp, sizeof(temp), fi) != NULL)
390         {
391           temp[strlen(temp)-1]='\0';
392           string_list_add_item(&names,temp);
393         }
394       fclose(fi);
395     }
396   else
397     {
398       string_list_add_item(&names,"Credits were not found!");
399       string_list_add_item(&names,"Shame on the guy, who");
400       string_list_add_item(&names,"forgot to include them");
401       string_list_add_item(&names,"in your SuperTux distribution.");
402     }
403
404
405   timer_init(&timer, SDL_GetTicks());
406   timer_start(&timer, 50);
407
408   scroll = 0;
409   speed = 2;
410   done = 0;
411
412   n = d = 0;
413
414   length = names.num_items;
415
416   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
417
418   while(done == 0)
419     {
420       /* in case of input, exit */
421       while(SDL_PollEvent(&event))
422         switch(event.type)
423           {
424           case SDL_KEYDOWN:
425             switch(event.key.keysym.sym)
426               {
427               case SDLK_UP:
428                 speed -= SPEED;
429                 break;
430               case SDLK_DOWN:
431                 speed += SPEED;
432                 break;
433               case SDLK_SPACE:
434               case SDLK_RETURN:
435                 if(speed >= 0)
436                   scroll += SCROLL;
437                 break;
438               case SDLK_ESCAPE:
439                 done = 1;
440                 break;
441               default:
442                 break;
443               }
444             break;
445           case SDL_QUIT:
446             done = 1;
447             break;
448           default:
449             break;
450           }
451
452       if(speed > MAX_VEL)
453         speed = MAX_VEL;
454       else if(speed < -MAX_VEL)
455         speed = -MAX_VEL;
456
457       /* draw the credits */
458
459       draw_background();
460
461       text_drawf(&white_big_text, "- Credits -", 0, screen->h-scroll, A_HMIDDLE, A_TOP, 2);
462
463       for(i = 0, n = 0, d = 0; i < length; i++,n++,d++)
464         {
465           if(names.item[i] == "")
466             n--;
467           else
468             {
469               if(names.item[i][0] == ' ')
470                 text_drawf(&white_small_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll-10, A_HMIDDLE, A_TOP, 1);
471               else if(names.item[i][0] == '     ')
472                 text_drawf(&white_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll, A_HMIDDLE, A_TOP, 1);
473               else if(names.item[i+1][0] == '-' || names.item[i][0] == '-')
474                 text_drawf(&white_big_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll, A_HMIDDLE, A_TOP, 3);
475               else
476                 text_drawf(&blue_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll, A_HMIDDLE, A_TOP, 1);
477             }
478         }
479
480       flipscreen();
481
482       if(60+screen->h+(n*18)+(d*18)-scroll < 0 && 20+60+screen->h+(n*18)+(d*18)-scroll < 0)
483         done = 1;
484
485       scroll += speed;
486       if(scroll < 0)
487         scroll = 0;
488
489       SDL_Delay(35);
490
491       if(timer_get_left(&timer) < 0)
492         {
493           frame++;
494           timer_start(&timer, 50);
495         }
496     }
497   string_list_free(&names);
498
499   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
500   show_menu = 1;
501   Menu::set_current(main_menu);
502 }