10b7c4c3a6519b54338ca976a435d26b1c70f5b0
[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           current_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_reset();
332               show_menu = 1;
333               Menu::set_current(main_menu);
334               break;
335             case 4:
336               display_credits();
337               break;
338             case 5:
339               done = true;
340               break;
341             }
342         }
343       else if(current_menu == options_menu)
344         {
345           process_options_menu();
346         }
347       else if(current_menu == load_game_menu)
348         {
349           if (process_load_game_menu())
350             {
351               // FIXME: shouldn't be needed if GameSession doesn't relay on global variables
352               // reset tux
353               scroll_x = 0;
354               //titletux.level_begin();
355               update_time = st_get_ticks();
356             }
357         }
358       else if(current_menu == contrib_menu)
359         {
360           
361         }
362
363       mouse_cursor->draw();
364       
365       flipscreen();
366
367       /* Set the time of the last update and the time of the current update */
368       last_update_time = update_time;
369       update_time = st_get_ticks();
370
371       /* Pause: */
372       frame++;
373       SDL_Delay(25);
374
375     }
376   /* Free surfaces: */
377
378   texture_free(&bkg_title);
379   texture_free(&logo);
380   string_list_free(&level_subsets);
381
382   /* Return to main! */
383   return done;
384 }
385
386 #define MAX_VEL 10
387 #define SPEED   1
388 #define SCROLL  60
389
390 void display_credits()
391 {
392   int done;
393   int scroll, speed;
394   Timer timer;
395   int n,d;
396   int length;
397   FILE* fi;
398   char temp[1024];
399   string_list_type names;
400   char filename[1024];
401   string_list_init(&names);
402   sprintf(filename,"%s/CREDITS", datadir.c_str());
403   if((fi = fopen(filename,"r")) != NULL)
404     {
405       while(fgets(temp, sizeof(temp), fi) != NULL)
406         {
407           temp[strlen(temp)-1]='\0';
408           string_list_add_item(&names,temp);
409         }
410       fclose(fi);
411     }
412   else
413     {
414       string_list_add_item(&names,"Credits were not found!");
415       string_list_add_item(&names,"Shame on the guy, who");
416       string_list_add_item(&names,"forgot to include them");
417       string_list_add_item(&names,"in your SuperTux distribution.");
418     }
419
420
421   timer.init(SDL_GetTicks());
422   timer.start(50);
423
424   scroll = 0;
425   speed = 2;
426   done = 0;
427
428   n = d = 0;
429
430   length = names.num_items;
431
432   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
433
434   while(done == 0)
435     {
436       /* in case of input, exit */
437       while(SDL_PollEvent(&event))
438         switch(event.type)
439           {
440           case SDL_KEYDOWN:
441             switch(event.key.keysym.sym)
442               {
443               case SDLK_UP:
444                 speed -= SPEED;
445                 break;
446               case SDLK_DOWN:
447                 speed += SPEED;
448                 break;
449               case SDLK_SPACE:
450               case SDLK_RETURN:
451                 if(speed >= 0)
452                   scroll += SCROLL;
453                 break;
454               case SDLK_ESCAPE:
455                 done = 1;
456                 break;
457               default:
458                 break;
459               }
460             break;
461           case SDL_QUIT:
462             done = 1;
463             break;
464           default:
465             break;
466           }
467
468       if(speed > MAX_VEL)
469         speed = MAX_VEL;
470       else if(speed < -MAX_VEL)
471         speed = -MAX_VEL;
472
473       /* draw the credits */
474
475       draw_background();
476
477       text_drawf(&white_big_text, "- Credits -", 0, screen->h-scroll, A_HMIDDLE, A_TOP, 2);
478
479       for(i = 0, n = 0, d = 0; i < length; i++,n++,d++)
480         {
481           if(names.item[i] == "")
482             n--;
483           else
484             {
485               if(names.item[i][0] == ' ')
486                 text_drawf(&white_small_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll-10, A_HMIDDLE, A_TOP, 1);
487               else if(names.item[i][0] == '     ')
488                 text_drawf(&white_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll, A_HMIDDLE, A_TOP, 1);
489               else if(names.item[i+1][0] == '-' || names.item[i][0] == '-')
490                 text_drawf(&white_big_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll, A_HMIDDLE, A_TOP, 3);
491               else
492                 text_drawf(&blue_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll, A_HMIDDLE, A_TOP, 1);
493             }
494         }
495
496       flipscreen();
497
498       if(60+screen->h+(n*18)+(d*18)-scroll < 0 && 20+60+screen->h+(n*18)+(d*18)-scroll < 0)
499         done = 1;
500
501       scroll += speed;
502       if(scroll < 0)
503         scroll = 0;
504
505       SDL_Delay(35);
506
507       if(timer.get_left() < 0)
508         {
509           frame++;
510           timer.start(50);
511         }
512     }
513   string_list_free(&names);
514
515   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
516   show_menu = 1;
517   Menu::set_current(main_menu);
518 }