- changed level subsets so that they do a readdir() instead of iterating ovre level1, level2,.. until error, this should also allow abitary level file names
SVN-Revision: 1502
interactive_object.h \
level.cpp \
level.h \
+level_subset.cpp \
+level_subset.h \
leveleditor.cpp \
leveleditor.h \
lispreader.cpp \
using namespace std;
-LevelSubset::LevelSubset()
- : image(0), levels(0)
-{
-}
-
-LevelSubset::~LevelSubset()
-{
- delete image;
-}
-
-void LevelSubset::create(const std::string& subset_name)
-{
- Level new_lev;
- LevelSubset new_subset;
- new_subset.name = subset_name;
- new_subset.title = "Unknown Title";
- new_subset.description = "No description so far.";
- new_subset.save();
- //new_lev.save(subset_name, 1, 0);
-}
-
-void LevelSubset::parse (lisp_object_t* cursor)
-{
- while(!lisp_nil_p(cursor))
- {
- lisp_object_t* cur = lisp_car(cursor);
- char *s;
-
- if (!lisp_cons_p(cur) || !lisp_symbol_p (lisp_car(cur)))
- {
- printf("Not good");
- }
- else
- {
- if (strcmp(lisp_symbol(lisp_car(cur)), "title") == 0)
- {
- if(( s = lisp_string(lisp_car(lisp_cdr(cur)))) != NULL)
- {
- title = s;
- }
- }
- else if (strcmp(lisp_symbol(lisp_car(cur)), "description") == 0)
- {
- if(( s = lisp_string(lisp_car(lisp_cdr(cur)))) != NULL)
- {
- description = s;
- }
- }
- }
- cursor = lisp_cdr (cursor);
- }
-}
-
-void LevelSubset::load(const char* subset)
-{
- FILE* fi;
- char filename[1024];
- char str[1024];
- int i;
- lisp_object_t* root_obj = 0;
-
- name = subset;
-
- snprintf(filename, 1024, "%s/levels/%s/info", st_dir, subset);
- if(!faccessible(filename))
- snprintf(filename, 1024, "%s/levels/%s/info", datadir.c_str(), subset);
- if(faccessible(filename))
- {
- fi = fopen(filename, "r");
- if (fi == NULL)
- {
- perror(filename);
- }
- lisp_stream_t stream;
- lisp_stream_init_file (&stream, fi);
- root_obj = lisp_read (&stream);
-
- if (root_obj->type == LISP_TYPE_EOF || root_obj->type == LISP_TYPE_PARSE_ERROR)
- {
- printf("World: Parse Error in file %s", filename);
- }
-
- lisp_object_t* cur = lisp_car(root_obj);
-
- if (!lisp_symbol_p (cur))
- {
- printf("World: Read error in %s",filename);
- }
-
- if (strcmp(lisp_symbol(cur), "supertux-level-subset") == 0)
- {
- parse(lisp_cdr(root_obj));
-
- }
-
- lisp_free(root_obj);
- fclose(fi);
-
- snprintf(str, 1024, "%s.png", filename);
- if(faccessible(str))
- {
- delete image;
- image = new Surface(str,IGNORE_ALPHA);
- }
- else
- {
- snprintf(filename, 1024, "%s/images/status/level-subset-info.png", datadir.c_str());
- delete image;
- image = new Surface(filename,IGNORE_ALPHA);
- }
- }
-
- for(i=1; i != -1; ++i)
- {
- /* Get the number of levels in this subset */
- snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir, subset,i);
- if(!faccessible(filename))
- {
- snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(), subset,i);
- if(!faccessible(filename))
- break;
- }
- }
- levels = --i;
-}
-
-void
-LevelSubset::save()
-{
- FILE* fi;
- string filename;
-
- /* Save data file: */
- filename = "/levels/" + name + "/";
-
- fcreatedir(filename.c_str());
- filename = string(st_dir) + "/levels/" + name + "/info";
- if(!fwriteable(filename.c_str()))
- filename = datadir + "/levels/" + name + "/info";
- if(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());
-
- fprintf( fi,")");
- fclose(fi);
- }
-}
-
-std::string
-LevelSubset::get_level_filename(unsigned int num)
-{
- char filename[1024];
-
- // Load data file:
- snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir,
- name.c_str(), num);
- if(!faccessible(filename))
- snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(),
- name.c_str(), num);
-
- return std::string(filename);
-}
-
-//---------------------------------------------------------------------------
-
Level::Level()
: name("noname"), author("mr. x"), time_left(500)
{
#include <map>
#include <string>
-#include "screen/surface.h"
-#include "lispreader.h"
-#include "musicref.h"
-
-class Tile;
-
-/** This type holds meta-information about a level-subset.
- It could be extended to handle manipulation of subsets. */
-class LevelSubset
-{
-public:
- LevelSubset();
- ~LevelSubset();
-
- static void create(const std::string& subset_name);
- void load(const char* subset);
- void save();
-
- std::string get_level_filename(unsigned int i);
-
- std::string name;
- std::string title;
- std::string description;
- Surface* image;
- int levels;
-
-private:
- void parse(lisp_object_t* cursor);
-};
-
class Sector;
+class LispReader;
class Level
{
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
+#include <assert.h>
#include "setup.h"
#include "level.h"
#include "globals.h"
#include "screen/surface.h"
#include "level_subset.h"
+static bool has_suffix(const std::string& data, const std::string& suffix)
+{
+ if (data.length() >= suffix.length())
+ return data.compare(data.length() - suffix.length(), suffix.length(), suffix) == 0;
+ else
+ return false;
+}
+
LevelSubset::LevelSubset()
- : image(0), levels(0)
+ : levels(0)
{
}
LevelSubset::~LevelSubset()
{
- delete image;
}
void LevelSubset::create(const std::string& subset_name)
new_subset.title = "Unknown Title";
new_subset.description = "No description so far.";
new_subset.save();
- //new_lev.save(subset_name, 1, 0);
}
-void LevelSubset::parse (lisp_object_t* cursor)
+void LevelSubset::read_info_file(const std::string& info_file)
{
- while(!lisp_nil_p(cursor))
+ lisp_object_t* root_obj = lisp_read_from_file(info_file);
+ lisp_object_t* cur = lisp_car(root_obj);
+
+ if (lisp_symbol_p(cur) && strcmp(lisp_symbol(cur), "supertux-level-subset") == 0)
{
- lisp_object_t* cur = lisp_car(cursor);
- char *s;
+ LispReader reader(lisp_cdr(root_obj));
- if (!lisp_cons_p(cur) || !lisp_symbol_p (lisp_car(cur)))
- {
- printf("Not good");
- }
- else
- {
- if (strcmp(lisp_symbol(lisp_car(cur)), "title") == 0)
- {
- if(( s = lisp_string(lisp_car(lisp_cdr(cur)))) != NULL)
- {
- title = s;
- }
- }
- else if (strcmp(lisp_symbol(lisp_car(cur)), "description") == 0)
- {
- if(( s = lisp_string(lisp_car(lisp_cdr(cur)))) != NULL)
- {
- description = s;
- }
- }
- }
- cursor = lisp_cdr (cursor);
+ reader.read_string("title", title);
+ reader.read_string("description", description);
+ reader.read_string_vector("levels", levels);
+ }
+ else
+ {
+ std::cout << "LevelSubset: parse error in info file: " << info_file << std::endl;
}
+
+ lisp_free(root_obj);
}
void LevelSubset::load(const char* subset)
{
- FILE* fi;
- char filename[1024];
- char str[1024];
- int i;
- lisp_object_t* root_obj = 0;
-
name = subset;
-
- snprintf(filename, 1024, "%s/levels/%s/info", st_dir, subset);
- if(!faccessible(filename))
- snprintf(filename, 1024, "%s/levels/%s/info", datadir.c_str(), subset);
- if(faccessible(filename))
+
+ // Check in which directory our subset is located (ie. ~/.supertux/
+ // or SUPERTUX_DATADIR)
+ char filename[1024];
+ snprintf(filename, 1024, "%s/levels/%s/", st_dir, subset);
+ if (access(filename, R_OK) == 0)
{
- fi = fopen(filename, "r");
- if (fi == NULL)
- {
- perror(filename);
- }
- lisp_stream_t stream;
- lisp_stream_init_file (&stream, fi);
- root_obj = lisp_read (&stream);
-
- if (root_obj->type == LISP_TYPE_EOF || root_obj->type == LISP_TYPE_PARSE_ERROR)
- {
- printf("World: Parse Error in file %s", filename);
- }
-
- lisp_object_t* cur = lisp_car(root_obj);
-
- if (!lisp_symbol_p (cur))
- {
- printf("World: Read error in %s",filename);
- }
-
- if (strcmp(lisp_symbol(cur), "supertux-level-subset") == 0)
- {
- parse(lisp_cdr(root_obj));
-
- }
-
- lisp_free(root_obj);
- fclose(fi);
-
- snprintf(str, 1024, "%s.png", filename);
- if(faccessible(str))
+ directory = filename;
+ }
+ else
+ {
+ snprintf(filename, 1024, "%s/levels/%s/", datadir.c_str(), subset);
+ if (access(filename, R_OK) == 0)
+ directory = filename;
+ else
+ std::cout << "Error: LevelSubset: couldn't find subset: " << subset << std::endl;
+ }
+
+ read_info_file(directory + "info");
+
+ if (levels.empty())
+ { // Level info file doesn't define any levels, so read the
+ // directory to see what we can find
+ std::vector<std::string> files;
+
+ snprintf(filename, 1024, "%s/levels/%s/", st_dir, subset);
+ if(access(filename, R_OK) == 0)
{
- delete image;
- image = new Surface(str,IGNORE_ALPHA);
+ files = read_directory(filename);
}
else
{
- snprintf(filename, 1024, "%s/images/status/level-subset-info.png", datadir.c_str());
- delete image;
- image = new Surface(filename,IGNORE_ALPHA);
+ snprintf(filename, 1024, "%s/levels/%s/", datadir.c_str(), subset);
+ files = read_directory(filename);
}
- }
-
- for(i=1; i != -1; ++i)
- {
- /* Get the number of levels in this subset */
- snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir, subset,i);
- if(!faccessible(filename))
+
+ for(std::vector<std::string>::iterator i = files.begin(); i != files.end(); ++i)
{
- snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(), subset,i);
- if(!faccessible(filename))
- break;
+ if (has_suffix(*i, ".stl"))
+ levels.push_back(*i);
}
}
- levels = --i;
}
void
}
/* Write header: */
- fprintf(fi,";SuperTux-Level-Subset\n");
+ fprintf(fi,";; SuperTux-Level-Subset\n");
fprintf(fi,"(supertux-level-subset\n");
/* Save title info: */
}
}
+void
+LevelSubset::add_level(const std::string& name)
+{
+ levels.push_back(name);
+}
+
std::string
LevelSubset::get_level_filename(unsigned int num)
{
- char filename[1024];
-
- // Load data file:
- snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir,
- name.c_str(), num);
- if(!faccessible(filename))
- snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(),
- name.c_str(), num);
-
- return std::string(filename);
+ assert(num < levels.size());
+
+ return directory + levels[num];
}
-/* EOF */
+int
+LevelSubset::get_num_levels() const
+{
+ return levels.size();
+}
+/* EOF */
#ifndef SUPERTUX_LEVEL_SUBSET_H
#define SUPERTUX_LEVEL_SUBSET_H
+#include <vector>
#include <string>
#include "lispreader.h"
It could be extended to handle manipulation of subsets. */
class LevelSubset
{
+private:
+ /** Directory in which the level subset is stored */
+ std::string directory;
+
+ /** Level filenames without the leading path ("level1.stl",
+ "level3.stl", ...) */
+ std::vector<std::string> levels;
+
public:
LevelSubset();
~LevelSubset();
void load(const char* subset);
void save();
+ void add_level(const std::string& name);
+
std::string get_level_filename(unsigned int i);
+ int get_num_levels() const;
std::string name;
std::string title;
std::string description;
Surface* image;
- int levels;
-
+
private:
- void parse(lisp_object_t* cursor);
+ void read_info_file(const std::string& info_file);
};
#endif
le_object_properties_bt->draw(context);
}
- sprintf(str, "%d/%d", le_levelnb,le_level_subset->levels);
- context.draw_text(white_text, str, Vector((le_level_subset->levels < 10) ? -10 : 0, 16), LAYER_GUI);
+ sprintf(str, "%d/%d", le_levelnb, le_level_subset->get_num_levels());
+ context.draw_text(white_text, str, Vector((le_level_subset->get_num_levels() < 10) ? -10 : 0, 16), LAYER_GUI);
if(!le_help_shown)
context.draw_text(white_small_text, "F1 for Help", Vector(10, 430), LAYER_GUI);
le_next_level_bt->event(event);
if(le_next_level_bt->get_state() == BUTTON_CLICKED)
{
- if(le_levelnb < le_level_subset->levels)
+ if(le_levelnb < le_level_subset->get_num_levels())
{
goto_level(le_levelnb+1);
}
Surface* surf = new Surface(le_level->get_sector("main")->background->get_image(), false);
if(confirm_dialog(surf, str))
{
- new_lev.save(le_level_subset->name.c_str());
- le_level_subset->levels = le_levelnb;
+ le_level_subset->add_level("newlevel.stl");
+ new_lev.save(le_level_subset->get_level_filename(le_levelnb+1));
goto_level(le_levelnb);
}
if(surf != NULL)
#include "game_object.h"
#include "screen/surface.h"
#include "level.h"
+#include "level_subset.h"
+#include "moving_object.h"
#include "button.h"
#include "menu.h"
exit(ret);
}
+std::vector<std::string> read_directory(const std::string& pathname)
+{
+ std::vector<std::string> dirnames;
+
+ DIR* dir = opendir(pathname.c_str());
+ if (dir)
+ {
+ struct dirent *direntp;
+
+ while((direntp = readdir(dir)))
+ {
+ dirnames.push_back(direntp->d_name);
+ }
+
+ closedir(dir);
+ }
+
+ return dirnames;
+}
+
+/* EOF */
#ifndef SUPERTUX_SETUP_H
#define SUPERTUX_SETUP_H
+#include <vector>
+#include <string>
#include "menu.h"
#include "sound.h"
#include "type.h"
int faccessible(const char *filename);
int fcreatedir(const char* relative_dir);
int fwriteable(const char *filename);
+std::vector<std::string> read_directory(const std::string& pathname);
+
FILE * opendata(const char * filename, const char * mode);
string_list_type dsubdirs(const char *rel_path, const char* expected_file);
string_list_type dfiles(const char *rel_path, const char* glob, const char* exception_str);
contrib_subset_menu->additem(MN_LABEL, subset.title, 0,0);
contrib_subset_menu->additem(MN_HL,"",0,0);
- for (int i = 1; i <= subset.levels; ++i)
+ for (int i = 0; i < subset.get_num_levels(); ++i)
{
Level* level = new Level;
level->load(subset.get_level_filename(i));