6b86242ea88a0af6d341afa4a9fc063a3b0a266f
[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_type 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   loadshared();
150
151   //FIXME:activate_particle_systems();
152
153   /* Reset menu variables */
154   menu_reset();
155   Menu::set_current(main_menu);
156
157   clearscreen(0, 0, 0);
158   updatescreen();
159
160   /* Load images: */
161
162   texture_load(&bkg_title,datadir + "/images/title/background.jpg", IGNORE_ALPHA);
163   texture_load(&logo,datadir + "/images/title/logo.png", USE_ALPHA);
164   texture_load(&img_choose_subset,datadir + "/images/status/choose-level-subset.png", USE_ALPHA);
165
166   /* --- Main title loop: --- */
167   bool done = 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   random_timer.start(rand() % 2000 + 2000);
177
178   while (!done)
179     {
180       /* Calculate the movement-factor */
181       double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
182       if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
183         frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
184       /* Lower the frame_ratio that Tux doesn't jump to hectically throught the demo. */
185       frame_ratio /= 2;
186
187       /* Handle events: */
188
189       while (SDL_PollEvent(&event))
190         {
191           menu_event(event);
192           if (event.type == SDL_QUIT)
193             {
194               done = true;
195             }
196           else if (event.type == SDL_KEYDOWN)
197             {
198               /* Keypress... */
199               key = event.key.keysym.sym;
200
201               /* Check for menu events */
202               //menu_event(event);
203
204               if (key == SDLK_ESCAPE)
205                 {
206                   /* Escape: Quit: */
207                   done = true;
208                 }
209             }
210         }
211
212       /* Draw the background: */
213       draw_background();
214       draw_demo(&session, frame_ratio);
215       
216       if (current_menu == main_menu)
217         texture_draw(&logo, 160, 30);
218
219       text_draw(&white_small_text, 
220                 " SuperTux " VERSION "\n"
221                 "Copyright (c) 2003 SuperTux Devel Team\n"
222                 "This game comes with ABSOLUTELY NO WARRANTY. This is free software, and you\n"
223                 "are welcome to redistribute it under certain conditions; see the file COPYING\n"
224                 "for details.\n",
225                 0, 420, 0);
226
227       /* Draw the high score: */
228       /*
229         sprintf(str, "High score: %d", hs_score);
230         text_drawf(&gold_text, str, 0, -40, A_HMIDDLE, A_BOTTOM, 1);
231         sprintf(str, "by %s", hs_name);
232         text_drawf(&gold_text, str, 0, -20, A_HMIDDLE, A_BOTTOM, 1);
233       */
234
235       /* Don't draw menu, if quit is true */
236       if(show_menu && !done)
237         menu_process_current();
238
239       if(current_menu == main_menu)
240         {
241           switch (main_menu->check())
242             {
243 #if 0
244             case 0:
245               // Quick Play
246               // FIXME: obsolete
247               done = 0;
248               i = 0;
249               if(level_subsets.num_items != 0)
250                 {
251                   subset.load(level_subsets.item[0]);
252                   while(!done)
253                     {
254                       texture_draw(&img_choose_subset,(screen->w - img_choose_subset.w) / 2, 0);
255                       if(level_subsets.num_items != 0)
256                         {
257                           texture_draw(&subset.image,(screen->w - subset.image.w) / 2 + 25,78);
258                           if(level_subsets.num_items > 1)
259                             {
260                               if(i > 0)
261                                 texture_draw(&arrow_left,(screen->w / 2) - ((subset.title.length()+2)*16)/2,20);
262                               if(i < level_subsets.num_items-1)
263                                 texture_draw(&arrow_right,(screen->w / 2) + ((subset.description.length())*16)/2,20);
264                             }
265                           text_drawf(&gold_text, subset.title.c_str(), 0, 20, A_HMIDDLE, A_TOP, 1);
266                           text_drawf(&gold_text, subset.description.c_str(), 20, -20, A_HMIDDLE, A_BOTTOM, 1);
267                         }
268                       updatescreen();
269                       SDL_Delay(50);
270                       while(SDL_PollEvent(&event) && !done)
271                         {
272                           switch(event.type)
273                             {
274                             case SDL_QUIT:
275                               done = true;
276                               break;
277                             case SDL_KEYDOWN:           // key pressed
278                               // Keypress...
279                               key = event.key.keysym.sym;
280
281                               if(key == SDLK_LEFT)
282                                 {
283                                   if(i > 0)
284                                     {
285                                       --i;
286                                       subset.free();
287                                       subset.load(level_subsets.item[i]);
288                                     }
289                                 }
290                               else if(key == SDLK_RIGHT)
291                                 {
292                                   if(i < level_subsets.num_items -1)
293                                     {
294                                       ++i;
295                                       subset.free();
296                                       subset.load(level_subsets.item[i]);
297                                     }
298                                 }
299                               else if(key == SDLK_SPACE || key == SDLK_RETURN)
300                                 {
301                                   done = true;
302                                   quit = gameloop(subset.name.c_str(),1,ST_GL_PLAY);
303                                   subset.free();
304                                 }
305                               else if(key == SDLK_ESCAPE)
306                                 {
307                                   done = true;
308                                 }
309                               break;
310                             default:
311                               break;
312                             }
313                         }
314                     }
315                 }
316               // reset tux
317               scroll_x = 0;
318               titletux.level_begin();
319               update_time = st_get_ticks();
320               break;
321 #endif
322             case 0:
323               // Start Game, ie. goto the slots menu
324               update_load_save_game_menu(load_game_menu, true);
325               break;
326             case 1:
327               // Contrib Menu
328               break;
329             case 3:
330               done = 1;
331               done = leveleditor(1);
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_type 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 }