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