bc9d10c6dcdb12f55a43d78f8fe21455c08fd8de
[supertux.git] / src / setup.cpp
1 /*
2   setup.c
3   
4   Super Tux - Setup
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 <assert.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <unistd.h>
19 #include <SDL.h>
20 #include <SDL_image.h>
21 #ifndef NOOPENGL
22 #include <SDL_opengl.h>
23 #endif
24
25 #ifndef WIN32
26 #include <pwd.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <dirent.h>
30 #include <libgen.h>
31 #include <ctype.h>
32 #endif
33
34 #include "defines.h"
35 #include "globals.h"
36 #include "setup.h"
37 #include "screen.h"
38 #include "texture.h"
39 #include "menu.h"
40 #include "gameloop.h"
41
42 /* Local function prototypes: */
43
44 void seticon(void);
45 void usage(char * prog, int ret);
46
47 /* Does the given file exist and is it accessible? */
48 int faccessible(const char *filename)
49 {
50   struct stat filestat;
51   if (stat(filename, &filestat) == -1)
52     {
53       return NO;
54     }
55   else
56     {
57       if(S_ISREG(filestat.st_mode))
58         return YES;
59       else
60         return NO;
61     }
62 }
63
64 /* Can we write to this location? */
65 int fwriteable(const char *filename)
66 {
67   FILE* fi;
68   fi = fopen(filename, "wa");
69   if (fi == NULL)
70     {
71       return NO;
72     }
73   return YES;
74 }
75
76 /* Makes sure a directory is created in either the SuperTux base directory or the SuperTux base directory.*/
77 int fcreatedir(const char* relative_dir)
78 {
79   char path[1024];
80   snprintf(path, 1024, "%s/%s/", st_dir, relative_dir);
81   if(mkdir(path,0755) != 0)
82     {
83       snprintf(path, 1024, "%s/%s/", datadir.c_str(), relative_dir);
84       if(mkdir(path,0755) != 0)
85         {
86           return NO;
87         }
88       else
89         {
90           return YES;
91         }
92     }
93   else
94     {
95       return YES;
96     }
97 }
98
99 /* Get all names of sub-directories in a certain directory. */
100 /* Returns the number of sub-directories found. */
101 /* Note: The user has to free the allocated space. */
102 string_list_type dsubdirs(const char *rel_path,const  char* expected_file)
103 {
104   DIR *dirStructP;
105   struct dirent *direntp;
106   string_list_type sdirs;
107   char filename[1024];
108   char path[1024];
109
110   string_list_init(&sdirs);
111   sprintf(path,"%s/%s",st_dir,rel_path);
112   if((dirStructP = opendir(path)) != NULL)
113     {
114       while((direntp = readdir(dirStructP)) != NULL)
115         {
116           char absolute_filename[1024];
117           struct stat buf;
118
119           sprintf(absolute_filename, "%s/%s", path, direntp->d_name);
120
121           if (stat(absolute_filename, &buf) == 0 && S_ISDIR(buf.st_mode))
122             {
123               if(expected_file != NULL)
124                 {
125                   sprintf(filename,"%s/%s/%s",path,direntp->d_name,expected_file);
126                   if(!faccessible(filename))
127                     continue;
128                 }
129
130               string_list_add_item(&sdirs,direntp->d_name);
131             }
132         }
133       closedir(dirStructP);
134     }
135
136   sprintf(path,"%s/%s",datadir.c_str(),rel_path);
137   if((dirStructP = opendir(path)) != NULL)
138     {
139       while((direntp = readdir(dirStructP)) != NULL)
140         {
141           char absolute_filename[1024];
142           struct stat buf;
143
144           sprintf(absolute_filename, "%s/%s", path, direntp->d_name);
145
146           if (stat(absolute_filename, &buf) == 0 && S_ISDIR(buf.st_mode))
147             {
148               if(expected_file != NULL)
149                 {
150                   sprintf(filename,"%s/%s/%s",path,direntp->d_name,expected_file);
151                   if(!faccessible(filename))
152                     {
153                       continue;
154                     }
155                   else
156                     {
157                       sprintf(filename,"%s/%s/%s/%s",st_dir,rel_path,direntp->d_name,expected_file);
158                       if(faccessible(filename))
159                         continue;
160                     }
161                 }
162
163               string_list_add_item(&sdirs,direntp->d_name);
164             }
165         }
166       closedir(dirStructP);
167     }
168
169   return sdirs;
170 }
171
172 string_list_type dfiles(const char *rel_path, const  char* glob, const  char* exception_str)
173 {
174   DIR *dirStructP;
175   struct dirent *direntp;
176   string_list_type sdirs;
177   char path[1024];
178
179   string_list_init(&sdirs);
180   sprintf(path,"%s/%s",st_dir,rel_path);
181   if((dirStructP = opendir(path)) != NULL)
182     {
183       while((direntp = readdir(dirStructP)) != NULL)
184         {
185           char absolute_filename[1024];
186           struct stat buf;
187
188           sprintf(absolute_filename, "%s/%s", path, direntp->d_name);
189
190           if (stat(absolute_filename, &buf) == 0 && S_ISREG(buf.st_mode))
191             {
192               if(exception_str != NULL)
193                 {
194                   if(strstr(direntp->d_name,exception_str) != NULL)
195                     continue;
196                 }
197               if(glob != NULL)
198                 if(strstr(direntp->d_name,glob) == NULL)
199                   continue;
200
201               string_list_add_item(&sdirs,direntp->d_name);
202             }
203         }
204       closedir(dirStructP);
205     }
206
207   sprintf(path,"%s/%s",datadir.c_str(),rel_path);
208   if((dirStructP = opendir(path)) != NULL)
209     {
210       while((direntp = readdir(dirStructP)) != NULL)
211         {
212           char absolute_filename[1024];
213           struct stat buf;
214
215           sprintf(absolute_filename, "%s/%s", path, direntp->d_name);
216
217           if (stat(absolute_filename, &buf) == 0 && S_ISREG(buf.st_mode))
218             {
219               if(exception_str != NULL)
220                 {
221                   if(strstr(direntp->d_name,exception_str) != NULL)
222                     continue;
223                 }
224               if(glob != NULL)
225                 if(strstr(direntp->d_name,glob) == NULL)
226                   continue;
227
228               string_list_add_item(&sdirs,direntp->d_name);
229             }
230         }
231       closedir(dirStructP);
232     }
233
234   return sdirs;
235 }
236
237 void free_strings(char **strings, int num)
238 {
239   int i;
240   for(i=0; i < num; ++i)
241     free(strings[i]);
242 }
243
244 /* --- SETUP --- */
245 /* Set SuperTux configuration and save directories */
246 void st_directory_setup(void)
247 {
248   char *home;
249   char str[1024];
250   /* Get home directory (from $HOME variable)... if we can't determine it,
251      use the current directory ("."): */
252   if (getenv("HOME") != NULL)
253     home = getenv("HOME");
254   else
255     home = ".";
256
257   st_dir = (char *) malloc(sizeof(char) * (strlen(home) +
258                                            strlen("/.supertux") + 1));
259   strcpy(st_dir, home);
260   strcat(st_dir, "/.supertux");
261
262   /* Remove .supertux config-file from old SuperTux versions */
263   if(faccessible(st_dir))
264     {
265       remove
266         (st_dir);
267     }
268
269   st_save_dir = (char *) malloc(sizeof(char) * (strlen(st_dir) + strlen("/save") + 1));
270
271   strcpy(st_save_dir,st_dir);
272   strcat(st_save_dir,"/save");
273
274   /* Create them. In the case they exist they won't destroy anything. */
275 #ifndef WIN32
276   mkdir(st_dir, 0755);
277   mkdir(st_save_dir, 0755);
278
279   sprintf(str, "%s/levels", st_dir);
280   mkdir(str, 0755);
281 #else
282   mkdir(st_dir);
283   mkdir(st_save_dir);
284   sprintf(str, "%s/levels", st_dir);
285   mkdir(str);
286 #endif
287
288   // User has not that a datadir, so we try some magic
289   if (datadir.empty())
290     {
291       // Detect datadir
292       char exe_file[PATH_MAX];
293       if (readlink("/proc/self/exe", exe_file, PATH_MAX) < 0)
294         {
295           puts("Couldn't read /proc/self/exe, using default path: " DATA_PREFIX);
296           datadir = DATA_PREFIX;
297         }
298       else
299         {
300           std::string exedir = std::string(dirname(exe_file)) + "/";
301           
302           datadir = exedir + "../data/"; // SuperTux run from source dir
303           if (access(datadir.c_str(), F_OK) != 0)
304             {
305               datadir = exedir + "../share/supertux/"; // SuperTux run from PATH
306               if (access(datadir.c_str(), F_OK) != 0) 
307                 { // If all fails, fall back to compiled path
308                   datadir = DATA_PREFIX; 
309                 }
310             }
311         }
312     }
313   printf("Datadir: %s\n", datadir.c_str());
314 }
315
316 /* Create and setup menus. */
317 void st_menu(void)
318 {
319   menu_init(&main_menu);
320   menu_additem(&main_menu,menu_item_create(MN_LABEL,"Main Menu",0,0));
321   menu_additem(&main_menu,menu_item_create(MN_HL,"",0,0));
322   menu_additem(&main_menu,menu_item_create(MN_ACTION,"Start Game",0,0));
323   menu_additem(&main_menu,menu_item_create(MN_GOTO,"Load Game",0,&load_game_menu));
324   menu_additem(&main_menu,menu_item_create(MN_GOTO,"Options",0,&options_menu));
325   menu_additem(&main_menu,menu_item_create(MN_ACTION,"Level editor",0,0));
326   menu_additem(&main_menu,menu_item_create(MN_ACTION,"Credits",0,0));
327   menu_additem(&main_menu,menu_item_create(MN_HL,"",0,0));
328   menu_additem(&main_menu,menu_item_create(MN_ACTION,"Quit",0,0));
329
330   menu_init(&options_menu);
331   menu_additem(&options_menu,menu_item_create(MN_LABEL,"Options",0,0));
332   menu_additem(&options_menu,menu_item_create(MN_HL,"",0,0));
333   menu_additem(&options_menu,menu_item_create(MN_TOGGLE,"Fullscreen",use_fullscreen,0));
334   if(audio_device == YES)
335     {
336       menu_additem(&options_menu,menu_item_create(MN_TOGGLE,"Sound     ",use_sound,0));
337       menu_additem(&options_menu,menu_item_create(MN_TOGGLE,"Music     ",use_music,0));
338     }
339   else
340     {
341       menu_additem(&options_menu,menu_item_create(MN_DEACTIVE,"Sound     ",use_sound,0));
342       menu_additem(&options_menu,menu_item_create(MN_DEACTIVE,"Music     ",use_music,0));
343     }
344   menu_additem(&options_menu,menu_item_create(MN_TOGGLE,"Show FPS  ",show_fps,0));
345   menu_additem(&options_menu,menu_item_create(MN_HL,"",0,0));
346   menu_additem(&options_menu,menu_item_create(MN_BACK,"Back",0,0));
347
348   menu_init(&load_game_menu);
349   menu_additem(&load_game_menu,menu_item_create(MN_LABEL,"Load Game",0,0));
350   menu_additem(&load_game_menu,menu_item_create(MN_HL,"",0,0));
351   menu_additem(&load_game_menu,menu_item_create(MN_DEACTIVE,"Slot 1",0,0));
352   menu_additem(&load_game_menu,menu_item_create(MN_DEACTIVE,"Slot 2",0,0));
353   menu_additem(&load_game_menu,menu_item_create(MN_DEACTIVE,"Slot 3",0,0));
354   menu_additem(&load_game_menu,menu_item_create(MN_DEACTIVE,"Slot 4",0,0));
355   menu_additem(&load_game_menu,menu_item_create(MN_DEACTIVE,"Slot 5",0,0));
356   menu_additem(&load_game_menu,menu_item_create(MN_HL,"",0,0));
357   menu_additem(&load_game_menu,menu_item_create(MN_BACK,"Back",0,0));
358
359   menu_init(&save_game_menu);
360   menu_additem(&save_game_menu,menu_item_create(MN_LABEL,"Save Game",0,0));
361   menu_additem(&save_game_menu,menu_item_create(MN_HL,"",0,0));
362   menu_additem(&save_game_menu,menu_item_create(MN_DEACTIVE,"Slot 1",0,0));
363   menu_additem(&save_game_menu,menu_item_create(MN_DEACTIVE,"Slot 2",0,0));
364   menu_additem(&save_game_menu,menu_item_create(MN_DEACTIVE,"Slot 3",0,0));
365   menu_additem(&save_game_menu,menu_item_create(MN_DEACTIVE,"Slot 4",0,0));
366   menu_additem(&save_game_menu,menu_item_create(MN_DEACTIVE,"Slot 5",0,0));
367   menu_additem(&save_game_menu,menu_item_create(MN_HL,"",0,0));
368   menu_additem(&save_game_menu,menu_item_create(MN_BACK,"Back",0,0));
369
370   menu_init(&game_menu);
371   menu_additem(&game_menu,menu_item_create(MN_LABEL,"InGame Menu",0,0));
372   menu_additem(&game_menu,menu_item_create(MN_HL,"",0,0));
373   menu_additem(&game_menu,menu_item_create(MN_ACTION,"Return To Game",0,0));
374   menu_additem(&game_menu,menu_item_create(MN_GOTO,"Save Game",0,&save_game_menu));
375   menu_additem(&game_menu,menu_item_create(MN_GOTO,"Load Game",0,&load_game_menu));
376   menu_additem(&game_menu,menu_item_create(MN_GOTO,"Options",0,&options_menu));
377   menu_additem(&game_menu,menu_item_create(MN_HL,"",0,0));
378   menu_additem(&game_menu,menu_item_create(MN_ACTION,"Quit Game",0,0));
379
380   menu_init(&highscore_menu);
381   menu_additem(&highscore_menu,menu_item_create(MN_TEXTFIELD,"Enter your name:",0,0));
382
383 }
384
385 void update_load_save_game_menu(menu_type* pmenu, int load)
386 {
387   int i;
388
389   for(i = 2; i < 7; ++i)
390     {
391       char *tmp;
392       slotinfo(&tmp,i-1);
393       if(load && strlen(tmp) == strlen("Slot X - Free") )
394         pmenu->item[i].kind = MN_DEACTIVE;
395       else
396         pmenu->item[i].kind = MN_ACTION;
397       menu_item_change_text(&pmenu->item[i],tmp);
398       free(tmp);
399     }
400 }
401
402 void process_save_load_game_menu(int save)
403 {
404   int slot;
405   switch (slot = menu_check(save ? &save_game_menu : &load_game_menu))
406     {
407     default:
408       if(slot != -1)
409         {
410           if(save == YES)
411             {
412               savegame(slot - 1);
413             }
414           else
415             {
416               if(game_started == NO)
417                 {
418                   gameloop("default",slot - 1,ST_GL_LOAD_GAME);
419                   show_menu = YES;
420                   menu_set_current(&main_menu);
421                 }
422               else
423                 loadgame(slot - 1);
424             }
425           st_pause_ticks_stop();
426         }
427       break;
428     }
429 }
430
431 /* Handle changes made to global settings in the options menu. */
432 void process_options_menu(void)
433 {
434   switch (menu_check(&options_menu))
435     {
436     case 2:
437       if(use_fullscreen != options_menu.item[2].toggled)
438         {
439           use_fullscreen = !use_fullscreen;
440           st_video_setup();
441         }
442       break;
443     case 3:
444       if(use_sound != options_menu.item[3].toggled)
445         use_sound = !use_sound;
446       break;
447     case 4:
448       if(use_music != options_menu.item[4].toggled)
449         {
450           if(use_music == YES)
451             {
452               if(playing_music())
453                 {
454                   halt_music();
455                 }
456               use_music = NO;
457             }
458           else
459             {
460               use_music = YES;
461               if (!playing_music())
462                 {
463                   play_current_music();
464                 }
465             }
466         }
467       break;
468     case 5:
469       if(show_fps != options_menu.item[5].toggled)
470         show_fps = !show_fps;
471       break;
472     }
473 }
474
475 void st_general_setup(void)
476 {
477   /* Seed random number generator: */
478
479   srand(SDL_GetTicks());
480
481   /* Set icon image: */
482
483   seticon();
484
485   /* Unicode needed for input handling: */
486
487   SDL_EnableUNICODE(1);
488
489   /* Load global images: */
490
491   text_load(&black_text, datadir + "/images/status/letters-black.png", TEXT_TEXT, 16,18);
492   text_load(&gold_text,datadir + "/images/status/letters-gold.png", TEXT_TEXT, 16,18);
493   text_load(&blue_text,datadir + "/images/status/letters-blue.png", TEXT_TEXT, 16,18);
494   text_load(&red_text,datadir + "/images/status/letters-red.png", TEXT_TEXT, 16,18);
495   text_load(&white_text,datadir + "/images/status/letters-white.png", TEXT_TEXT, 16,18);
496   text_load(&white_small_text,datadir + "/images/status/letters-white-small.png", TEXT_TEXT, 8,9);
497   text_load(&white_big_text,datadir + "/images/status/letters-white-big.png", TEXT_TEXT, 20,23);
498   text_load(&yellow_nums,datadir + "/images/status/numbers.png", TEXT_NUM, 32,32);
499
500   /* Load GUI/menu images: */
501   texture_load(&checkbox, datadir + "/images/status/checkbox.png", USE_ALPHA);
502   texture_load(&checkbox_checked, datadir + "/images/status/checkbox-checked.png", USE_ALPHA);
503   texture_load(&back, datadir + "/images/status/back.png", USE_ALPHA);
504   texture_load(&arrow_left, datadir + "/images/icons/left.png", USE_ALPHA);
505   texture_load(&arrow_right, datadir + "/images/icons/right.png", USE_ALPHA);
506
507 }
508
509 void st_general_free(void)
510 {
511
512   /* Free global images: */
513
514   text_free(&black_text);
515   text_free(&gold_text);
516   text_free(&white_text);
517   text_free(&blue_text);
518   text_free(&red_text);
519   text_free(&white_small_text);
520   text_free(&white_big_text);
521
522   /* Free GUI/menu images: */
523   texture_free(&checkbox);
524   texture_free(&checkbox_checked);
525   texture_free(&back);
526   texture_free(&arrow_left);
527   texture_free(&arrow_right);
528
529   /* Free menus */
530
531   menu_free(&main_menu);
532   menu_free(&game_menu);
533   menu_free(&options_menu);
534   menu_free(&highscore_menu);
535   menu_free(&save_game_menu);
536   menu_free(&load_game_menu);
537
538 }
539
540 void st_video_setup(void)
541 {
542
543   if(screen != NULL)
544     SDL_FreeSurface(screen);
545
546   /* Init SDL Video: */
547
548   if (SDL_Init(SDL_INIT_VIDEO) < 0)
549     {
550       fprintf(stderr,
551               "\nError: I could not initialize video!\n"
552               "The Simple DirectMedia error that occured was:\n"
553               "%s\n\n", SDL_GetError());
554       exit(1);
555     }
556
557   /* Open display: */
558
559   if(use_gl)
560     st_video_setup_gl();
561   else
562     st_video_setup_sdl();
563
564   texture_setup();
565
566   /* Set window manager stuff: */
567
568   SDL_WM_SetCaption("Super Tux", "Super Tux");
569
570 }
571
572 void st_video_setup_sdl(void)
573 {
574   SDL_FreeSurface(screen);
575
576   if (use_fullscreen == YES)
577     {
578       screen = SDL_SetVideoMode(640, 480, 0, SDL_FULLSCREEN ) ; /* | SDL_HWSURFACE); */
579       if (screen == NULL)
580         {
581           fprintf(stderr,
582                   "\nWarning: I could not set up fullscreen video for "
583                   "640x480 mode.\n"
584                   "The Simple DirectMedia error that occured was:\n"
585                   "%s\n\n", SDL_GetError());
586           use_fullscreen = NO;
587         }
588     }
589   else
590     {
591       screen = SDL_SetVideoMode(640, 480, 0, SDL_HWSURFACE | SDL_DOUBLEBUF );
592
593       if (screen == NULL)
594         {
595           fprintf(stderr,
596                   "\nError: I could not set up video for 640x480 mode.\n"
597                   "The Simple DirectMedia error that occured was:\n"
598                   "%s\n\n", SDL_GetError());
599           exit(1);
600         }
601     }
602 }
603
604 void st_video_setup_gl(void)
605 {
606 #ifndef NOOPENGL
607
608   SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
609   SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
610   SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
611   SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
612   SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
613
614   if (use_fullscreen == YES)
615     {
616       screen = SDL_SetVideoMode(640, 480, 0, SDL_FULLSCREEN | SDL_OPENGL) ; /* | SDL_HWSURFACE); */
617       if (screen == NULL)
618         {
619           fprintf(stderr,
620                   "\nWarning: I could not set up fullscreen video for "
621                   "640x480 mode.\n"
622                   "The Simple DirectMedia error that occured was:\n"
623                   "%s\n\n", SDL_GetError());
624           use_fullscreen = NO;
625         }
626     }
627   else
628     {
629       screen = SDL_SetVideoMode(640, 480, 0, SDL_OPENGL);
630
631       if (screen == NULL)
632         {
633           fprintf(stderr,
634                   "\nError: I could not set up video for 640x480 mode.\n"
635                   "The Simple DirectMedia error that occured was:\n"
636                   "%s\n\n", SDL_GetError());
637           exit(1);
638         }
639     }
640
641   /*
642    * Set up OpenGL for 2D rendering.
643    */
644   glDisable(GL_DEPTH_TEST);
645   glDisable(GL_CULL_FACE);
646
647   glViewport(0, 0, screen->w, screen->h);
648   glMatrixMode(GL_PROJECTION);
649   glLoadIdentity();
650   glOrtho(0, screen->w, screen->h, 0, -1.0, 1.0);
651
652   glMatrixMode(GL_MODELVIEW);
653   glLoadIdentity();
654   glTranslatef(0.0f, 0.0f, 0.0f);
655
656 #endif
657
658 }
659
660 void st_joystick_setup(void)
661 {
662
663   /* Init Joystick: */
664
665 #ifdef JOY_YES
666   use_joystick = YES;
667
668   if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
669     {
670       fprintf(stderr, "Warning: I could not initialize joystick!\n"
671               "The Simple DirectMedia error that occured was:\n"
672               "%s\n\n", SDL_GetError());
673
674       use_joystick = NO;
675     }
676   else
677     {
678       /* Open joystick: */
679
680       if (SDL_NumJoysticks() <= 0)
681         {
682           fprintf(stderr, "Warning: No joysticks are available.\n");
683
684           use_joystick = NO;
685         }
686       else
687         {
688           js = SDL_JoystickOpen(0);
689
690           if (js == NULL)
691             {
692               fprintf(stderr, "Warning: Could not open joystick 1.\n"
693                       "The Simple DirectMedia error that occured was:\n"
694                       "%s\n\n", SDL_GetError());
695
696               use_joystick = NO;
697             }
698           else
699             {
700               /* Check for proper joystick configuration: */
701
702               if (SDL_JoystickNumAxes(js) < 2)
703                 {
704                   fprintf(stderr,
705                           "Warning: Joystick does not have enough axes!\n");
706
707                   use_joystick = NO;
708                 }
709               else
710                 {
711                   if (SDL_JoystickNumButtons(js) < 2)
712                     {
713                       fprintf(stderr,
714                               "Warning: "
715                               "Joystick does not have enough buttons!\n");
716
717                       use_joystick = NO;
718                     }
719                 }
720             }
721         }
722     }
723 #endif
724
725 }
726
727 void st_audio_setup(void)
728 {
729
730   /* Init SDL Audio silently even if --disable-sound : */
731
732   if (audio_device == YES)
733     {
734       if (SDL_Init(SDL_INIT_AUDIO) < 0)
735         {
736           /* only print out message if sound or music
737              was not disabled at command-line
738            */
739           if (use_sound == YES || use_music == YES)
740             {
741               fprintf(stderr,
742                       "\nWarning: I could not initialize audio!\n"
743                       "The Simple DirectMedia error that occured was:\n"
744                       "%s\n\n", SDL_GetError());
745             }
746           /* keep the programming logic the same :-)
747              because in this case, use_sound & use_music' values are ignored
748              when there's no available audio device
749           */
750           use_sound = NO;
751           use_music = NO;
752           audio_device = NO;
753         }
754     }
755
756
757   /* Open sound silently regarless the value of "use_sound": */
758
759   if (audio_device == YES)
760     {
761       if (open_audio(44100, AUDIO_S16, 2, 2048) < 0)
762         {
763           /* only print out message if sound or music
764              was not disabled at command-line
765            */
766           if ((use_sound == YES) || (use_music == YES))
767             {
768               fprintf(stderr,
769                       "\nWarning: I could not set up audio for 44100 Hz "
770                       "16-bit stereo.\n"
771                       "The Simple DirectMedia error that occured was:\n"
772                       "%s\n\n", SDL_GetError());
773             }
774           use_sound = NO;
775           use_music = NO;
776           audio_device = NO;
777         }
778     }
779
780 }
781
782
783 /* --- SHUTDOWN --- */
784
785 void st_shutdown(void)
786 {
787   close_audio();
788   SDL_Quit();
789 }
790
791
792 /* --- ABORT! --- */
793
794 void st_abort(const char * reason,const  char * details)
795 {
796   fprintf(stderr, "\nError: %s\n%s\n\n", reason, details);
797   st_shutdown();
798   exit(1);
799 }
800
801
802 /* Set Icon (private) */
803
804 void seticon(void)
805 {
806   int masklen;
807   Uint8 * mask;
808   SDL_Surface * icon;
809
810
811   /* Load icon into a surface: */
812
813   icon = IMG_Load((datadir + "/images/icon.png").c_str());
814   if (icon == NULL)
815     {
816       fprintf(stderr,
817               "\nError: I could not load the icon image: %s%s\n"
818               "The Simple DirectMedia error that occured was:\n"
819               "%s\n\n", datadir.c_str(), "/images/icon.png", SDL_GetError());
820       exit(1);
821     }
822
823
824   /* Create mask: */
825
826   masklen = (((icon -> w) + 7) / 8) * (icon -> h);
827   mask = (Uint8*) malloc(masklen * sizeof(Uint8));
828   memset(mask, 0xFF, masklen);
829
830
831   /* Set icon: */
832
833   SDL_WM_SetIcon(icon, mask);
834
835
836   /* Free icon surface & mask: */
837
838   free(mask);
839   SDL_FreeSurface(icon);
840 }
841
842
843 /* Parse command-line arguments: */
844
845 void parseargs(int argc, char * argv[])
846 {
847   int i;
848
849   /* Set defaults: */
850
851
852   debug_mode = NO;
853   use_fullscreen = NO;
854   show_fps = NO;
855   use_gl = NO;
856
857 #ifndef NOSOUND
858
859   use_sound = YES;
860   use_music = YES;
861   audio_device = YES;
862 #else
863
864   use_sound = NO;
865   use_music = NO;
866   audio_device = NO;
867 #endif
868
869   /* Parse arguments: */
870
871   for (i = 1; i < argc; i++)
872     {
873       if (strcmp(argv[i], "--fullscreen") == 0 ||
874           strcmp(argv[i], "-f") == 0)
875         {
876           /* Use full screen: */
877
878           use_fullscreen = YES;
879         }
880       else if (strcmp(argv[i], "--worldmap") == 0)
881         {
882           launch_worldmap_mode = true;
883         }
884       else if (strcmp(argv[i], "--datadir") == 0 
885                || strcmp(argv[i], "-d") == 0 )
886         {
887           assert(i+1 < argc);
888           datadir = argv[i+1];
889         }
890       else if (strcmp(argv[i], "--show-fps") == 0)
891         {
892           /* Use full screen: */
893
894           show_fps = YES;
895         }
896       else if (strcmp(argv[i], "--opengl") == 0 ||
897                strcmp(argv[i], "-gl") == 0)
898         {
899 #ifndef NOOPENGL
900           /* Use OpengGL: */
901
902           use_gl = YES;
903 #endif
904
905         }
906       else if (strcmp(argv[i], "--usage") == 0)
907         {
908           /* Show usage: */
909
910           usage(argv[0], 0);
911         }
912       else if (strcmp(argv[i], "--version") == 0)
913         {
914           /* Show version: */
915
916           printf("Super Tux - version " VERSION "\n");
917           exit(0);
918         }
919       else if (strcmp(argv[i], "--disable-sound") == 0)
920         {
921           /* Disable the compiled in sound feature */
922 #ifndef NOSOUND
923           printf("Sounds disabled \n");
924           use_sound = NO;
925 #else
926
927           printf("Warning: Sound capability has not been compiled into this build.\n");
928 #endif
929
930         }
931       else if (strcmp(argv[i], "--disable-music") == 0)
932         {
933           /* Disable the compiled in sound feature */
934 #ifndef NOSOUND
935           printf("Music disabled \n");
936           use_music = NO;
937 #else
938
939           printf("Warning: Music feature is not compiled in \n");
940 #endif
941
942         }
943       else if (strcmp(argv[i], "--debug-mode") == 0)
944         {
945           /* Enable the debug-mode */
946           debug_mode = YES;
947
948         }
949       else if (strcmp(argv[i], "--help") == 0)
950         {         /* Show help: */
951           puts("Super Tux " VERSION "\n"
952                "  Please see the file \"README.txt\" for more details.\n");
953           printf("Usage: %s [OPTIONS] FILENAME\n\n", argv[0]);
954           puts("Display Options:\n"
955                "  --fullscreen      Run in fullscreen mode.\n"
956                "  --opengl          If opengl support was compiled in, this will enable\n"
957                "                    the EXPERIMENTAL OpenGL mode.\n"
958                "\n"
959                "Sound Options:\n"
960                "  --disable-sound   If sound support was compiled in,  this will\n"
961                "                    disable sound for this session of the game.\n"
962                "  --disable-music   Like above, but this will disable music.\n"
963                "\n"
964                "Misc Options:\n"
965                "  --worldmap        Start in worldmap-mode (EXPERIMENTAL)\n"          
966                "  -d, --datadir DIR Load Game data from DIR (default: automatic)\n"
967                "  --debug-mode      Enables the debug-mode, which is useful for developers.\n"
968                "  --help            Display a help message summarizing command-line\n"
969                "                    options, license and game controls.\n"
970                "  --usage           Display a brief message summarizing command-line options.\n"
971                "  --version         Display the version of SuperTux you're running.\n\n"
972                );
973           exit(0);
974         }
975       else if (argv[i][0] != '-')
976         {
977           level_startup_file = argv[i];
978         }
979       else
980         {
981           /* Unknown - complain! */
982
983           usage(argv[0], 1);
984         }
985     }
986 }
987
988
989 /* Display usage: */
990
991 void usage(char * prog, int ret)
992 {
993   FILE * fi;
994
995
996   /* Determine which stream to write to: */
997
998   if (ret == 0)
999     fi = stdout;
1000   else
1001     fi = stderr;
1002
1003
1004   /* Display the usage message: */
1005
1006   fprintf(fi, "Usage: %s [--fullscreen] [--opengl] [--disable-sound] [--disable-music] [--debug-mode] | [--usage | --help | --version] [--worldmap] FILENAME\n",
1007           prog);
1008
1009
1010   /* Quit! */
1011
1012   exit(ret);
1013 }
1014