- moved level subsets into their own file
authorIngo Ruhnke <grumbel@gmx.de>
Wed, 16 Jun 2004 00:40:42 +0000 (00:40 +0000)
committerIngo Ruhnke <grumbel@gmx.de>
Wed, 16 Jun 2004 00:40:42 +0000 (00:40 +0000)
- 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

src/Makefile.am
src/level.cpp
src/level.h
src/level_subset.cpp
src/level_subset.h
src/leveleditor.cpp
src/leveleditor.h
src/setup.cpp
src/setup.h
src/title.cpp

index 6fc28fd..c6c9bef 100644 (file)
@@ -44,6 +44,8 @@ interactive_object.cpp \
 interactive_object.h \
 level.cpp \
 level.h \
+level_subset.cpp \
+level_subset.h \
 leveleditor.cpp \
 leveleditor.h \
 lispreader.cpp \
index b2748d9..3470547 100644 (file)
 
 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)
 {
index e9bb6f0..c955c5f 100644 (file)
 #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
 {
index f401121..25785d1 100644 (file)
 //  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)
@@ -42,112 +50,74 @@ 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
@@ -172,7 +142,7 @@ LevelSubset::save()
         }
 
       /* Write header: */
-      fprintf(fi,";SuperTux-Level-Subset\n");
+      fprintf(fi,";SuperTux-Level-Subset\n");
       fprintf(fi,"(supertux-level-subset\n");
 
       /* Save title info: */
@@ -186,20 +156,24 @@ LevelSubset::save()
     }
 }
 
+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 */
index 45be7ae..4ff6b4d 100644 (file)
@@ -21,6 +21,7 @@
 #ifndef SUPERTUX_LEVEL_SUBSET_H
 #define SUPERTUX_LEVEL_SUBSET_H
 
+#include <vector>
 #include <string>
 #include "lispreader.h"
 
@@ -30,6 +31,14 @@ class Surface;
     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();
@@ -38,16 +47,18 @@ public:
   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
index 6b1b9aa..2d7f6f7 100644 (file)
@@ -822,8 +822,8 @@ void LevelEditor::drawinterface(DrawingContext &context)
       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);
@@ -1153,7 +1153,7 @@ void LevelEditor::checkevents()
           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);
             }
@@ -1165,8 +1165,8 @@ void LevelEditor::checkevents()
               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)
index 4ded83f..5c333a8 100644 (file)
@@ -27,6 +27,8 @@
 #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"
 
index 45a8bed..4a58f76 100644 (file)
@@ -1112,3 +1112,24 @@ void usage(char * prog, int ret)
   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 */
index 1661be7..ebb85c4 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef SUPERTUX_SETUP_H
 #define SUPERTUX_SETUP_H
 
+#include <vector>
+#include <string>
 #include "menu.h"
 #include "sound.h"
 #include "type.h"
@@ -27,6 +29,8 @@
 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);
index 7d75ef1..84bd3f6 100644 (file)
@@ -129,7 +129,7 @@ void check_contrib_menu()
               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));