From: Matthias Braun Date: Tue, 7 Jun 2005 15:59:27 +0000 (+0000) Subject: supertux is using physfs now, this simplifies the code and generalises file handling X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=7ae3aef67ad305cb9c6ed584cdac6117da9eba88;p=supertux.git supertux is using physfs now, this simplifies the code and generalises file handling SVN-Revision: 2575 --- diff --git a/configure.ac b/configure.ac index c2dc0e8cd..a504fd255 100644 --- a/configure.ac +++ b/configure.ac @@ -97,6 +97,18 @@ AM_ICONV AC_SUBST([ICONV_LIBS], [$LIBICONV]) dnl =========================================================================== +dnl Check for OpenGL +if test "$enable_opengl" = "yes"; then + AX_CHECK_GL +fi +if test "$no_gl" = "yes" -o "$enable_opengl" = "no"; then + GL_AVAILABLE="no" + AC_DEFINE([NOOPENGL],, [Define if opengl should not be used]) +else + GL_AVAILABLE="yes" +fi +AC_SUBST([GL_AVAILABLE]) + dnl Check for SDL SDL_VERSION=1.2.4 AM_PATH_SDL($SDL_VERSION, @@ -126,16 +138,14 @@ NP_FINDLIB([SDLIMAGE], [SDL_image], [SDL_image >= 1.2], [AC_MSG_ERROR([Please install SDLImage >= 1.2.1])], [$SDL_CFLAGS], [$SDL_LIBS]) -if test "$enable_opengl" = "yes"; then - AX_CHECK_GL -fi -if test "$no_gl" = "yes" -o "$enable_opengl" = "no"; then - GL_AVAILABLE="no" - AC_DEFINE([NOOPENGL],, [Define if opengl should not be used]) -else - GL_AVAILABLE="yes" -fi -AC_SUBST([GL_AVAILABLE]) +NP_FINDLIB([PHYSFS], [physfs], [physfs >= 1.0.0], + NP_LANG_PROGRAM([#include +#if PHYSFS_VER_MAJOR < 1 +# error PHYSFS is too old +#endif]), + [], [-lphysfs], + [], + [AC_MSG_ERROR([Please install physfs >= 1.0])]) dnl Checks for library functions. AC_CHECK_FUNCS(mkdir strdup strstr) diff --git a/data/levels/test/script.stl b/data/levels/test/script.stl index fad86a352..2f9bd8414 100644 --- a/data/levels/test/script.stl +++ b/data/levels/test/script.stl @@ -138,10 +138,6 @@ (solid #f) ) (init-script " -function wait(time) { - set_wakeup_time(time); - suspend(); -} Text.set_text(translate(\"The Crazy Nolok Dance\")); Text.fade_in(2); TUX.set_animation(\"jump\"); diff --git a/mk/jam/np_findlib.m4 b/mk/jam/np_findlib.m4 new file mode 100644 index 000000000..f2c2d2fdc --- /dev/null +++ b/mk/jam/np_findlib.m4 @@ -0,0 +1,51 @@ +# NP_FINDLIB(VARNAME, NAME, STRING, TESTAPP, CFLAGS, LIBS, ACTION_IF_FOUND, +# ACTION_IF_NOT_FOUND, EXTRACFLAGS, EXTRALIBS) +AC_DEFUN([NP_FINDLIB], [ + AC_ARG_WITH([lib$2], [AC_HELP_STRING([--with-lib$2=dir], + [specify location of lib$2 if not detected automatically; uses + dir, dir/include and dir/lib])]) + + save_CFLAGS="$CFLAGS" + save_CPPFLAGS="$CPPFLAGS" + save_LIBS="$LIBS" + + RESCFLAGS="$5" + RESLIBS="$6" + CFLAGS="$CFLAGS $5 $9" + CPPFLAGS="$CPPFLAGS $5 $9" + LIBS="$LIBS $6 $10" + + AS_IF([test -n "$with_lib$2"], [ + CFLAGS="-I$with_lib$2/include $CFLAGS" + CPPFLAGS="-I$with_lib$2/include $CPPFLAGS" + LIBS="-L$with_lib$2/lib $LIBS" + RESCFLAGS="-I$with_lib$2/include $RESCFLAGS" + RESLIBS="-L$with_lib$2/lib $RESLIBS" + ]) + + AC_MSG_CHECKING([for $3]) + + AC_LINK_IFELSE([$4], [buildok=yes], [buildok=no]) + + LIBS=$save_LIBS + CPPFLAGS=$save_CPPFLAGS + CFLAGS=$save_CFLAGS + + AS_IF([test $buildok = yes], + [AC_MSG_RESULT([found]) + $1_AVAILABLE=yes + $1_CFLAGS="$RESCFLAGS" + $1_LIBS="$RESLIBS"], + [AC_MSG_RESULT([not found]) + $1_AVAILABLE=no + $1_CFLAGS="" + $1_LIBS=""]) + + AC_SUBST([$1_AVAILABLE]) + AC_SUBST([$1_CFLAGS]) + AC_SUBST([$1_LIBS]) + + AS_IF([test $buildok = yes], + [ifelse([$7], , :, [$7])], + [ifelse([$8], , :, [$8])]) +]) diff --git a/mk/jam/np_lang_program.m4 b/mk/jam/np_lang_program.m4 new file mode 100644 index 000000000..e6559d531 --- /dev/null +++ b/mk/jam/np_lang_program.m4 @@ -0,0 +1,13 @@ +# NP_LANG_PROGRAM, custom version of AC_LANG_PROGRAM (because SDL on win32 +# NEEDS main(int argc, char** argv) +AC_DEFUN([NP_LANG_PROGRAM], +[$1 +m4_ifdef([_AC_LANG_PROGRAM_C_F77_HOOKS], [_AC_LANG_PROGRAM_C_F77_HOOKS])[]dnl +int +main(int argc, char** argv) +{ +$2 + ; + return 0; +} +]) diff --git a/src/Jamfile b/src/Jamfile index aeb443c53..ba6b3759c 100644 --- a/src/Jamfile +++ b/src/Jamfile @@ -5,24 +5,25 @@ SubInclude TOP src scripting ; sources = [ Wildcard *.cpp *.h ] - [ Wildcard math : *.cpp *.h ] - [ Wildcard video : *.cpp *.h ] [ Wildcard audio : *.cpp *.h ] + [ Wildcard badguy : *.cpp *.h ] + [ Wildcard control : *.cpp *.h ] [ Wildcard gui : *.cpp *.h ] [ Wildcard lisp : *.cpp *.h ] + [ Wildcard math : *.cpp *.h ] [ Wildcard object : *.cpp *.h ] - [ Wildcard badguy : *.cpp *.h ] + [ Wildcard physfs : *.cpp *.h ] [ Wildcard sprite : *.cpp *.h ] - [ Wildcard trigger : *.cpp *.h ] [ Wildcard tinygettext : *.cpp *.h ] - [ Wildcard control : *.cpp *.h ] + [ Wildcard trigger : *.cpp *.h ] + [ Wildcard video : *.cpp *.h ] ; TRANSLATABLE_SOURCES += [ SearchSource $(sources) ] ; Application supertux : $(sources) $(wrapper_objects) ; -C++Flags supertux : -DDATA_PREFIX='\"$(appdatadir)\"' ; +C++Flags supertux : -DAPPDATADIR='\"$(appdatadir)\"' ; LinkWith supertux : squirrel ; -ExternalLibs supertux : SDL SDLMIXER SDLIMAGE GL ICONV ; +ExternalLibs supertux : SDL SDLMIXER SDLIMAGE GL ICONV PHYSFS BINRELOC ; Help supertux : "Build the supertux executable" ; IncludeDir supertux : squirrel/include ; diff --git a/src/audio/sound_manager.cpp b/src/audio/sound_manager.cpp index 329190eee..bb26ed2e7 100644 --- a/src/audio/sound_manager.cpp +++ b/src/audio/sound_manager.cpp @@ -23,10 +23,12 @@ #include #include #include +#include #include "audio/sound_manager.h" #include "audio/musicref.h" +#include "physfs/physfs_sdl.h" #include "moving_object.h" #include "resources.h" @@ -122,25 +124,28 @@ SoundManager::load_music(const std::string& file) } bool -SoundManager::exists_music(const std::string& file) +SoundManager::exists_music(const std::string& filename) { if(!audio_device) return true; // song already loaded? - std::map::iterator i = musics.find(file); + std::map::iterator i = musics.find(filename); if(i != musics.end()) { return true; } - - Mix_Music* song = Mix_LoadMUS(file.c_str()); + + const char* dir = PHYSFS_getRealDir(filename.c_str()); + if(dir == 0) + return false; + Mix_Music* song = Mix_LoadMUS( (std::string(dir) + "/" + filename).c_str() ); if(song == 0) return false; // insert into music list std::pair::iterator, bool> result = musics.insert( - std::make_pair (file, MusicResource())); + std::make_pair (filename, MusicResource())); MusicResource& resource = result.first->second; resource.manager = this; resource.music = song; @@ -236,9 +241,8 @@ Mix_Chunk* SoundManager::preload_sound(const std::string& name) std::string filename = "sounds/"; filename += name; filename += ".wav"; - filename = get_resource_filename(filename); - Mix_Chunk* chunk = Mix_LoadWAV(filename.c_str()); + Mix_Chunk* chunk = Mix_LoadWAV_RW(get_physfs_SDLRWops(filename), true); if(chunk != 0) { sounds.insert(std::make_pair(name, chunk)); } diff --git a/src/file_system.cpp b/src/file_system.cpp index af243f837..8d8b811b0 100644 --- a/src/file_system.cpp +++ b/src/file_system.cpp @@ -1,194 +1,12 @@ #include #include "file_system.h" -#include -#include -#include -#ifndef WIN32 -#include -#endif -#include "resources.h" - -#ifdef WIN32 -#define mkdir(dir, mode) mkdir(dir) -#endif +#include namespace FileSystem { -/* Does the given file exist and is it accessible? */ -bool faccessible(const std::string& filename) -{ - FILE* f = fopen(filename.c_str(), "r"); - if(f == 0) - return false; - - fclose(f); - return true; -} - -/* Can we write to this location? */ -bool fwriteable(const std::string& filename) -{ - FILE* f = fopen(filename.c_str(), "wa"); - if (f == 0) - return false; - - fclose(f); - return true; -} - -/* Makes sure a directory is created in either the SuperTux home directory or the SuperTux base directory.*/ -bool fcreatedir(const std::string& relative_dir) -{ - std::string path = user_dir + "/" + relative_dir + "/"; - if(mkdir(path.c_str(),0755) == 0) - return true; - - path = datadir + "/" + relative_dir + "/"; - if(mkdir(path.c_str(),0755) == 0) - return true; - - return false; -} - -/* Get all names of sub-directories in a certain directory. */ -/* Returns the number of sub-directories found. */ -/* Note: The user has to free the allocated space. */ -std::set dsubdirs(const std::string &rel_path, - const std::string& expected_file) -{ - DIR *dirStructP; - struct dirent *direntp; - std::set sdirs; - std::string filename; - std::string path = user_dir + "/" + rel_path; - - if((dirStructP = opendir(path.c_str())) != NULL) - { - while((direntp = readdir(dirStructP)) != NULL) - { - std::string absolute_filename; - struct stat buf; - - absolute_filename = path + "/" + direntp->d_name; - - if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode)) - { - if(!expected_file.empty()) - { - filename = path + "/" + direntp->d_name + "/" + expected_file; - if(!faccessible(filename)) - continue; - } - - sdirs.insert(direntp->d_name); - } - } - closedir(dirStructP); - } - - path = datadir + "/" + rel_path; - if((dirStructP = opendir(path.c_str())) != NULL) - { - while((direntp = readdir(dirStructP)) != NULL) - { - std::string absolute_filename; - struct stat buf; - - absolute_filename = path + "/" + direntp->d_name; - - if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode)) - { - if(!expected_file.empty()) - { - filename = path + "/" + direntp->d_name + "/" + expected_file; - if(!faccessible(filename.c_str())) - { - continue; - } - else - { - filename = user_dir + "/" + rel_path + "/" + direntp->d_name + "/" + expected_file; - if(faccessible(filename.c_str())) - continue; - } - } - - sdirs.insert(direntp->d_name); - } - } - closedir(dirStructP); - } - - return sdirs; -} - -std::set dfiles(const std::string& rel_path, - const std::string& glob, const std::string& exception_str) -{ - DIR *dirStructP; - struct dirent *direntp; - std::set sdirs; - std::string path = user_dir + "/" + rel_path; - - if((dirStructP = opendir(path.c_str())) != NULL) - { - while((direntp = readdir(dirStructP)) != NULL) - { - std::string absolute_filename; - struct stat buf; - - absolute_filename = path + "/" + direntp->d_name; - - if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISREG(buf.st_mode)) - { - if(!exception_str.empty()) - { - if(strstr(direntp->d_name,exception_str.c_str()) != NULL) - continue; - } - if(!glob.empty()) - if(strstr(direntp->d_name,glob.c_str()) == NULL) - continue; - - sdirs.insert(direntp->d_name); - } - } - closedir(dirStructP); - } - - path = datadir + "/" + rel_path; - if((dirStructP = opendir(path.c_str())) != NULL) - { - while((direntp = readdir(dirStructP)) != NULL) - { - std::string absolute_filename; - struct stat buf; - - absolute_filename = path + "/" + direntp->d_name; - - if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISREG(buf.st_mode)) - { - if(!exception_str.empty()) - { - if(strstr(direntp->d_name,exception_str.c_str()) != NULL) - continue; - } - if(!glob.empty()) - if(strstr(direntp->d_name,glob.c_str()) == NULL) - continue; - - sdirs.insert(direntp->d_name); - } - } - closedir(dirStructP); - } - - return sdirs; -} - std::string dirname(const std::string& filename) { std::string::size_type p = filename.find_last_of('/'); @@ -198,24 +16,13 @@ std::string dirname(const std::string& filename) return filename.substr(0, p+1); } -std::set read_directory(const std::string& pathname) +std::string basename(const std::string& filename) { - std::set dirnames; - - DIR* dir = opendir(pathname.c_str()); - if (dir) - { - struct dirent *direntp; - - while((direntp = readdir(dir))) - { - dirnames.insert(direntp->d_name); - } - - closedir(dir); - } + std::string::size_type p = filename.find_last_of('/'); + if(p == std::string::npos) + return filename; - return dirnames; + return filename.substr(p, filename.size()-p); } } diff --git a/src/file_system.h b/src/file_system.h index 341e1fcfc..47f86f4a3 100644 --- a/src/file_system.h +++ b/src/file_system.h @@ -6,15 +6,8 @@ namespace FileSystem { - bool faccessible(const std::string& filename); - bool fcreatedir(const std::string& relative_dir); - bool fwriteable(const std::string& filename); - std::set read_directory(const std::string& pathname); - std::set dsubdirs(const std::string& rel_path, - const std::string& expected_file); - std::set dfiles(const std::string& rel_path, - const std::string& glob, const std::string& exception_str); std::string dirname(const std::string& filename); + std::string basename(const std::string& filename); } #endif diff --git a/src/game_session.cpp b/src/game_session.cpp index 2928ed156..4f5495c50 100644 --- a/src/game_session.cpp +++ b/src/game_session.cpp @@ -765,7 +765,7 @@ std::string slotinfo(int slot) std::string title; std::stringstream stream; stream << slot; - slotfile = user_dir + "/save/slot" + stream.str() + ".stsg"; + slotfile = "save/slot" + stream.str() + ".stsg"; try { lisp::Parser parser; @@ -796,7 +796,7 @@ bool process_load_game_menu() std::stringstream stream; stream << slot; - std::string slotfile = user_dir + "/save/slot" + stream.str() + ".stsg"; + std::string slotfile = "save/slot" + stream.str() + ".stsg"; fadeout(256); DrawingContext context; diff --git a/src/gameconfig.cpp b/src/gameconfig.cpp index 2387c8cf8..94fa2acae 100644 --- a/src/gameconfig.cpp +++ b/src/gameconfig.cpp @@ -61,7 +61,7 @@ void Config::load() { lisp::Parser parser; - std::auto_ptr root (parser.parse(user_dir + "/config")); + std::auto_ptr root (parser.parse("config")); const lisp::Lisp* config_lisp = root->get_lisp("supertux-config"); if(!config_lisp) @@ -96,14 +96,7 @@ Config::load() void Config::save() { - std::string configfile = user_dir + "/config"; - std::ofstream file( (user_dir + "/config").c_str() ); - if(!file.good()) { - std::stringstream msg; - msg << "Couldn't write config file '" << configfile << "'"; - throw std::runtime_error(msg.str()); - } - lisp::Writer writer(file); + lisp::Writer writer("config"); writer.start_list("supertux-config"); diff --git a/src/level.cpp b/src/level.cpp index e9f8ccd53..d6cd3c753 100644 --- a/src/level.cpp +++ b/src/level.cpp @@ -70,13 +70,6 @@ Level::load(const std::string& filepath) level->get("version", version); if(version == 1) { load_old_format(*level); - -#if 0 - // test for now - FlipLevelTransformer* transformer = new FlipLevelTransformer(); - transformer->transform(this); -#endif - return; } @@ -123,12 +116,7 @@ Level::load_old_format(const lisp::Lisp& reader) void Level::save(const std::string& filename) { - std::string filepath = "levels/" + filename; - int last_slash = filepath.find_last_of('/'); - FileSystem::fcreatedir(filepath.substr(0,last_slash).c_str()); - filepath = user_dir + "/" + filepath; - ofstream file(filepath.c_str(), ios::out); - lisp::Writer* writer = new lisp::Writer(file); + lisp::Writer* writer = new lisp::Writer(filename); writer->write_comment("Level made using SuperTux's built-in Level Editor"); @@ -150,7 +138,6 @@ Level::save(const std::string& filename) writer->end_list("supertux-level"); delete writer; - file.close(); } Level::~Level() diff --git a/src/level_subset.cpp b/src/level_subset.cpp index 2366f8cf1..960f7dcfa 100644 --- a/src/level_subset.cpp +++ b/src/level_subset.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "level.h" #include "resources.h" #include "file_system.h" @@ -30,6 +31,7 @@ #include "level_subset.h" #include "lisp/parser.h" #include "lisp/lisp.h" +#include "lisp/writer.h" static bool has_suffix(const std::string& data, const std::string& suffix) { @@ -80,90 +82,55 @@ void LevelSubset::load(const std::string& subset) { name = subset; - // Check in which directory our subset is located (ie. ~/.supertux/ - // or SUPERTUX_DATADIR) - std::string filename = get_resource_filename( - std::string("levels/") + subset + "/info"); - if(filename == "") { - std::stringstream msg; - msg << "Couldn't find level subset '" << subset << "'."; - throw new std::runtime_error(msg.str()); - } - + std::string infofile = subset + "/info"; try { - read_info_file(filename); + read_info_file(infofile); } catch(std::exception& e) { std::stringstream msg; - msg << "Couldn't parse info file '" << filename << "': " << e.what(); - throw new std::runtime_error(msg.str()); + msg << "Couldn't parse info file '" << infofile << "': " << e.what(); + throw std::runtime_error(msg.str()); } // test is a worldmap exists has_worldmap = false; - std::string worldmap = get_resource_filename( - std::string("levels/") + subset + "/worldmap.stwm"); - if(worldmap != "") { + std::string worldmap = subset + "/worldmap.stwm"; + if(PHYSFS_exists(worldmap.c_str())) { has_worldmap = true; } - if (levels.empty()) - { // Level info file doesn't define any levels, so read the - // directory to see what we can find - std::set files; - - filename = datadir + "/levels/" + subset + "/"; - files = FileSystem::read_directory(filename); + if (levels.empty()) { + // Level info file doesn't define any levels, so read the + // directory to see what we can find + + std::string path = subset + "/"; + char** files = PHYSFS_enumerateFiles(path.c_str()); + if(!files) { + std::cerr << "Warning: Couldn't read subset dir '" + << path << "'.\n"; + return; + } - filename = user_dir + "/levels/" + subset + "/"; - std::set user_files = FileSystem::read_directory(filename); - files.insert(user_files.begin(), user_files.end()); - - for(std::set::iterator i = files.begin(); i != files.end(); ++i) - { - if (has_suffix(*i, ".stl")) - levels.push_back(get_resource_filename( - std::string("levels/" + subset+ "/" + *i))); - } + for(const char* const* filename = files; *filename != 0; ++filename) { + if(has_suffix(*filename, ".stl")) { + levels.push_back(path + *filename); + } } + PHYSFS_freeList(files); + } } void LevelSubset::save() { - FILE* fi; - std::string filename; - /* Save data file: */ - filename = "/levels/" + name + "/"; - - FileSystem::fcreatedir(filename.c_str()); - filename = std::string(user_dir) + "/levels/" + name + "/info"; - if(!FileSystem::fwriteable(filename.c_str())) - filename = datadir + "/levels/" + name + "/info"; - if(FileSystem::fwriteable(filename.c_str())) - { - fi = fopen(filename.c_str(), "w"); - if (fi == NULL) - { - perror(filename.c_str()); - } - - /* Write header: */ - fprintf(fi,";; SuperTux-Level-Subset\n"); - fprintf(fi,"(supertux-level-subset\n"); - - /* Save title info: */ - fprintf(fi," (title \"%s\")\n", title.c_str()); - - /* Save the description: */ - fprintf(fi," (description \"%s\")\n", description.c_str()); - - /* Save the hide from Contrbis menu boolean: */ - fprintf(fi," (hide-from-contribs %s)\n", hide_from_contribs ? "#t" : "#f"); - - fprintf( fi,")"); - fclose(fi); - } + std::string filename = name + "/info"; + lisp::Writer writer(filename); + + writer.start_list("supertux-level-subset"); + writer.write_string("title", title); + writer.write_string("description", description); + writer.write_bool("hide-from-contribs", hide_from_contribs); + writer.end_list("supertux-level-subset"); } void @@ -182,7 +149,7 @@ LevelSubset::get_level_filename(unsigned int num) std::string LevelSubset::get_worldmap_filename() { - return std::string("/levels/" + name + "/worldmap.stwm"); + return std::string(name + "/worldmap.stwm"); } int diff --git a/src/lisp/list_iterator.cpp b/src/lisp/list_iterator.cpp index 1850113b8..e03e0caec 100644 --- a/src/lisp/list_iterator.cpp +++ b/src/lisp/list_iterator.cpp @@ -39,12 +39,12 @@ ListIterator::next() const lisp::Lisp* child = cur->get_car(); if(!child) - throw new std::runtime_error("child is 0 in list entry"); + throw std::runtime_error("child is 0 in list entry"); if(child->get_type() != lisp::Lisp::TYPE_CONS) - throw new std::runtime_error("Expected CONS"); + throw std::runtime_error("Expected CONS"); const lisp::Lisp* name = child->get_car(); if(!name || name->get_type() != lisp::Lisp::TYPE_SYMBOL) - throw new std::runtime_error("Expected symbol"); + throw std::runtime_error("Expected symbol"); name->get(current_item); current_lisp = child->get_cdr(); diff --git a/src/lisp/parser.cpp b/src/lisp/parser.cpp index 224ee3eb1..565dcc989 100644 --- a/src/lisp/parser.cpp +++ b/src/lisp/parser.cpp @@ -26,6 +26,8 @@ #include #include "tinygettext/tinygettext.h" +#include "physfs/physfs_stream.h" +#include "resources.h" #include "parser.h" #include "lisp.h" #include "file_system.h" @@ -51,7 +53,7 @@ Parser::~Parser() Lisp* Parser::parse(const std::string& filename) { - std::ifstream in(filename.c_str()); + IFileStream in(filename); if(!in.good()) { std::stringstream msg; msg << "Parser problem: Couldn't open file '" << filename << "'."; @@ -115,7 +117,7 @@ Parser::read() // evaluate translation function (_ str) in place here token = lexer->getNextToken(); if(token != Lexer::TOKEN_STRING) - throw new std::runtime_error("Expected string after '(_'"); + throw std::runtime_error("Expected string after '(_'"); result = new Lisp(Lisp::TYPE_STRING); if(dictionary) { @@ -129,7 +131,7 @@ Parser::read() } token = lexer->getNextToken(); if(token != Lexer::TOKEN_CLOSE_PAREN) - throw new std::runtime_error("Expected ')' after '(_ string'"); + throw std::runtime_error("Expected ')' after '(_ string'"); break; } diff --git a/src/lisp/writer.cpp b/src/lisp/writer.cpp index e4a810af3..ff70ce1ad 100644 --- a/src/lisp/writer.cpp +++ b/src/lisp/writer.cpp @@ -22,13 +22,23 @@ #include #include "writer.h" +#include "physfs/physfs_stream.h" namespace lisp { -Writer::Writer(std::ostream& newout) - : out(newout), indent_depth(0) +Writer::Writer(const std::string& filename) { + out = new OFileStream(filename); + out_owned = true; + indent_depth = 0; +} + +Writer::Writer(std::ostream* newout) +{ + out = newout; + out_owned = false; + indent_depth = 0; } Writer::~Writer() @@ -36,19 +46,21 @@ Writer::~Writer() if(lists.size() > 0) { std::cerr << "Warning: Not all sections closed in lispwriter!\n"; } + if(out_owned) + delete out; } void Writer::write_comment(const std::string& comment) { - out << "; " << comment << "\n"; + *out << "; " << comment << "\n"; } void Writer::start_list(const std::string& listname) { indent(); - out << '(' << listname << '\n'; + *out << '(' << listname << '\n'; indent_depth += 2; lists.push_back(listname); @@ -71,21 +83,21 @@ Writer::end_list(const std::string& listname) indent_depth -= 2; indent(); - out << ")\n"; + *out << ")\n"; } void Writer::write_int(const std::string& name, int value) { indent(); - out << '(' << name << ' ' << value << ")\n"; + *out << '(' << name << ' ' << value << ")\n"; } void Writer::write_float(const std::string& name, float value) { indent(); - out << '(' << name << ' ' << value << ")\n"; + *out << '(' << name << ' ' << value << ")\n"; } void @@ -93,11 +105,11 @@ Writer::write_string(const std::string& name, const std::string& value, bool translatable) { indent(); - out << '(' << name; + *out << '(' << name; if(translatable) { - out << " (_ \"" << value << "\"))\n"; + *out << " (_ \"" << value << "\"))\n"; } else { - out << " \"" << value << "\")\n"; + *out << " \"" << value << "\")\n"; } } @@ -105,7 +117,7 @@ void Writer::write_bool(const std::string& name, bool value) { indent(); - out << '(' << name << ' ' << (value ? "#t" : "#f") << ")\n"; + *out << '(' << name << ' ' << (value ? "#t" : "#f") << ")\n"; } void @@ -113,10 +125,10 @@ Writer::write_int_vector(const std::string& name, const std::vector& value) { indent(); - out << '(' << name; + *out << '(' << name; for(std::vector::const_iterator i = value.begin(); i != value.end(); ++i) - out << " " << *i; - out << ")\n"; + *out << " " << *i; + *out << ")\n"; } void @@ -124,17 +136,17 @@ Writer::write_int_vector(const std::string& name, const std::vector& value) { indent(); - out << '(' << name; + *out << '(' << name; for(std::vector::const_iterator i = value.begin(); i != value.end(); ++i) - out << " " << *i; - out << ")\n"; + *out << " " << *i; + *out << ")\n"; } void Writer::indent() { for(int i = 0; i& value); - void write_int_vector(const std::string& name, const std::vector& value); - // add more write-functions when needed... + void write_int(const std::string& name, int value); + void write_float(const std::string& name, float value); + void write_string(const std::string& name, const std::string& value, + bool translatable = false); + void write_bool(const std::string& name, bool value); + void write_int_vector(const std::string& name, const std::vector& value); + void write_int_vector(const std::string& name, const std::vector& value); + // add more write-functions when needed... - void end_list(const std::string& listname); + void end_list(const std::string& listname); - private: - void indent(); - - std::ostream& out; - int indent_depth; - std::vector lists; - }; + private: + void indent(); + std::ostream* out; + bool out_owned; + int indent_depth; + std::vector lists; + }; + } //namespace lisp #endif //SUPERTUX_LISPWRITER_H diff --git a/src/main.cpp b/src/main.cpp index 950da90dc..acf4465ea 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -32,9 +32,7 @@ #include #include #include -#ifndef WIN32 -#include -#endif +#include #include #include #include @@ -50,10 +48,7 @@ #include "title.h" #include "game_session.h" #include "file_system.h" - -#ifdef WIN32 -#define mkdir(dir, mode) mkdir(dir) -#endif +#include "physfs/physfs_sdl.h" SDL_Surface* screen = 0; JoystickKeyboardController* main_controller = 0; @@ -71,73 +66,110 @@ static void init_config() } } -static void find_directories() +static void init_tinygettext() { - const char* home = getenv("HOME"); - if(home == 0) { -#ifdef DEBUG - std::cerr << "Couldn't find home directory.\n"; -#endif - home = "."; - } - - user_dir = home; - user_dir += "/.supertux"; - - // create directories - std::string savedir = user_dir + "/save"; - mkdir(user_dir.c_str(), 0755); - mkdir(savedir.c_str(), 0755); + dictionary_manager.add_directory("locale"); + dictionary_manager.set_charset("UTF-8"); +} - // try current directory as datadir - if(datadir.empty()) { - if(FileSystem::faccessible("./data/credits.txt")) { - datadir = "./data/"; - } +static void init_physfs(const char* argv0) +{ + if(!PHYSFS_init(argv0)) { + std::stringstream msg; + msg << "Couldn't initialize physfs: " << PHYSFS_getLastError(); + throw std::runtime_error(msg.str()); } - // Detect datadir with some linux magic - if(datadir.empty()) { - std::string exedir; -#ifdef WIN32 - exedir = "."; -#else - char exe_file[PATH_MAX]; - if(readlink("/proc/self/exe", exe_file, PATH_MAX) >= 0) { - exedir = std::string(dirname(exe_file)); - } else { -#ifdef DEBUG - std::cerr << "Couldn't read /proc/self/exe \n"; -#endif - exedir = "."; - } -#endif - std::string testdir = exedir + "/data/"; - if(access(testdir.c_str(), F_OK) == 0) { - datadir = testdir; + // Initialize physfs (this is a slightly modified version of + // PHYSFS_setSaneConfig + const char* application = PACKAGE_NAME; + const char* userdir = PHYSFS_getUserDir(); + const char* dirsep = PHYSFS_getDirSeparator(); + char* writedir = new char[strlen(userdir) + strlen(application) + 2]; + + // Set configuration directory + sprintf(writedir, "%s.%s", userdir, application); + if(!PHYSFS_setWriteDir(writedir)) { + // try to create the directory + char* mkdir = new char[strlen(application) + 2]; + sprintf(mkdir, ".%s", application); + if(!PHYSFS_setWriteDir(userdir) || !PHYSFS_mkdir(mkdir)) { + std::ostringstream msg; + msg << "Failed creating configuration directory '" + << writedir << "': " << PHYSFS_getLastError(); + delete[] writedir; + delete[] mkdir; + throw std::runtime_error(msg.str()); } + delete[] mkdir; - testdir = exedir + "/../share/supertux/"; - if(datadir.empty() && access(testdir.c_str(), F_OK) == 0) { - datadir = testdir; + if(!PHYSFS_setWriteDir(writedir)) { + std::ostringstream msg; + msg << "Failed to use configuration directory '" + << writedir << "': " << PHYSFS_getLastError(); + delete[] writedir; + throw std::runtime_error(msg.str()); } - } + } + PHYSFS_addToSearchPath(writedir, 0); + delete[] writedir; + + // Search for archives and add them to the search path + const char* archiveExt = "zip"; + char** rc = PHYSFS_enumerateFiles("/"); + size_t extlen = strlen(archiveExt); + + for(char** i = rc; *i != 0; ++i) { + size_t l = strlen(*i); + if((l > extlen) && ((*i)[l - extlen - 1] == '.')) { + const char* ext = (*i) + (l - extlen); + if(strcasecmp(ext, archiveExt) == 0) { + const char* d = PHYSFS_getRealDir(*i); + char* str = new char[strlen(d) + strlen(dirsep) + l + 1]; + sprintf(str, "%s%s%s", d, dirsep, *i); + PHYSFS_addToSearchPath(str, 1); + delete[] str; + } + } + } -#ifdef DATA_PREFIX - // use default location - if(datadir.empty()) { - datadir = DATA_PREFIX; + PHYSFS_freeList(rc); + + // when started from source dir... + std::string dir = PHYSFS_getBaseDir(); + dir += "/data"; + std::string testfname = dir; + testfname += "/credits.txt"; + FILE* f = fopen(testfname.c_str(), "r"); + if(f) { + fclose(f); + if(!PHYSFS_addToSearchPath(dir.c_str(), 1)) { + std::cout << "Warning: Couldn't add '" << dir + << "' to physfs searchpath: " << PHYSFS_getLastError() << "\n"; + } + } + +#if defined(APPDATADIR) || defined(ENABLE_BINRELOC) + std::string datadir; +#ifdef ENABLE_BINRELOC + char* brdatadir = br_strcat(DATADIR, "/" PACKAGE_NAME); + datadir = brdatadir; + free(brdatadir); +#else + datadir = APPDATADIR; +#endif + if(!PHYSFS_addToSearchPath(datadir.c_str(), 1)) { + std::cout << "Couldn't add '" << datadir + << "' to physfs searchpath: " << PHYSFS_getLastError() << "\n"; } #endif - if(datadir.empty()) - throw std::runtime_error("Couldn't find datadir"); -} + // allow symbolic links + PHYSFS_permitSymbolicLinks(1); -static void init_tinygettext() -{ - dictionary_manager.add_directory(datadir + "/locale"); - dictionary_manager.set_charset("UTF-8"); + //show search Path + for(char** i = PHYSFS_getSearchPath(); *i != NULL; i++) + printf("[%s] is in the search path.\n", *i); } static void print_usage(const char* argv0) @@ -284,8 +316,8 @@ void init_video() SDL_WM_SetCaption(PACKAGE_NAME " " PACKAGE_VERSION, 0); // set icon - SDL_Surface* icon = IMG_Load( - get_resource_filename("images/engine/icons/supertux.xpm").c_str()); + SDL_Surface* icon = IMG_Load_RW( + get_physfs_SDLRWops("images/engine/icons/supertux.xpm"), true); if(icon != 0) { SDL_WM_SetIcon(icon, 0); SDL_FreeSurface(icon); @@ -389,9 +421,9 @@ int main(int argc, char** argv) try { #endif srand(time(0)); + init_physfs(argv[0]); init_sdl(); main_controller = new JoystickKeyboardController(); - find_directories(); init_config(); init_tinygettext(); parse_commandline(argc, argv); @@ -401,7 +433,12 @@ int main(int argc, char** argv) setup_menu(); load_shared(); if(config->start_level != "") { - GameSession session(config->start_level, ST_GL_LOAD_LEVEL_FILE); + // we have a normal path specified at commandline not physfs paths. + // So we simply mount that path here... + std::string dir = FileSystem::dirname(config->start_level); + PHYSFS_addToSearchPath(dir.c_str(), true); + GameSession session( + FileSystem::basename(config->start_level), ST_GL_LOAD_LEVEL_FILE); if(config->start_demo != "") session.play_demo(config->start_demo); if(config->record_demo != "") @@ -434,6 +471,7 @@ int main(int argc, char** argv) delete config; delete main_controller; SDL_Quit(); + PHYSFS_deinit(); return 0; } diff --git a/src/object/background.cpp b/src/object/background.cpp index a35376327..d2ef43638 100644 --- a/src/object/background.cpp +++ b/src/object/background.cpp @@ -92,7 +92,7 @@ Background::set_image(const std::string& name, float speed) this->speed = speed; delete image; - image = new Surface(datadir + "/images/background/" + name, false); + image = new Surface("images/background/" + name, false); } void diff --git a/src/object/particlesystem.cpp b/src/object/particlesystem.cpp index 4a78b96a1..d930c1dc8 100644 --- a/src/object/particlesystem.cpp +++ b/src/object/particlesystem.cpp @@ -73,9 +73,9 @@ void ParticleSystem::draw(DrawingContext& context) SnowParticleSystem::SnowParticleSystem() { - snowimages[0] = new Surface(datadir+"/images/objects/particles/snow0.png", true); - snowimages[1] = new Surface(datadir+"/images/objects/particles/snow1.png", true); - snowimages[2] = new Surface(datadir+"/images/objects/particles/snow2.png", true); + snowimages[0] = new Surface("images/objects/particles/snow0.png", true); + snowimages[1] = new Surface("images/objects/particles/snow1.png", true); + snowimages[2] = new Surface("images/objects/particles/snow2.png", true); virtual_width = SCREEN_WIDTH * 2; @@ -133,8 +133,8 @@ void SnowParticleSystem::update(float elapsed_time) // Ghosts don't change their movement pattern - not random GhostParticleSystem::GhostParticleSystem() { - ghosts[0] = new Surface(datadir+"/images/objects/particles/ghost0.png", true); - ghosts[1] = new Surface(datadir+"/images/objects/particles/ghost1.png", true); + ghosts[0] = new Surface("images/objects/particles/ghost0.png", true); + ghosts[1] = new Surface("images/objects/particles/ghost1.png", true); virtual_width = SCREEN_WIDTH * 2; @@ -190,7 +190,7 @@ void GhostParticleSystem::update(float elapsed_time) CloudParticleSystem::CloudParticleSystem() { - cloudimage = new Surface(datadir + "/images/objects/particles/cloud.png", true); + cloudimage = new Surface("images/objects/particles/cloud.png", true); virtual_width = 2000.0; diff --git a/src/object/particlesystem_interactive.cpp b/src/object/particlesystem_interactive.cpp index 13064bcc3..d411f8921 100644 --- a/src/object/particlesystem_interactive.cpp +++ b/src/object/particlesystem_interactive.cpp @@ -129,8 +129,8 @@ ParticleSystem_Interactive::collision(Particle* object, Vector movement) RainParticleSystem::RainParticleSystem() { - rainimages[0] = new Surface(datadir+"/images/objects/particles/rain0.png", true); - rainimages[1] = new Surface(datadir+"/images/objects/particles/rain1.png", true); + rainimages[0] = new Surface("images/objects/particles/rain0.png", true); + rainimages[1] = new Surface("images/objects/particles/rain1.png", true); virtual_width = SCREEN_WIDTH * 2; @@ -209,8 +209,8 @@ void RainParticleSystem::update(float elapsed_time) CometParticleSystem::CometParticleSystem() { - cometimages[0] = new Surface(datadir+"/images/creatures/mr_bomb/exploding-left-0.png", true); - cometimages[1] = new Surface(datadir+"/images/creatures/mr_bomb/exploding-left-0.png", true); + cometimages[0] = new Surface("images/creatures/mr_bomb/exploding-left-0.png", true); + cometimages[1] = new Surface("images/creatures/mr_bomb/exploding-left-0.png", true); virtual_width = SCREEN_WIDTH * 2; diff --git a/src/resources.cpp b/src/resources.cpp index a533ab7ba..7ab1cbfe0 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -27,9 +27,6 @@ #include "object/gameobjs.h" #include "object/player.h" -std::string datadir; -std::string user_dir; - MusicRef herring_song; MusicRef level_end_song; MusicRef credits_song; @@ -52,29 +49,26 @@ Font* white_big_text; void load_shared() { /* Load GUI/menu images: */ - checkbox = new Surface(datadir + "/images/engine/menu/checkbox-unchecked.png", true); - checkbox_checked = new Surface(datadir + "/images/engine/menu/checkbox-checked.png", true); - back = new Surface(datadir + "/images/engine/menu/arrow-back.png", true); - arrow_left = new Surface(datadir + "/images/engine/menu/arrow-left.png", true); - arrow_right = new Surface(datadir + "/images/engine/menu/arrow-right.png", true); + checkbox = new Surface("images/engine/menu/checkbox-unchecked.png", true); + checkbox_checked = new Surface("images/engine/menu/checkbox-checked.png", true); + back = new Surface("images/engine/menu/arrow-back.png", true); + arrow_left = new Surface("images/engine/menu/arrow-left.png", true); + arrow_right = new Surface("images/engine/menu/arrow-right.png", true); /* Load the mouse-cursor */ - mouse_cursor = new MouseCursor(datadir + "/images/engine/menu/mousecursor.png"); + mouse_cursor = new MouseCursor("images/engine/menu/mousecursor.png"); MouseCursor::set_current(mouse_cursor); /* Load global images: */ - gold_text = new Font(datadir + "/images/engine/fonts/gold.png", Font::TEXT, 16,18); - blue_text = new Font(datadir + "/images/engine/fonts/blue.png", Font::TEXT, 16,18,3); - white_text = new Font(datadir + "/images/engine/fonts/white.png", - Font::TEXT, 16,18); - gray_text = new Font(datadir + "/images/engine/fonts/gray.png", - Font::TEXT, 16,18); - white_small_text = new Font(datadir + "/images/engine/fonts/white-small.png", + gold_text = new Font("images/engine/fonts/gold.png", Font::TEXT, 16,18); + blue_text = new Font("images/engine/fonts/blue.png", Font::TEXT, 16,18,3); + white_text = new Font("images/engine/fonts/white.png", Font::TEXT, 16,18); + gray_text = new Font("images/engine/fonts/gray.png", Font::TEXT, 16,18); + white_small_text = new Font("images/engine/fonts/white-small.png", Font::TEXT, 8,9, 1); - white_big_text = new Font(datadir + "/images/engine/fonts/white-big.png", + white_big_text = new Font("images/engine/fonts/white-big.png", Font::TEXT, 20,22, 3); - yellow_nums = new Font(datadir + "/images/engine/fonts/numbers.png", - Font::NUM, 32,32); + yellow_nums = new Font("images/engine/fonts/numbers.png", Font::NUM, 32,32); Menu::default_font = white_text; Menu::active_font = blue_text; @@ -84,18 +78,17 @@ void load_shared() Button::info_font = white_small_text; - sprite_manager = new SpriteManager( - get_resource_filename("/images/sprites.strf")); - tile_manager = new TileManager("/images/tiles.strf"); + sprite_manager = new SpriteManager("images/sprites.strf"); + tile_manager = new TileManager("images/tiles.strf"); /* Tuxes: */ char img_name[1024]; for (int i = 0; i < GROWING_FRAMES; i++) { - sprintf(img_name, "%s/images/creatures/tux_grow/left-%i.png", datadir.c_str(), i+1); + sprintf(img_name, "images/creatures/tux_grow/left-%i.png", i+1); growingtux_left[i] = new Surface(img_name, true); - sprintf(img_name, "%s/images/creatures/tux_grow/right-%i.png", datadir.c_str(), i+1); + sprintf(img_name, "images/creatures/tux_grow/right-%i.png", i+1); growingtux_right[i] = new Surface(img_name, true); } @@ -127,8 +120,7 @@ void load_shared() load_object_gfx(); /* Tux life: */ - tux_life = new Surface(datadir + "/images/creatures/tux_small/tux-life.png", - true); + tux_life = new Surface("images/creatures/tux_small/tux-life.png", true); /* Sound effects: */ sound_manager->preload_sound("jump"); @@ -154,8 +146,8 @@ void load_shared() sound_manager->preload_sound("fireworks"); /* Herring song */ - herring_song = sound_manager->load_music(datadir + "/music/salcon.mod"); - level_end_song = sound_manager->load_music(datadir + "/music/leveldone.mod"); + herring_song = sound_manager->load_music("music/salcon.mod"); + level_end_song = sound_manager->load_music("music/leveldone.mod"); } /* Free shared data: */ @@ -200,16 +192,3 @@ void unload_shared() delete mouse_cursor; } -std::string get_resource_filename(const std::string& resource) -{ - std::string filepath = user_dir + "/" + resource; - if(FileSystem::faccessible(filepath)) - return filepath; - - filepath = datadir + resource; - if(FileSystem::faccessible(filepath)) - return filepath; - - std::cerr << "Couldn't find resource: '" << resource << "'." << std::endl; - return ""; -} diff --git a/src/resources.h b/src/resources.h index c3bcbaaa5..200a9a283 100644 --- a/src/resources.h +++ b/src/resources.h @@ -57,16 +57,6 @@ extern Font* white_small_text; extern Font* white_big_text; extern Font* yellow_nums; -extern std::string datadir; -extern std::string user_dir; - -/** maps a virtual resource path to a real path (ie. levels/bla is mapped to - * $DATADIR/levels/bla or $HOME/.supertux/levels/bla) - * All paths inside the game should be handled in as virtual paths and then - * expanded with this function just before the call to fopen or std::ifstream. - */ -std::string get_resource_filename(const std::string& resource); - void load_shared(); void unload_shared(); diff --git a/src/scripting/functions.cpp b/src/scripting/functions.cpp index a3c211a12..b46e6e2f6 100644 --- a/src/scripting/functions.cpp +++ b/src/scripting/functions.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "textscroller.h" #include "functions.h" #include "script_interpreter.h" @@ -28,5 +29,23 @@ void display_text_file(const std::string& filename) ::display_text_file(file); } +void import(HSQUIRRELVM v, const std::string& filename) +{ + std::string file + = ScriptInterpreter::current()->get_working_directory() + filename; + if(sqstd_loadfile(v, file.c_str(), true) < 0) { + std::cerr << "Warning couldn't load script '" << filename << "' (" + << file << ").\n"; + return; + } + + sq_push(v, -2); + if(sq_call(v, 1, false) < 0) { + std::cerr << "Couldn't execute script '" << filename << "' (" + << file << ").\n"; + return; + } +} + } diff --git a/src/scripting/functions.h b/src/scripting/functions.h index 2f4d6c801..a2c518d20 100644 --- a/src/scripting/functions.h +++ b/src/scripting/functions.h @@ -12,6 +12,10 @@ void set_wakeup_time(float seconds); * files) */ std::string translate(const std::string& text); +/** load a script file and executes it + * This is typically used to import functions from external files. + * */ +void import(HSQUIRRELVM v, const std::string& filename); } diff --git a/src/scripting/script_interpreter.cpp b/src/scripting/script_interpreter.cpp index 2d273f232..25c89d17b 100644 --- a/src/scripting/script_interpreter.cpp +++ b/src/scripting/script_interpreter.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -17,6 +18,8 @@ #include "sector.h" #include "file_system.h" #include "game_session.h" +#include "resources.h" +#include "physfs/physfs_stream.h" #include "object/text_object.h" #include "object/scripted_object.h" #include "object/display_effect.h" @@ -115,17 +118,12 @@ static SQInteger squirrel_read_char(SQUserPointer file) return c; } - void -ScriptInterpreter::load_script(std::istream& in, const std::string& sourcename) +ScriptInterpreter::run_script(std::istream& in, const std::string& sourcename) { if(sq_compile(v, squirrel_read_char, &in, sourcename.c_str(), true) < 0) throw SquirrelError(v, "Couldn't parse script"); -} - -void -ScriptInterpreter::start_script() -{ + _current = this; sq_push(v, -2); if(sq_call(v, 1, false) < 0) @@ -202,12 +200,22 @@ ScriptInterpreter::add_script_object(Sector* sector, const std::string& name, const std::string& script) { try { - std::auto_ptr interpreter - (new ScriptInterpreter(GameSession::current()->get_working_directory())); + std::string workdir = GameSession::current()->get_working_directory(); + std::auto_ptr interpreter( + new ScriptInterpreter(workdir)); interpreter->register_sector(sector); + + // load default.nut file if it exists + try { + std::string filename = workdir + "/default.nut"; + IFileStream in(filename); + interpreter->run_script(in, filename); + } catch(std::exception& e) { + // nothing + } + std::istringstream in(script); - interpreter->load_script(in, name); - interpreter->start_script(); + interpreter->run_script(in, name); sector->add_object(interpreter.release()); } catch(std::exception& e) { std::cerr << "Couldn't start '" << name << "' script: " << e.what() << "\n"; diff --git a/src/scripting/script_interpreter.h b/src/scripting/script_interpreter.h index 9cb99c58e..d8db300c1 100644 --- a/src/scripting/script_interpreter.h +++ b/src/scripting/script_interpreter.h @@ -21,8 +21,7 @@ public: void draw(DrawingContext& ); void update(float ); - void load_script(std::istream& in, const std::string& sourcename = ""); - void start_script(); + void run_script(std::istream& in, const std::string& sourcename = ""); void expose_object(void* object, const std::string& name, const std::string& type); diff --git a/src/scripting/wrapper.cpp b/src/scripting/wrapper.cpp index 8c3ff5295..7dfa7ac92 100644 --- a/src/scripting/wrapper.cpp +++ b/src/scripting/wrapper.cpp @@ -439,10 +439,22 @@ static int translate_wrapper(HSQUIRRELVM v) return 1; } +static int import_wrapper(HSQUIRRELVM v) +{ + HSQUIRRELVM arg0 = v; + const char* arg1; + sq_getstring(v, 4, &arg1); + + Scripting::import(arg0, arg1); + + return 0; +} + WrappedFunction supertux_global_functions[] = { { "display_text_file", &display_text_file_wrapper }, { "set_wakeup_time", &set_wakeup_time_wrapper }, { "translate", &translate_wrapper }, + { "import", &import_wrapper }, { 0, 0 } }; diff --git a/src/sector.cpp b/src/sector.cpp index 058f045e5..cb7a2d981 100644 --- a/src/sector.cpp +++ b/src/sector.cpp @@ -784,8 +784,7 @@ Sector::add_floating_text(const Vector& pos, const std::string& text) void Sector::load_music() { - level_song = sound_manager->load_music( - get_resource_filename("/music/" + song_title)); + level_song = sound_manager->load_music("/music/" + song_title); } void diff --git a/src/sprite/sprite_data.cpp b/src/sprite/sprite_data.cpp index a369d6664..69c2d2eeb 100644 --- a/src/sprite/sprite_data.cpp +++ b/src/sprite/sprite_data.cpp @@ -108,8 +108,7 @@ SpriteData::parse_action(const lisp::Lisp* lisp) } for(std::vector::size_type i = 0; i < images.size(); i++) { - action->surfaces.push_back( - new Surface(datadir + "/images/" + images[i], true)); + action->surfaces.push_back(new Surface("images/" + images[i], true)); } } actions[action->name] = action; diff --git a/src/textscroller.cpp b/src/textscroller.cpp index 859ca3092..20d900ce5 100644 --- a/src/textscroller.cpp +++ b/src/textscroller.cpp @@ -53,7 +53,7 @@ static void split_text(const std::string& text, std::vector& lines) } } -void display_text_file(const std::string& file) +void display_text_file(const std::string& filename) { const Font* heading_font = white_big_text; const Font* normal_font = white_text; @@ -66,7 +66,6 @@ void display_text_file(const std::string& file) std::string background_file; std::vector lines; - std::string filename = datadir + "/" + file; lisp::Parser parser; try { std::auto_ptr root (parser.parse(filename)); @@ -91,8 +90,8 @@ void display_text_file(const std::string& file) split_text(text, lines); // load background image - Surface* background = new Surface( - get_resource_filename("images/background/" + background_file), false); + Surface* background + = new Surface("images/background/" + background_file, false); bool done = false; float scroll = 0; diff --git a/src/tile.cpp b/src/tile.cpp index 79988924d..0fba4df16 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -135,8 +135,7 @@ Tile::load_images(const std::string& tilesetpath) imagespecs.end(); ++i) { const ImageSpec& spec = *i; Surface* surface; - std::string file - = get_resource_filename(tilesetpath + spec.file); + std::string file = tilesetpath + spec.file; if(spec.rect.get_width() <= 0) { surface = new Surface(file, true); } else { @@ -149,8 +148,7 @@ Tile::load_images(const std::string& tilesetpath) images.push_back(surface); } if(editor_imagefile != "") { - editor_image = new Surface( - get_resource_filename(tilesetpath + editor_imagefile), true); + editor_image = new Surface(tilesetpath + editor_imagefile, true); } } diff --git a/src/tile_manager.cpp b/src/tile_manager.cpp index 2bf90bfed..7422e7c9d 100644 --- a/src/tile_manager.cpp +++ b/src/tile_manager.cpp @@ -56,8 +56,7 @@ void TileManager::load_tileset(std::string filename) } lisp::Parser parser; - std::auto_ptr root (parser.parse( - get_resource_filename(filename))); + std::auto_ptr root (parser.parse(filename)); const lisp::Lisp* tiles_lisp = root->get_lisp("supertux-tiles"); if(!tiles_lisp) diff --git a/src/tinygettext/tinygettext.cpp b/src/tinygettext/tinygettext.cpp index f151e64b4..d908242af 100644 --- a/src/tinygettext/tinygettext.cpp +++ b/src/tinygettext/tinygettext.cpp @@ -20,12 +20,13 @@ #include #include -#include #include #include #include #include + #include "tinygettext.h" +#include "physfs/physfs_stream.h" //#define TRANSLATION_DEBUG @@ -34,7 +35,7 @@ namespace TinyGetText { /** Convert \a which is in \a from_charset to \a to_charset and return it */ std::string convert(const std::string& text, const std::string& from_charset, - const std::string& to_charset) + const std::string& to_charset) { if (from_charset == to_charset) return text; @@ -42,7 +43,7 @@ std::string convert(const std::string& text, iconv_t cd = iconv_open(to_charset.c_str(), from_charset.c_str()); size_t in_len = text.length(); - size_t out_len = text.length()*3; // FIXME: cross fingers that this is enough + size_t out_len = text.length()*3; // FIXME: cross fingers that this is enough char* out_orig = new char[out_len]; char* in_orig = new char[in_len+1]; @@ -244,31 +245,27 @@ DictionaryManager::get_dictionary(const std::string& spec) for (SearchPath::iterator p = search_path.begin(); p != search_path.end(); ++p) { - DIR* dir = opendir(p->c_str()); - if (!dir) + char** files = PHYSFS_enumerateFiles(p->c_str()); + if(!files) { - std::cerr << "Error: opendir() failed on " << *p << std::endl; + std::cerr << "Error: enumerateFiles() failed on " << *p << std::endl; } else { - struct dirent* ent; - while((ent = readdir(dir))) - { - if (std::string(ent->d_name) == lang + ".po") - { - std::string pofile = *p + "/" + ent->d_name; - std::ifstream in(pofile.c_str()); - if (!in) - { - std::cerr << "Error: Failure file opening: " << pofile << std::endl; - } - else - { - read_po_file(dict, in); - } - } + for(const char* const* filename = files; + *filename != 0; filename++) { + if(std::string(*filename) == lang + ".po") { + std::string pofile = *p + "/" + *filename; + try { + IFileStream in(pofile); + read_po_file(dict, in); + } catch(std::exception& e) { + std::cerr << "Error: Failure file opening: " << pofile << std::endl; + std::cerr << e.what() << "\n"; + } } - closedir(dir); + } + PHYSFS_freeList(files); } } @@ -283,23 +280,20 @@ DictionaryManager::get_languages() for (SearchPath::iterator p = search_path.begin(); p != search_path.end(); ++p) { - DIR* dir = opendir(p->c_str()); - if (!dir) + char** files = PHYSFS_enumerateFiles(p->c_str()); + if (!files) { std::cerr << "Error: opendir() failed on " << *p << std::endl; } else { - struct dirent* ent; - while((ent = readdir(dir))) - { - if (has_suffix(ent->d_name, ".po")) - { - std::string filename = ent->d_name; + for(const char* const* file = files; *file != 0; file++) { + if(has_suffix(*file, ".po")) { + std::string filename = *file; languages.insert(filename.substr(0, filename.length()-3)); - } - } - closedir(dir); + } + } + PHYSFS_freeList(files); } } return languages; @@ -312,6 +306,12 @@ DictionaryManager::set_language(const std::string& lang) current_dict = & (get_dictionary(language)); } +const std::string& +DictionaryManager::get_language() const +{ + return language; +} + void DictionaryManager::set_charset(const std::string& charset) { @@ -417,13 +417,13 @@ Dictionary::translate(const std::string& msgid, const std::string& msgid2, int n } } -std::string -Dictionary::translate(const std::string& msgid) +const char* +Dictionary::translate(const char* msgid) { Entries::iterator i = entries.find(msgid); if (i != entries.end() && !i->second.empty()) { - return i->second; + return i->second.c_str(); } else { @@ -434,18 +434,21 @@ Dictionary::translate(const std::string& msgid) } } -const char* -Dictionary::translate(const char* msgid) +std::string +Dictionary::translate(const std::string& msgid) { Entries::iterator i = entries.find(msgid); - if(i == entries.end() || i->second.empty()) { + if (i != entries.end() && !i->second.empty()) + { + return i->second; + } + else + { #ifdef TRANSLATION_DBEUG - std::cout << "Error: Couldn't translate: " << msgid << std::endl; -#endif - return msgid; - } - - return i->second.c_str(); + std::cout << "Error: Couldn't translate: " << msgid << std::endl; +#endif + return msgid; + } } void @@ -493,10 +496,10 @@ public: line_num = 0; char c = in.get(); if(c == (char) 0xef) { // skip UTF-8 intro that some texteditors produce - in.get(); - in.get(); + in.get(); + in.get(); } else { - in.unget(); + in.unget(); } tokenize_po(in); } @@ -532,8 +535,8 @@ public: to_charset = dict.get_charset(); if (to_charset.empty()) - { // No charset requested from the dict, so we use the one from the .po - to_charset = from_charset; + { // No charset requested from the dict, use utf-8 + to_charset = "utf-8"; dict.set_charset(from_charset); } } diff --git a/src/tinygettext/tinygettext.h b/src/tinygettext/tinygettext.h index a8a584680..d08790197 100644 --- a/src/tinygettext/tinygettext.h +++ b/src/tinygettext/tinygettext.h @@ -78,7 +78,7 @@ public: /** Translate the string \a msgid. */ std::string translate(const std::string& msgid); - + /** Translate the string \a msgid. */ const char* translate(const char* msgid); /** Add a translation from \a msgid to \a msgstr to the dictionary, @@ -125,6 +125,9 @@ public: /** Set a language based on a four? letter country code */ void set_language(const std::string& langspec); + /** returns the (normalized) country code of the currently used language */ + const std::string& get_language() const; + /** Set a charset that will be set on the returned dictionaries */ void set_charset(const std::string& charset); diff --git a/src/title.cpp b/src/title.cpp index 9afb6675b..5842cd4dc 100644 --- a/src/title.cpp +++ b/src/title.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #ifndef WIN32 #include @@ -115,7 +116,14 @@ void free_contrib_menu() void generate_contrib_menu() { /** Generating contrib levels list by making use of Level Subset */ - std::set level_subsets = FileSystem::dsubdirs("/levels", "info"); + std::vector level_subsets; + char** files = PHYSFS_enumerateFiles("levels/"); + for(const char* const* filename = files; *filename != 0; ++filename) { + std::string filepath = std::string("levels/") + *filename; + if(PHYSFS_isDirectory(filepath.c_str())) + level_subsets.push_back(filepath); + } + PHYSFS_freeList(files); free_contrib_menu(); @@ -123,24 +131,26 @@ void generate_contrib_menu() contrib_menu->add_hl(); int i = 0; - for (std::set::iterator it = level_subsets.begin(); - it != level_subsets.end(); ++it) - { - LevelSubset* subset = new LevelSubset(); + for (std::vector::iterator it = level_subsets.begin(); + it != level_subsets.end(); ++it) { + try { + std::auto_ptr subset (new LevelSubset()); subset->load(*it); if(subset->hide_from_contribs) { - delete subset; continue; } - contrib_menu->add_submenu(subset->title, contrib_subset_menu, i); - contrib_subsets.push_back(subset); - ++i; + contrib_menu->add_submenu(subset->title, contrib_subset_menu, i++); + contrib_subsets.push_back(subset.release()); + } catch(std::exception& e) { +#ifdef DEBUG + std::cerr << "Couldn't parse levelset info for '" + << *it << "': " << e.what() << "\n"; +#endif } + } contrib_menu->add_hl(); contrib_menu->add_back(_("Back")); - - level_subsets.clear(); } std::string get_level_name(const std::string& filename) @@ -184,7 +194,7 @@ void check_levels_contrib_menu() context.do_drawing(); // TODO: slots should be available for contrib maps - worldmap.loadgame(user_dir + "/save/" + subset.name + "-slot1.stsg"); + worldmap.loadgame("save/" + subset.name + "-slot1.stsg"); worldmap.display(); // run the map Menu::set_current(main_menu); @@ -275,13 +285,12 @@ void title() MusicRef credits_music; controller = new CodeController(); - titlesession = new GameSession(get_resource_filename("levels/misc/menu.stl"), - ST_GL_DEMO_GAME); + titlesession = new GameSession("levels/misc/menu.stl", ST_GL_DEMO_GAME); /* Load images: */ - bkg_title = new Surface(datadir + "/images/background/arctis.jpg", false); - logo = new Surface(datadir + "/images/engine/menu/logo.png", true); - //img_choose_subset = new Surface(datadir + "/images/status/choose-level-subset.png", true); + bkg_title = new Surface("images/background/arctis.jpg", false); + logo = new Surface("images/engine/menu/logo.png", true); + //img_choose_subset = new Surface("images/status/choose-level-subset.png", true); titlesession->get_current_sector()->activate("main"); titlesession->set_current(); @@ -375,7 +384,7 @@ void title() case MNID_CREDITS: fadeout(500); credits_music = sound_manager->load_music( - get_resource_filename("/music/credits.ogg")); + "/music/credits.ogg"); sound_manager->play_music(credits_music); display_text_file("credits.txt"); fadeout(500); @@ -399,12 +408,11 @@ void title() stream << slot; std::string str = _("Are you sure you want to delete slot") + stream.str() + "?"; - if(confirm_dialog(bkg_title, str.c_str())) - { - str = user_dir + "/save/slot" + stream.str() + ".stsg"; + if(confirm_dialog(bkg_title, str.c_str())) { + str = "save/slot" + stream.str() + ".stsg"; printf("Removing: %s\n",str.c_str()); - remove(str.c_str()); - } + PHYSFS_delete(str.c_str()); + } update_load_save_game_menu(load_game_menu); Menu::set_current(main_menu); diff --git a/src/video/surface.cpp b/src/video/surface.cpp index 823e23a1c..a650b4fe4 100644 --- a/src/video/surface.cpp +++ b/src/video/surface.cpp @@ -29,6 +29,7 @@ #include #include "gameconfig.h" +#include "physfs/physfs_sdl.h" #include "video/surface.h" #include "video/screen.h" @@ -295,7 +296,7 @@ sdl_surface_part_from_file(const std::string& file, int x, int y, int w, int h, SDL_Surface * temp; SDL_Surface * conv; - temp = IMG_Load(file.c_str()); + temp = IMG_Load_RW(get_physfs_SDLRWops(file), true); if (temp == 0) { std::stringstream msg; msg << "Couldn't load '" << file << "': " << SDL_GetError(); @@ -344,7 +345,7 @@ sdl_surface_from_file(const std::string& file, bool use_alpha) SDL_Surface* sdl_surface; SDL_Surface* temp; - temp = IMG_Load(file.c_str()); + temp = IMG_Load_RW(get_physfs_SDLRWops(file), true); if (temp == 0) { std::stringstream msg; msg << "Couldn't load file '" << file << "': " << SDL_GetError(); diff --git a/src/worldmap.cpp b/src/worldmap.cpp index 9f0c0c349..c4e3d29e0 100644 --- a/src/worldmap.cpp +++ b/src/worldmap.cpp @@ -352,14 +352,10 @@ WorldMap::WorldMap() tux = new Tux(this); add_object(tux); - leveldot_green - = new Surface(datadir + "/images/tiles/worldmap/leveldot_green.png", true); - leveldot_red - = new Surface(datadir + "/images/tiles/worldmap/leveldot_red.png", true); - messagedot - = new Surface(datadir + "/images/tiles/worldmap/messagedot.png", true); - teleporterdot - = new Surface(datadir + "/images/tiles/worldmap/teleporterdot.png", true); + leveldot_green= new Surface("images/tiles/worldmap/leveldot_green.png", true); + leveldot_red = new Surface("images/tiles/worldmap/leveldot_red.png", true); + messagedot = new Surface("images/tiles/worldmap/messagedot.png", true); + teleporterdot = new Surface("images/tiles/worldmap/teleporterdot.png", true); name = ""; music = "salcon.mod"; @@ -415,12 +411,11 @@ WorldMap::load_map() try { lisp::Parser parser; - std::string filename = get_resource_filename(map_filename); - std::auto_ptr root (parser.parse(filename)); + std::auto_ptr root (parser.parse(map_filename)); const lisp::Lisp* lisp = root->get_lisp("supertux-worldmap"); if(!lisp) - throw new std::runtime_error("file isn't a supertux-worldmap file."); + throw std::runtime_error("file isn't a supertux-worldmap file."); clear_objects(); lisp::ListIterator iter(lisp); @@ -548,8 +543,7 @@ WorldMap::get_level_title(Level& level) try { lisp::Parser parser; - std::auto_ptr root ( - parser.parse(get_resource_filename(levels_path + level.name))); + std::auto_ptr root (parser.parse(levels_path + level.name)); const lisp::Lisp* level_lisp = root->get_lisp("supertux-level"); if(!level_lisp) @@ -745,7 +739,7 @@ WorldMap::update(float delta) // do a shriking fade to the level shrink_fade(Vector((level->pos.x*32 + 16 + offset.x), (level->pos.y*32 + 16 + offset.y)), 500); - GameSession session(get_resource_filename(levels_path + level->name), + GameSession session(levels_path + level->name, ST_GL_LOAD_LEVEL_FILE, &level->statistics); switch (session.run()) @@ -847,8 +841,7 @@ WorldMap::update(float delta) std::auto_ptr interpreter (new ScriptInterpreter(levels_path)); std::istringstream in(level->extro_script); - interpreter->load_script(in, "level-extro-script"); - interpreter->start_script(); + interpreter->run_script(in, "level-extro-script"); add_object(interpreter.release()); } catch(std::exception& e) { std::cerr << "Couldn't run level-extro-script:" << e.what() << "\n"; @@ -992,7 +985,7 @@ WorldMap::display() quit = false; - song = sound_manager->load_music(datadir + "/music/" + music); + song = sound_manager->load_music("music/" + music); sound_manager->play_music(song); if(!intro_displayed && intro_script != "") { @@ -1000,8 +993,7 @@ WorldMap::display() std::auto_ptr interpreter (new ScriptInterpreter(levels_path)); std::istringstream in(intro_script); - interpreter->load_script(in, "worldmap-intro-script"); - interpreter->start_script(); + interpreter->run_script(in, "worldmap-intro-script"); add_object(interpreter.release()); } catch(std::exception& e) { std::cerr << "Couldn't execute worldmap-intro-script: " @@ -1058,8 +1050,7 @@ WorldMap::savegame(const std::string& filename) if(filename == "") return; - std::ofstream file(filename.c_str(), std::ios::out); - lisp::Writer writer(file); + lisp::Writer writer(filename); int nb_solved_levels = 0, total_levels = 0; for(Levels::iterator i = levels.begin(); i != levels.end(); ++i) {