- moved gameobjects into there own file
[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
43 void loadshared(void);
44
45 static texture_type bkg_title;
46 static texture_type logo;
47 static texture_type img_choose_subset;
48
49 static bool walking;
50 static Player titletux;
51 static timer_type random_timer;
52
53 static SDL_Event event;
54 static SDLKey key;
55 static int frame, i;
56 static unsigned int last_update_time;
57 static unsigned int update_time;
58
59 void display_credits();
60
61 void draw_background()
62 {
63   /* Draw the title background: */
64
65   texture_draw_bg(&bkg_title);
66 }
67
68 void draw_demo(Level* plevel)
69 {
70   /* FIXME:
71   // update particle systems
72   std::vector<ParticleSystem*>::iterator p;
73   for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
74     {
75       (*p)->simulate(frame_ratio);
76     }
77
78   // Draw particle systems (background)
79   for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
80     {
81       (*p)->draw(scroll_x, 0, 0);
82     }
83   */
84
85   // Draw interactive tiles:
86   for (int y = 0; y < 15; ++y)
87     {
88       for (int x = 0; x < 21; ++x)
89         {
90           Tile::draw(32*x - fmodf(scroll_x, 32), y * 32,
91                      plevel->ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
92         }
93     }
94
95   global_frame_counter++;
96   titletux.key_event(SDLK_RIGHT,DOWN);
97   
98   if(timer_check(&random_timer))
99     {
100       if(walking)
101         titletux.key_event(SDLK_UP,UP);
102       else
103         titletux.key_event(SDLK_UP,DOWN);
104     }
105   else
106     {
107       timer_start(&random_timer, rand() % 3000 + 3000);
108       walking = !walking;
109     }
110   
111   // Wrap around at the end of the level back to the beginnig
112   if(plevel->width * 32 - 320 < titletux.base.x)
113     {
114       titletux.base.x = titletux.base.x - (plevel->width * 32 - 640);
115       scroll_x = titletux.base.x - 320;
116     }
117
118   float last_tux_x_pos = titletux.base.x;
119   titletux.action();
120
121   // Jump if tux stays in the same position for one loop, ie. if he is
122   // stuck behind a wall
123   if (last_tux_x_pos == titletux.base.x)
124     walking = false;
125
126   titletux.draw();
127
128   /* DEMO end */
129 }
130
131 /* --- TITLE SCREEN --- */
132
133 bool title(void)
134 {
135   string_list_type level_subsets;
136   st_subset subset;
137   level_subsets = dsubdirs("/levels", "info");
138   timer_init(&random_timer, true);
139
140   walking = true;
141   titletux.init();
142
143   st_pause_ticks_init();
144
145   GameSession session(datadir + "/levels/misc/menu.stl");
146   loadshared();
147   //FIXME:activate_particle_systems();
148   /* Lower the gravity that tux doesn't jump to hectically through the demo */
149   //gravity = 5;
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.get_level());
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               // reset tux
348               scroll_x = 0;
349               titletux.level_begin();
350               update_time = st_get_ticks();
351             }
352         }
353       else if(current_menu == contrib_menu)
354         {
355           
356         }
357
358       mouse_cursor->draw();
359       
360       flipscreen();
361
362       /* Set the time of the last update and the time of the current update */
363       last_update_time = update_time;
364       update_time = st_get_ticks();
365
366       /* Pause: */
367       frame++;
368       SDL_Delay(25);
369
370     }
371   /* Free surfaces: */
372
373   texture_free(&bkg_title);
374   texture_free(&logo);
375   string_list_free(&level_subsets);
376
377   /* Return to main! */
378   return done;
379 }
380
381 #define MAX_VEL 10
382 #define SPEED   1
383 #define SCROLL  60
384
385 void display_credits()
386 {
387   int done;
388   int scroll, speed;
389   timer_type timer;
390   int n,d;
391   int length;
392   FILE* fi;
393   char temp[1024];
394   string_list_type names;
395   char filename[1024];
396   string_list_init(&names);
397   sprintf(filename,"%s/CREDITS", datadir.c_str());
398   if((fi = fopen(filename,"r")) != NULL)
399     {
400       while(fgets(temp, sizeof(temp), fi) != NULL)
401         {
402           temp[strlen(temp)-1]='\0';
403           string_list_add_item(&names,temp);
404         }
405       fclose(fi);
406     }
407   else
408     {
409       string_list_add_item(&names,"Credits were not found!");
410       string_list_add_item(&names,"Shame on the guy, who");
411       string_list_add_item(&names,"forgot to include them");
412       string_list_add_item(&names,"in your SuperTux distribution.");
413     }
414
415
416   timer_init(&timer, SDL_GetTicks());
417   timer_start(&timer, 50);
418
419   scroll = 0;
420   speed = 2;
421   done = 0;
422
423   n = d = 0;
424
425   length = names.num_items;
426
427   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
428
429   while(done == 0)
430     {
431       /* in case of input, exit */
432       while(SDL_PollEvent(&event))
433         switch(event.type)
434           {
435           case SDL_KEYDOWN:
436             switch(event.key.keysym.sym)
437               {
438               case SDLK_UP:
439                 speed -= SPEED;
440                 break;
441               case SDLK_DOWN:
442                 speed += SPEED;
443                 break;
444               case SDLK_SPACE:
445               case SDLK_RETURN:
446                 if(speed >= 0)
447                   scroll += SCROLL;
448                 break;
449               case SDLK_ESCAPE:
450                 done = 1;
451                 break;
452               default:
453                 break;
454               }
455             break;
456           case SDL_QUIT:
457             done = 1;
458             break;
459           default:
460             break;
461           }
462
463       if(speed > MAX_VEL)
464         speed = MAX_VEL;
465       else if(speed < -MAX_VEL)
466         speed = -MAX_VEL;
467
468       /* draw the credits */
469
470       draw_background();
471
472       text_drawf(&white_big_text, "- Credits -", 0, screen->h-scroll, A_HMIDDLE, A_TOP, 2);
473
474       for(i = 0, n = 0, d = 0; i < length; i++,n++,d++)
475         {
476           if(names.item[i] == "")
477             n--;
478           else
479             {
480               if(names.item[i][0] == ' ')
481                 text_drawf(&white_small_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll-10, A_HMIDDLE, A_TOP, 1);
482               else if(names.item[i][0] == '     ')
483                 text_drawf(&white_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll, A_HMIDDLE, A_TOP, 1);
484               else if(names.item[i+1][0] == '-' || names.item[i][0] == '-')
485                 text_drawf(&white_big_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll, A_HMIDDLE, A_TOP, 3);
486               else
487                 text_drawf(&blue_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll, A_HMIDDLE, A_TOP, 1);
488             }
489         }
490
491       flipscreen();
492
493       if(60+screen->h+(n*18)+(d*18)-scroll < 0 && 20+60+screen->h+(n*18)+(d*18)-scroll < 0)
494         done = 1;
495
496       scroll += speed;
497       if(scroll < 0)
498         scroll = 0;
499
500       SDL_Delay(35);
501
502       if(timer_get_left(&timer) < 0)
503         {
504           frame++;
505           timer_start(&timer, 50);
506         }
507     }
508   string_list_free(&names);
509
510   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
511   show_menu = 1;
512   Menu::set_current(main_menu);
513 }