Display number of solved levels in ContribMenu, kind of ugly patch, save system needs...
authorIngo Ruhnke <grumbel@gmail.com>
Sun, 10 Aug 2014 03:43:09 +0000 (05:43 +0200)
committerIngo Ruhnke <grumbel@gmail.com>
Sun, 10 Aug 2014 03:43:09 +0000 (05:43 +0200)
src/supertux/menu/contrib_menu.cpp
src/supertux/world.cpp
src/supertux/world.hpp

index 6bf8fcf..4078059 100644 (file)
 #include "supertux/menu/contrib_menu.hpp"
 
 #include <physfs.h>
+#include <sstream>
 
 #include "gui/menu_manager.hpp"
 #include "supertux/game_manager.hpp"
+#include "supertux/gameconfig.hpp"
 #include "supertux/menu/contrib_world_menu.hpp"
 #include "supertux/menu/menu_storage.hpp"
 #include "supertux/title_screen.hpp"
 #include "supertux/world.hpp"
+#include "util/file_system.hpp"
 #include "util/gettext.hpp"
 
 ContribMenu::ContribMenu() :
@@ -47,11 +50,24 @@ ContribMenu::ContribMenu() :
   {
     try
     {
-      std::unique_ptr<World> world (new World());
+      std::unique_ptr<World> world (new World);
+
       world->load(*it + "/info");
+
       if (!world->hide_from_contribs) 
       {
-        add_entry(i++, world->get_title());
+        { // FIXME: yuck, this should be easier
+          std::ostringstream stream;
+          std::string worlddirname = FileSystem::basename(*it);
+          stream << "profile" << g_config->profile << "/" << worlddirname << ".stsg";
+          std::string slotfile = stream.str();
+          world->set_savegame_filename(stream.str());
+          world->load_state();
+        }
+
+        std::ostringstream title;
+        title << world->get_title() << " (" << world->get_num_solved_levels() << "/" << world->get_num_levels() << ")";
+        add_entry(i++, title.str());
         m_contrib_worlds.push_back(std::move(world));
       }
     }
index f2e8300..05470f8 100644 (file)
@@ -34,6 +34,7 @@
 World* World::current_ = NULL;
 
 World::World() :
+  worldname(),
   levels(),
   basedir(),
   savegame_filename(),
@@ -85,6 +86,7 @@ void
 World::load(const std::string& filename)
 {
   basedir = FileSystem::dirname(filename);
+  worldname = basedir + "worldmap.stwm";
 
   lisp::Parser parser;
   const lisp::Lisp* root = parser.parse(filename);
@@ -115,12 +117,19 @@ World::load(const std::string& filename)
 
   for(const char* const* filename = files; *filename != 0; ++filename) {
     if(StringUtil::has_suffix(*filename, ".stl")) {
-      levels.push_back(path + *filename);
+      Level level;
+      level.fullpath = path + *filename;
+      level.name = *filename;
+      levels.push_back(level);
     }
   }
   PHYSFS_freeList(files);
 
-  std::sort(levels.begin(), levels.end(), StringUtil::numeric_less);
+  std::sort(levels.begin(), levels.end(),
+            [](const Level& lhs, const Level& rhs)
+            {
+              return StringUtil::numeric_less(lhs.fullpath, rhs.fullpath);
+            });
 }
 
 void
@@ -197,7 +206,12 @@ World::load_state()
 {
   using namespace scripting;
 
-  if(PHYSFS_exists(savegame_filename.c_str())) {
+  if(!PHYSFS_exists(savegame_filename.c_str()))
+  {
+    log_info << savegame_filename << ": doesn't exist, not loading state" << std::endl;
+  }
+  else
+  {
     try {
       lisp::Parser parser;
       const lisp::Lisp* root = parser.parse(savegame_filename);
@@ -240,7 +254,7 @@ World::load_state()
 const std::string&
 World::get_level_filename(unsigned int i) const
 {
-  return levels[i];
+  return levels[i].fullpath;
 }
 
 unsigned int
@@ -249,6 +263,71 @@ World::get_num_levels() const
   return levels.size();
 }
 
+int
+World::get_num_solved_levels() const
+{
+  int num_solved_levels = 0;
+
+  HSQUIRRELVM vm = scripting::global_vm;
+  int oldtop = sq_gettop(vm);
+
+  sq_pushroottable(vm);
+  sq_pushstring(vm, "state", -1);
+  if(SQ_FAILED(sq_get(vm, -2)))
+  {
+    log_warning << "failed to get 'state' table" << std::endl;
+  }
+  else
+  {
+    sq_pushstring(vm, "worlds", -1);
+    if(SQ_FAILED(sq_get(vm, -2)))
+    {
+      log_warning << "failed to get 'state.worlds' table" << std::endl;
+    }
+    else
+    {
+      sq_pushstring(vm, worldname.c_str(), -1);
+      if(SQ_FAILED(sq_get(vm, -2)))
+      {
+        log_warning << "failed to get state.worlds['" << worldname << "']" << std::endl;
+      }
+      else
+      {
+        sq_pushstring(vm, "levels", -1);
+        if(SQ_FAILED(sq_get(vm, -2)))
+        {
+          log_warning << "failed to get state.worlds['" << worldname << "'].levels" << std::endl;
+        }
+        else
+        {
+          for(auto level : levels)
+          {
+            sq_pushstring(vm, level.name.c_str(), -1);
+            if(SQ_FAILED(sq_get(vm, -2)))
+            {
+              log_warning << "failed to get state.worlds['" << worldname << "'].levels['"
+                          << level.name << "']" << std::endl;
+            }
+            else
+            {
+              bool solved = scripting::read_bool(vm, "solved");
+              if (solved)
+              {
+                num_solved_levels += 1;
+              }
+              sq_pop(vm, 1);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  sq_settop(vm, oldtop);
+
+  return num_solved_levels;
+}
+
 const std::string&
 World::get_basedir() const
 {
index bab44e9..c976c60 100644 (file)
@@ -45,6 +45,7 @@ public:
   void load_state();
 
   unsigned int get_num_levels() const;
+  int get_num_solved_levels() const;
 
   const std::string& get_level_filename(unsigned int i) const;
   const std::string& get_basedir() const;
@@ -55,7 +56,14 @@ public:
   void run();
 
 private:
-  std::vector<std::string> levels;
+  std::string worldname;
+  struct Level
+  {
+    std::string fullpath;
+    std::string name;
+  };
+
+  std::vector<Level> levels;
   std::string basedir;
   std::string savegame_filename;
   /// squirrel table that saves persistent state (about the world)