We have our own mouse-cursor now! (graphics by Settra Gaia)
[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 void activate_particle_systems(void);
44
45 static texture_type bkg_title, img_choose_subset, anim1, anim2;
46 static SDL_Event event;
47 static SDLKey key;
48 static int frame, pict, i;
49 static unsigned int last_update_time;
50 static unsigned int update_time;
51
52 void display_credits();
53
54 void draw_background()
55 {
56   /* Draw the title background: */
57
58   texture_draw_bg(&bkg_title);
59
60   /* Animate title screen: */
61
62   pict = (frame / 5) % 3;
63
64   if (pict == 0)
65     texture_draw_part(&bkg_title, 560, 270, 560, 270, 80, 75);
66   else if (pict == 1)
67     texture_draw(&anim1, 560, 270);
68   else if (pict == 2)
69     texture_draw(&anim2, 560, 270);
70 }
71
72 /* --- TITLE SCREEN --- */
73
74 int title(void)
75 {
76   int done;
77   char str[80];
78   string_list_type level_subsets;
79   st_subset subset;
80   level_subsets = dsubdirs("/levels", "info");
81   timer_type random_timer;
82   timer_init(&random_timer, true);
83   bool walking = true;
84   Player titletux;
85   titletux.init();
86   st_pause_ticks_init();
87   st_pause_ticks_stop();
88
89   level_load(&current_level, (datadir + "/levels/misc/menu.stl").c_str());
90   loadshared();
91   activate_particle_systems();
92   /* Lower the gravity that tux doesn't jump to hectically through the demo */
93   gravity = 5;
94
95   /* Reset menu variables */
96   menu_reset();
97   Menu::set_current(main_menu);
98
99   clearscreen(0, 0, 0);
100   updatescreen();
101
102   /* Load images: */
103
104   texture_load(&bkg_title,datadir + "/images/title/title.png", IGNORE_ALPHA);
105   texture_load(&anim1,datadir + "/images/title/title-anim2.png", IGNORE_ALPHA);
106   texture_load(&anim2,datadir + "/images/title/title-anim1.png", IGNORE_ALPHA);
107   texture_load(&img_choose_subset,datadir + "/images/status/choose-level-subset.png", USE_ALPHA);
108
109   /* --- Main title loop: --- */
110
111   done = 0;
112   quit = 0;
113   show_menu = 1;
114   frame = 0;
115
116   /* Draw the title background: */
117   texture_draw_bg(&bkg_title);
118   load_hs();
119
120   update_time = st_get_ticks();
121   timer_start(&random_timer, rand() % 2000 + 2000);
122
123   while (!done && !quit)
124     {
125
126       /* Calculate the movement-factor */
127       frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
128       if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
129         frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
130       /* Lower the frame_ratio that Tux doesn't jump to hectically throught the demo. */
131       frame_ratio /= 2;
132
133       /* Handle events: */
134
135       while (SDL_PollEvent(&event))
136         {
137         menu_event(event);
138           if (event.type == SDL_QUIT)
139             {
140               /* Quit event - quit: */
141               quit = 1;
142             }
143           else if (event.type == SDL_KEYDOWN)
144             {
145               /* Keypress... */
146
147               key = event.key.keysym.sym;
148
149               /* Check for menu events */
150               //menu_event(event);
151
152               if (key == SDLK_ESCAPE)
153                 {
154                   /* Escape: Quit: */
155
156                   quit = 1;
157                 }
158             }
159         }
160
161       /* Draw the background: */
162       draw_background();
163
164       /* DEMO begin */
165       /* update particle systems */
166       std::vector<ParticleSystem*>::iterator p;
167       for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
168         {
169           (*p)->simulate(frame_ratio);
170         }
171
172       /* Draw particle systems (background) */
173       for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
174         {
175           (*p)->draw(scroll_x, 0, 0);
176         }
177
178       /* Draw interactive tiles: */
179
180       for (int y = 0; y < 15; ++y)
181         {
182           for (int x = 0; x < 21; ++x)
183             {
184               drawshape(32*x - fmodf(scroll_x, 32), y * 32,
185                         current_level.ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
186             }
187         }
188
189       global_frame_counter++;
190       titletux.key_event(SDLK_RIGHT,DOWN);
191
192       
193       if(timer_check(&random_timer))
194         {
195           if(walking)
196           titletux.key_event(SDLK_UP,UP);
197           else
198           titletux.key_event(SDLK_UP,DOWN);
199         }
200       else
201         {
202           timer_start(&random_timer, rand() % 3000 + 3000);
203           walking = !walking;
204         }
205
206       if(current_level.width * 32 - 320 < titletux.base.x)
207         {
208           titletux.base.x = 160;
209           scroll_x = 0;
210         }
211
212       titletux.action();
213       titletux.draw();
214
215       /* DEMO end */
216
217       /* Draw the high score: */
218       sprintf(str, "High score: %d", hs_score);
219       text_drawf(&gold_text, str, 0, -40, A_HMIDDLE, A_BOTTOM, 1);
220       sprintf(str, "by %s", hs_name);
221       text_drawf(&gold_text, str, 0, -20, A_HMIDDLE, A_BOTTOM, 1);
222
223
224       /* Don't draw menu, if quit is true */
225       if(show_menu && !quit)
226         menu_process_current();
227
228       if(current_menu == main_menu)
229         {
230           switch (main_menu->check())
231             {
232             case 2:
233               done = 0;
234               i = 0;
235               if(level_subsets.num_items != 0)
236                 {
237                   subset.load(level_subsets.item[0]);
238                   while(!done)
239                     {
240                       texture_draw(&img_choose_subset,(screen->w - img_choose_subset.w) / 2, 0);
241                       if(level_subsets.num_items != 0)
242                         {
243                           texture_draw(&subset.image,(screen->w - subset.image.w) / 2 + 25,78);
244                           if(level_subsets.num_items > 1)
245                             {
246                               if(i > 0)
247                                 texture_draw(&arrow_left,(screen->w / 2) - ((subset.title.length()+2)*16)/2,20);
248                               if(i < level_subsets.num_items-1)
249                                 texture_draw(&arrow_right,(screen->w / 2) + ((subset.description.length())*16)/2,20);
250                             }
251                           text_drawf(&gold_text, subset.title.c_str(), 0, 20, A_HMIDDLE, A_TOP, 1);
252                           text_drawf(&gold_text, subset.description.c_str(), 20, -20, A_HMIDDLE, A_BOTTOM, 1);
253                         }
254                       updatescreen();
255                       SDL_Delay(50);
256                       while(SDL_PollEvent(&event) && !done)
257                         {
258                           switch(event.type)
259                             {
260                             case SDL_QUIT:
261                               done = 1;
262                               quit = 1;
263                               break;
264                             case SDL_KEYDOWN:           // key pressed
265                               /* Keypress... */
266
267                               key = event.key.keysym.sym;
268
269                               if(key == SDLK_LEFT)
270                                 {
271                                   if(i > 0)
272                                     {
273                                       --i;
274                                       subset.free();
275                                       subset.load(level_subsets.item[i]);
276                                     }
277                                 }
278                               else if(key == SDLK_RIGHT)
279                                 {
280                                   if(i < level_subsets.num_items -1)
281                                     {
282                                       ++i;
283                                       subset.free();
284                                       subset.load(level_subsets.item[i]);
285                                     }
286                                 }
287                               else if(key == SDLK_SPACE || key == SDLK_RETURN)
288                                 {
289                                   done = true;
290                                   quit = gameloop(subset.name.c_str(),1,ST_GL_PLAY);
291                                   subset.free();
292                                 }
293                               else if(key == SDLK_ESCAPE)
294                                 {
295                                   done = true;
296                                 }
297                               break;
298                             default:
299                               break;
300                             }
301                         }
302                     }
303                 }
304               break;
305             case 3:
306               update_load_save_game_menu(load_game_menu, true);
307               break;
308             case 5:
309               done = 1;
310               quit = leveleditor(1);
311               break;
312             case 6:
313               display_credits();
314               break;
315             case 8:
316               quit = 1;
317               break;
318             }
319         }
320       else if(current_menu == options_menu)
321         {
322           process_options_menu();
323         }
324       else if(current_menu == load_game_menu)
325         {
326           process_save_load_game_menu(false);
327         }
328
329       mouse_cursor->draw();
330       
331       flipscreen();
332
333       /* Set the time of the last update and the time of the current update */
334       last_update_time = update_time;
335       update_time = st_get_ticks();
336
337       /* Pause: */
338       frame++;
339       SDL_Delay(25);
340
341     }
342   /* Free surfaces: */
343
344   texture_free(&bkg_title);
345   texture_free(&anim1);
346   texture_free(&anim2);
347   string_list_free(&level_subsets);
348
349   /* Return to main! */
350
351   return(quit);
352 }
353
354 #define MAX_VEL 10
355 #define SPEED   1
356 #define SCROLL  60
357
358 void display_credits()
359 {
360   int done;
361   int scroll, speed;
362   timer_type timer;
363   int n,d;
364   int length;
365   FILE* fi;
366   char temp[1024];
367   string_list_type names;
368   char filename[1024];
369   string_list_init(&names);
370   sprintf(filename,"%s/CREDITS", datadir.c_str());
371   if((fi = fopen(filename,"r")) != NULL)
372     {
373       while(fgets(temp, sizeof(temp), fi) != NULL)
374         {
375           temp[strlen(temp)-1]='\0';
376           string_list_add_item(&names,temp);
377         }
378       fclose(fi);
379     }
380   else
381     {
382       string_list_add_item(&names,"Credits were not found!");
383       string_list_add_item(&names,"Shame on the guy, who");
384       string_list_add_item(&names,"forgot to include them");
385       string_list_add_item(&names,"in your SuperTux distribution.");
386     }
387
388
389   timer_init(&timer, SDL_GetTicks());
390   timer_start(&timer, 50);
391
392   scroll = 0;
393   speed = 2;
394   done = 0;
395
396   n = d = 0;
397
398   length = names.num_items;
399
400   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
401
402   while(done == 0)
403     {
404       /* in case of input, exit */
405       while(SDL_PollEvent(&event))
406         switch(event.type)
407           {
408           case SDL_KEYDOWN:
409             switch(event.key.keysym.sym)
410               {
411               case SDLK_UP:
412                 speed -= SPEED;
413                 break;
414               case SDLK_DOWN:
415                 speed += SPEED;
416                 break;
417               case SDLK_SPACE:
418               case SDLK_RETURN:
419                 if(speed >= 0)
420                   scroll += SCROLL;
421                 break;
422               case SDLK_ESCAPE:
423                 done = 1;
424                 break;
425               default:
426                 break;
427               }
428             break;
429           case SDL_QUIT:
430             done = 1;
431             break;
432           default:
433             break;
434           }
435
436       if(speed > MAX_VEL)
437         speed = MAX_VEL;
438       else if(speed < -MAX_VEL)
439         speed = -MAX_VEL;
440
441       /* draw the credits */
442
443       draw_background();
444
445       text_drawf(&white_big_text, "- Credits -", 0, screen->h-scroll, A_HMIDDLE, A_TOP, 2);
446
447       for(i = 0, n = 0, d = 0; i < length; i++,n++,d++)
448         {
449           if(names.item[i] == "")
450             n--;
451           else
452             {
453               if(names.item[i][0] == ' ')
454                 text_drawf(&white_small_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll-10, A_HMIDDLE, A_TOP, 1);
455               else if(names.item[i][0] == '     ')
456                 text_drawf(&white_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll, A_HMIDDLE, A_TOP, 1);
457               else if(names.item[i+1][0] == '-' || names.item[i][0] == '-')
458                 text_drawf(&white_big_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll, A_HMIDDLE, A_TOP, 3);
459               else
460                 text_drawf(&blue_text, names.item[i], 0, 60+screen->h+(n*18)+(d*18)-scroll, A_HMIDDLE, A_TOP, 1);
461             }
462         }
463
464
465       texture_draw_part(&bkg_title, 0, 0, 0, 0, 640, 130);
466       
467       flipscreen();
468
469       if(60+screen->h+(n*18)+(d*18)-scroll < 0 && 20+60+screen->h+(n*18)+(d*18)-scroll < 0)
470         done = 1;
471
472       scroll += speed;
473       if(scroll < 0)
474         scroll = 0;
475
476       SDL_Delay(35);
477
478       if(timer_get_left(&timer) < 0)
479         {
480           frame++;
481           timer_start(&timer, 50);
482         }
483     }
484   string_list_free(&names);
485
486   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
487   show_menu = 1;
488   Menu::set_current(main_menu);
489 }