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