aa096cb0b034638c08e095fb3859c63d2e29ed16
[supertux.git] / src / level_subset.cpp
1 //  $Id$
2 // 
3 //  SuperTux
4 //  Copyright (C) 2004 SuperTux Development Team, see AUTHORS for details
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 // 
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 //  02111-1307, USA.
20
21 #include <config.h>
22
23 #include <sstream>
24 #include <stdexcept>
25 #include <assert.h>
26 #include <unistd.h>
27 #include "app/setup.h"
28 #include "level.h"
29 #include "resources.h"
30 #include "app/globals.h"
31 #include "video/surface.h"
32 #include "level_subset.h"
33 #include "lisp/parser.h"
34 #include "lisp/lisp.h"
35
36 using namespace SuperTux;
37
38 static bool has_suffix(const std::string& data, const std::string& suffix)
39 {
40   if (data.length() >= suffix.length())
41     return data.compare(data.length() - suffix.length(), suffix.length(), suffix) == 0;
42   else
43     return false;
44 }
45
46 LevelSubset::LevelSubset()
47   : levels(0)
48 {
49 }
50
51 LevelSubset::~LevelSubset()
52 {
53 }
54
55 void LevelSubset::create(const std::string& subset_name)
56 {
57   Level new_lev;
58   LevelSubset new_subset;
59   new_subset.name = subset_name;
60   new_subset.title = "Unknown Title";
61   new_subset.description = "No description so far.";
62   new_subset.hide_from_contribs = false;
63   new_subset.save();
64 }
65
66 void LevelSubset::read_info_file(const std::string& info_file)
67 {
68   lisp::Parser parser;
69   std::auto_ptr<lisp::Lisp> root (parser.parse(info_file));
70
71   const lisp::Lisp* info = root->get_lisp("supertux-level-subset");
72   if(!info)
73     throw std::runtime_error("File is not a levelsubset file");
74
75   hide_from_contribs = false;
76
77   info->get("title", title);
78   info->get("description", description);
79   info->get_vector("levels", levels);
80   info->get("hide-from-contribs", hide_from_contribs);
81 }
82
83 void LevelSubset::load(const std::string& subset)
84 {
85   name = subset;
86   
87   // Check in which directory our subset is located (ie. ~/.supertux/
88   // or SUPERTUX_DATADIR)
89   std::string filename = get_resource_filename(
90       std::string("levels/") + subset + "/info");
91   if(filename == "") {
92     std::stringstream msg;
93     msg << "Couldn't find level subset '" << subset << "'.";
94     throw new std::runtime_error(msg.str());
95   }
96  
97   try {
98     read_info_file(filename);
99   } catch(std::exception& e) {
100     std::stringstream msg;
101     msg << "Couldn't parse info file '" << filename << "': " << e.what();
102     throw new std::runtime_error(msg.str());
103   }
104
105   // test is a worldmap exists
106   has_worldmap = false;
107   std::string worldmap = get_resource_filename(
108       std::string("levels/") + subset + "/worldmap.stwm");
109   if(worldmap != "") {
110     has_worldmap = true;
111   }
112
113   if (levels.empty())
114     { // Level info file doesn't define any levels, so read the
115       // directory to see what we can find
116       std::set<std::string> files;
117   
118       filename = datadir + "/levels/" + subset + "/";
119       files = FileSystem::read_directory(filename);
120
121       filename = user_dir + "/levels/" + subset + "/";
122       std::set<std::string> user_files = FileSystem::read_directory(filename);
123       files.insert(user_files.begin(), user_files.end());
124   
125       for(std::set<std::string>::iterator i = files.begin(); i != files.end(); ++i)
126         {
127           if (has_suffix(*i, ".stl"))
128             levels.push_back(get_resource_filename(
129                   std::string("levels/" + subset+ "/" + *i)));
130         }
131     }
132 }
133
134 void
135 LevelSubset::save()
136 {
137   FILE* fi;
138   std::string filename;
139
140   /* Save data file: */
141   filename = "/levels/" + name + "/";
142
143   FileSystem::fcreatedir(filename.c_str());
144   filename = std::string(user_dir) + "/levels/" + name + "/info";
145   if(!FileSystem::fwriteable(filename.c_str()))
146     filename = datadir + "/levels/" + name + "/info";
147   if(FileSystem::fwriteable(filename.c_str()))
148     {
149       fi = fopen(filename.c_str(), "w");
150       if (fi == NULL)
151         {
152           perror(filename.c_str());
153         }
154
155       /* Write header: */
156       fprintf(fi,";; SuperTux-Level-Subset\n");
157       fprintf(fi,"(supertux-level-subset\n");
158
159       /* Save title info: */
160       fprintf(fi,"  (title \"%s\")\n", title.c_str());
161
162       /* Save the description: */
163       fprintf(fi,"  (description \"%s\")\n", description.c_str());
164
165       /* Save the hide from Contrbis menu boolean: */
166       fprintf(fi,"  (hide-from-contribs %s)\n", hide_from_contribs ? "#t" : "#f");
167
168       fprintf( fi,")");
169       fclose(fi);
170     }
171 }
172
173 void
174 LevelSubset::add_level(const std::string& name)
175 {
176   levels.push_back(name);
177 }
178
179 std::string
180 LevelSubset::get_level_filename(unsigned int num)
181 {
182   assert(num < levels.size());
183   return levels[num];
184 }
185
186 std::string
187 LevelSubset::get_worldmap_filename()
188 {
189   return std::string("/levels/" + name + "/worldmap.stwm");
190 }
191
192 int
193 LevelSubset::get_num_levels() const
194 {
195   return levels.size();
196 }