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