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