3 // SuperTux - A Jump'n Run
4 // Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #include "SDL_image.h"
32 #include "SDL_opengl.h"
36 #include <sys/types.h>
44 #include "../app/globals.h"
45 #include "../app/defines.h"
46 #include "../app/setup.h"
47 #include "../video/screen.h"
48 #include "../video/surface.h"
49 #include "../gui/menu.h"
50 #include "../utils/configfile.h"
51 #include "../audio/sound_manager.h"
52 #include "../app/gettext.h"
54 using namespace SuperTux;
57 #define mkdir(dir, mode) mkdir(dir)
58 // on win32 we typically don't want LFS paths
60 #define DATA_PREFIX "./data/"
63 /* Local function prototypes: */
66 void usage(char * prog, int ret);
68 /* Does the given file exist and is it accessible? */
69 int SuperTux::faccessible(const char *filename)
72 if (stat(filename, &filestat) == -1)
78 if(S_ISREG(filestat.st_mode))
85 /* Can we write to this location? */
86 int SuperTux::fwriteable(const char *filename)
89 fi = fopen(filename, "wa");
97 /* Makes sure a directory is created in either the SuperTux home directory or the SuperTux base directory.*/
98 int SuperTux::fcreatedir(const char* relative_dir)
101 snprintf(path, 1024, "%s/%s/", st_dir, relative_dir);
102 if(mkdir(path,0755) != 0)
104 snprintf(path, 1024, "%s/%s/", datadir.c_str(), relative_dir);
105 if(mkdir(path,0755) != 0)
120 FILE * SuperTux::opendata(const char * rel_filename, const char * mode)
122 char * filename = NULL;
125 filename = (char *) malloc(sizeof(char) * (strlen(st_dir) +
126 strlen(rel_filename) + 1));
128 strcpy(filename, st_dir);
129 /* Open the high score file: */
131 strcat(filename, rel_filename);
133 /* Try opening the file: */
134 fi = fopen(filename, mode);
138 fprintf(stderr, "Warning: Unable to open the file \"%s\" ", filename);
140 if (strcmp(mode, "r") == 0)
141 fprintf(stderr, "for read!!!\n");
142 else if (strcmp(mode, "w") == 0)
143 fprintf(stderr, "for write!!!\n");
150 /* Get all names of sub-directories in a certain directory. */
151 /* Returns the number of sub-directories found. */
152 /* Note: The user has to free the allocated space. */
153 string_list_type SuperTux::dsubdirs(const char *rel_path,const char* expected_file)
156 struct dirent *direntp;
157 string_list_type sdirs;
161 string_list_init(&sdirs);
162 sprintf(path,"%s/%s",st_dir,rel_path);
163 if((dirStructP = opendir(path)) != NULL)
165 while((direntp = readdir(dirStructP)) != NULL)
167 char absolute_filename[1024];
170 sprintf(absolute_filename, "%s/%s", path, direntp->d_name);
172 if (stat(absolute_filename, &buf) == 0 && S_ISDIR(buf.st_mode))
174 if(expected_file != NULL)
176 sprintf(filename,"%s/%s/%s",path,direntp->d_name,expected_file);
177 if(!faccessible(filename))
181 string_list_add_item(&sdirs,direntp->d_name);
184 closedir(dirStructP);
187 sprintf(path,"%s/%s",datadir.c_str(),rel_path);
188 if((dirStructP = opendir(path)) != NULL)
190 while((direntp = readdir(dirStructP)) != NULL)
192 char absolute_filename[1024];
195 sprintf(absolute_filename, "%s/%s", path, direntp->d_name);
197 if (stat(absolute_filename, &buf) == 0 && S_ISDIR(buf.st_mode))
199 if(expected_file != NULL)
201 sprintf(filename,"%s/%s/%s",path,direntp->d_name,expected_file);
202 if(!faccessible(filename))
208 sprintf(filename,"%s/%s/%s/%s",st_dir,rel_path,direntp->d_name,expected_file);
209 if(faccessible(filename))
214 string_list_add_item(&sdirs,direntp->d_name);
217 closedir(dirStructP);
223 string_list_type SuperTux::dfiles(const char *rel_path, const char* glob, const char* exception_str)
226 struct dirent *direntp;
227 string_list_type sdirs;
230 string_list_init(&sdirs);
231 sprintf(path,"%s/%s",st_dir,rel_path);
232 if((dirStructP = opendir(path)) != NULL)
234 while((direntp = readdir(dirStructP)) != NULL)
236 char absolute_filename[1024];
239 sprintf(absolute_filename, "%s/%s", path, direntp->d_name);
241 if (stat(absolute_filename, &buf) == 0 && S_ISREG(buf.st_mode))
243 if(exception_str != NULL)
245 if(strstr(direntp->d_name,exception_str) != NULL)
249 if(strstr(direntp->d_name,glob) == NULL)
252 string_list_add_item(&sdirs,direntp->d_name);
255 closedir(dirStructP);
258 sprintf(path,"%s/%s",datadir.c_str(),rel_path);
259 if((dirStructP = opendir(path)) != NULL)
261 while((direntp = readdir(dirStructP)) != NULL)
263 char absolute_filename[1024];
266 sprintf(absolute_filename, "%s/%s", path, direntp->d_name);
268 if (stat(absolute_filename, &buf) == 0 && S_ISREG(buf.st_mode))
270 if(exception_str != NULL)
272 if(strstr(direntp->d_name,exception_str) != NULL)
276 if(strstr(direntp->d_name,glob) == NULL)
279 string_list_add_item(&sdirs,direntp->d_name);
282 closedir(dirStructP);
288 void SuperTux::free_strings(char **strings, int num)
291 for(i=0; i < num; ++i)
295 void SuperTux::st_info_setup(const std::string& _package_name, const std::string& _package_symbol_name, const std::string& _package_version)
297 package_name = _package_name;
298 package_symbol_name = _package_symbol_name;
299 package_version = _package_version;
303 /* Set SuperTux configuration and save directories */
304 void SuperTux::st_directory_setup(void)
308 /* Get home directory (from $HOME variable)... if we can't determine it,
309 use the current directory ("."): */
310 if (getenv("HOME") != NULL)
311 home = getenv("HOME");
315 std::string st_dir_tmp = "/." + package_symbol_name;
316 st_dir = (char *) malloc(sizeof(char) * (strlen(home) +
317 strlen(st_dir_tmp.c_str()) + 1));
318 strcpy(st_dir, home);
319 strcat(st_dir,st_dir_tmp.c_str());
321 /* Remove .supertux config-file from old SuperTux versions */
322 if(faccessible(st_dir))
328 st_save_dir = (char *) malloc(sizeof(char) * (strlen(st_dir) + strlen("/save") + 1));
330 strcpy(st_save_dir,st_dir);
331 strcat(st_save_dir,"/save");
333 /* Create them. In the case they exist they won't destroy anything. */
335 mkdir(st_save_dir, 0755);
337 sprintf(str, "%s/levels", st_dir);
340 // User has not that a datadir, so we try some magic
345 char exe_file[PATH_MAX];
346 if (readlink("/proc/self/exe", exe_file, PATH_MAX) < 0)
348 puts("Couldn't read /proc/self/exe, using default path: " DATA_PREFIX);
349 datadir = DATA_PREFIX;
353 std::string exedir = std::string(dirname(exe_file)) + "/";
355 datadir = exedir + "../data"; // SuperTux run from source dir
356 if (access(datadir.c_str(), F_OK) != 0)
358 datadir = exedir + "../share/" + package_symbol_name; // SuperTux run from PATH
359 if (access(datadir.c_str(), F_OK) != 0)
360 { // If all fails, fall back to compiled path
361 datadir = DATA_PREFIX;
366 datadir = DATA_PREFIX;
369 printf("Datadir: %s\n", datadir.c_str());
372 void SuperTux::st_general_setup(void)
374 /* Seed random number generator: */
376 srand(SDL_GetTicks());
378 /* Set icon image: */
382 /* Unicode needed for input handling: */
384 SDL_EnableUNICODE(1);
386 /* Load global images: */
387 gold_text = new Font(datadir + "/images/fonts/gold.png", Font::TEXT, 16,18);
388 blue_text = new Font(datadir + "/images/fonts/blue.png", Font::TEXT, 16,18,3);
389 white_text = new Font(datadir + "/images/fonts/white.png",
391 gray_text = new Font(datadir + "/images/fonts/gray.png",
393 white_small_text = new Font(datadir + "/images/fonts/white-small.png",
395 white_big_text = new Font(datadir + "/images/fonts/white-big.png",
396 Font::TEXT, 20,22, 3);
397 yellow_nums = new Font(datadir + "/images/fonts/numbers.png",
400 /* Load GUI/menu images: */
401 checkbox = new Surface(datadir + "/images/status/checkbox.png", true);
402 checkbox_checked = new Surface(datadir + "/images/status/checkbox-checked.png", true);
403 back = new Surface(datadir + "/images/status/back.png", true);
404 arrow_left = new Surface(datadir + "/images/icons/left.png", true);
405 arrow_right = new Surface(datadir + "/images/icons/right.png", true);
407 /* Load the mouse-cursor */
408 mouse_cursor = new MouseCursor( datadir + "/images/status/mousecursor.png",1);
409 MouseCursor::set_current(mouse_cursor);
413 void SuperTux::st_general_free(void)
416 /* Free global images: */
421 delete white_small_text;
422 delete white_big_text;
425 /* Free GUI/menu images: */
427 delete checkbox_checked;
432 /* Free mouse-cursor */
437 void SuperTux::st_video_setup(unsigned int screen_w, unsigned int screen_h)
439 /* Init SDL Video: */
440 if (SDL_Init(SDL_INIT_VIDEO) < 0)
443 "\nError: I could not initialize video!\n"
444 "The Simple DirectMedia error that occured was:\n"
445 "%s\n\n", SDL_GetError());
451 st_video_setup_gl(screen_w, screen_h);
453 st_video_setup_sdl(screen_w, screen_h);
455 Surface::reload_all();
457 /* Set window manager stuff: */
458 SDL_WM_SetCaption((package_name + " " + package_version).c_str(), package_name.c_str());
461 void SuperTux::st_video_setup_sdl(unsigned int screen_w, unsigned int screen_h)
465 screen = SDL_SetVideoMode(screen_w, screen_h, 0, SDL_FULLSCREEN ) ; /* | SDL_HWSURFACE); */
469 "\nWarning: I could not set up fullscreen video for "
471 "The Simple DirectMedia error that occured was:\n"
472 "%s\n\n", SDL_GetError());
473 use_fullscreen = false;
478 screen = SDL_SetVideoMode(screen_w, screen_h, 0, SDL_HWSURFACE | SDL_DOUBLEBUF );
483 "\nError: I could not set up video for 800x600 mode.\n"
484 "The Simple DirectMedia error that occured was:\n"
485 "%s\n\n", SDL_GetError());
491 void SuperTux::st_video_setup_gl(unsigned int screen_w, unsigned int screen_h)
495 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
496 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
497 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
498 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
499 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
503 screen = SDL_SetVideoMode(screen_w, screen_h, 0, SDL_FULLSCREEN | SDL_OPENGL) ; /* | SDL_HWSURFACE); */
507 "\nWarning: I could not set up fullscreen video for "
509 "The Simple DirectMedia error that occured was:\n"
510 "%s\n\n", SDL_GetError());
511 use_fullscreen = false;
516 screen = SDL_SetVideoMode(screen_w, screen_h, 0, SDL_OPENGL);
521 "\nError: I could not set up video for 640x480 mode.\n"
522 "The Simple DirectMedia error that occured was:\n"
523 "%s\n\n", SDL_GetError());
529 * Set up OpenGL for 2D rendering.
531 glDisable(GL_DEPTH_TEST);
532 glDisable(GL_CULL_FACE);
534 glViewport(0, 0, screen->w, screen->h);
535 glMatrixMode(GL_PROJECTION);
537 glOrtho(0, screen->w, screen->h, 0, -1.0, 1.0);
539 glMatrixMode(GL_MODELVIEW);
541 glTranslatef(0.0f, 0.0f, 0.0f);
547 void SuperTux::st_joystick_setup(void)
554 if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
556 fprintf(stderr, "Warning: I could not initialize joystick!\n"
557 "The Simple DirectMedia error that occured was:\n"
558 "%s\n\n", SDL_GetError());
560 use_joystick = false;
565 if (SDL_NumJoysticks() <= 0)
567 fprintf(stderr, "Info: No joysticks were found.\n");
569 use_joystick = false;
573 js = SDL_JoystickOpen(joystick_num);
577 fprintf(stderr, "Warning: Could not open joystick %d.\n"
578 "The Simple DirectMedia error that occured was:\n"
579 "%s\n\n", joystick_num, SDL_GetError());
581 use_joystick = false;
585 if (SDL_JoystickNumAxes(js) < 2)
588 "Warning: Joystick does not have enough axes!\n");
590 use_joystick = false;
594 if (SDL_JoystickNumButtons(js) < 2)
598 "Joystick does not have enough buttons!\n");
600 use_joystick = false;
608 void SuperTux::st_audio_setup(void)
611 /* Init SDL Audio silently even if --disable-sound : */
615 if (SDL_Init(SDL_INIT_AUDIO) < 0)
617 /* only print out message if sound or music
618 was not disabled at command-line
620 if (use_sound || use_music)
623 "\nWarning: I could not initialize audio!\n"
624 "The Simple DirectMedia error that occured was:\n"
625 "%s\n\n", SDL_GetError());
627 /* keep the programming logic the same :-)
628 because in this case, use_sound & use_music' values are ignored
629 when there's no available audio device
633 audio_device = false;
638 /* Open sound silently regarless the value of "use_sound": */
642 if (open_audio(44100, AUDIO_S16, 2, 2048) < 0)
644 /* only print out message if sound or music
645 was not disabled at command-line
647 if (use_sound || use_music)
650 "\nWarning: I could not set up audio for 44100 Hz "
652 "The Simple DirectMedia error that occured was:\n"
653 "%s\n\n", SDL_GetError());
657 audio_device = false;
664 /* --- SHUTDOWN --- */
666 void SuperTux::st_shutdown(void)
675 void SuperTux::st_abort(const std::string& reason, const std::string& details)
677 fprintf(stderr, "\nError: %s\n%s\n\n", reason.c_str(), details.c_str());
682 /* Set Icon (private) */
691 /* Load icon into a surface: */
693 icon = IMG_Load((datadir + "/images/" + package_symbol_name + ".xpm").c_str());
697 "\nError: I could not load the icon image: %s%s\n"
698 "The Simple DirectMedia error that occured was:\n"
699 "%s\n\n", datadir.c_str(), ("/images/" + package_symbol_name + ".xpm").c_str(), SDL_GetError());
706 masklen = (((icon -> w) + 7) / 8) * (icon -> h);
707 mask = (Uint8*) malloc(masklen * sizeof(Uint8));
708 memset(mask, 0xFF, masklen);
713 SDL_WM_SetIcon(icon, NULL);//mask);
716 /* Free icon surface & mask: */
719 SDL_FreeSurface(icon);
723 /* Parse command-line arguments: */
725 void SuperTux::parseargs(int argc, char * argv[])
731 /* Parse arguments: */
733 for (i = 1; i < argc; i++)
735 if (strcmp(argv[i], "--fullscreen") == 0 ||
736 strcmp(argv[i], "-f") == 0)
738 use_fullscreen = true;
740 else if (strcmp(argv[i], "--window") == 0 ||
741 strcmp(argv[i], "-w") == 0)
743 use_fullscreen = false;
745 else if (strcmp(argv[i], "--joystick") == 0 || strcmp(argv[i], "-j") == 0)
748 joystick_num = atoi(argv[++i]);
750 else if (strcmp(argv[i], "--joymap") == 0)
753 if (sscanf(argv[++i],
755 &joystick_keymap.x_axis,
756 &joystick_keymap.y_axis,
757 &joystick_keymap.a_button,
758 &joystick_keymap.b_button,
759 &joystick_keymap.start_button) != 5)
761 puts("Warning: Invalid or incomplete joymap, should be: 'XAXIS:YAXIS:A:B:START'");
765 std::cout << "Using new joymap:\n"
766 << " X-Axis: " << joystick_keymap.x_axis << "\n"
767 << " Y-Axis: " << joystick_keymap.y_axis << "\n"
768 << " A-Button: " << joystick_keymap.a_button << "\n"
769 << " B-Button: " << joystick_keymap.b_button << "\n"
770 << " Start-Button: " << joystick_keymap.start_button << std::endl;
773 else if (strcmp(argv[i], "--leveleditor") == 0)
775 launch_leveleditor_mode = true;
777 else if (strcmp(argv[i], "--worldmap") == 0)
779 launch_worldmap_mode = true;
781 else if (strcmp(argv[i], "--datadir") == 0
782 || strcmp(argv[i], "-d") == 0 )
787 else if (strcmp(argv[i], "--show-fps") == 0)
789 /* Use full screen: */
793 else if (strcmp(argv[i], "--opengl") == 0 ||
794 strcmp(argv[i], "-gl") == 0)
802 else if (strcmp(argv[i], "--sdl") == 0)
806 else if (strcmp(argv[i], "--usage") == 0)
812 else if (strcmp(argv[i], "--version") == 0)
815 printf((package_name + package_version + "\n").c_str() );
818 else if (strcmp(argv[i], "--disable-sound") == 0)
820 /* Disable the compiled in sound feature */
821 printf("Sounds disabled \n");
823 audio_device = false;
825 else if (strcmp(argv[i], "--disable-music") == 0)
827 /* Disable the compiled in sound feature */
828 printf("Music disabled \n");
831 else if (strcmp(argv[i], "--debug") == 0)
833 /* Enable the debug-mode */
837 else if (strcmp(argv[i], "--help") == 0)
839 puts(_(" SuperTux " VERSION "\n"
840 " Please see the file \"README.txt\" for more details.\n"));
841 printf(_("Usage: %s [OPTIONS] FILENAME\n\n"), argv[0]);
842 puts(_("Display Options:\n"
843 " -f, --fullscreen Run in fullscreen mode.\n"
844 " -w, --window Run in window mode.\n"
845 " --opengl If OpenGL support was compiled in, this will tell\n"
846 " SuperTux to make use of it.\n"
847 " --sdl Use the SDL software graphical renderer\n"
850 " --disable-sound If sound support was compiled in, this will\n"
851 " disable sound for this session of the game.\n"
852 " --disable-music Like above, but this will disable music.\n"
855 " -j, --joystick NUM Use joystick NUM (default: 0)\n"
856 " --joymap XAXIS:YAXIS:A:B:START\n"
857 " Define how joystick buttons and axis should be mapped\n"
858 " --leveleditor Opens the leveleditor in a file.\n"
859 " --worldmap Opens the specified worldmap file.\n"
860 " -d, --datadir DIR Load Game data from DIR (default: automatic)\n"
861 " --debug Enables the debug mode, which is useful for developers.\n"
862 " --help Display a help message summarizing command-line\n"
863 " options, license and game controls.\n"
864 " --usage Display a brief message summarizing command-line options.\n"
865 " --version Display the version of SuperTux you're running.\n\n"
869 else if (argv[i][0] != '-')
871 level_startup_file = argv[i];
875 /* Unknown - complain! */
885 void usage(char * prog, int ret)
890 /* Determine which stream to write to: */
898 /* Display the usage message: */
900 fprintf(fi, _("Usage: %s [--fullscreen] [--opengl] [--disable-sound] [--disable-music] [--debug] | [--usage | --help | --version] [--leveleditor] [--worldmap] FILENAME\n"),
909 std::vector<std::string> SuperTux::read_directory(const std::string& pathname)
911 std::vector<std::string> dirnames;
913 DIR* dir = opendir(pathname.c_str());
916 struct dirent *direntp;
918 while((direntp = readdir(dir)))
920 dirnames.push_back(direntp->d_name);