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