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