19edf4772766d1d00fe400717b609b78e889b856
[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
34 using namespace SuperTux;
35
36 static bool has_suffix(const std::string& data, const std::string& suffix)
37 {
38   if (data.length() >= suffix.length())
39     return data.compare(data.length() - suffix.length(), suffix.length(), suffix) == 0;
40   else
41     return false;
42 }
43
44 LevelSubset::LevelSubset()
45   : levels(0)
46 {
47 }
48
49 LevelSubset::~LevelSubset()
50 {
51 }
52
53 void LevelSubset::create(const std::string& subset_name)
54 {
55   Level new_lev;
56   LevelSubset new_subset;
57   new_subset.name = subset_name;
58   new_subset.title = "Unknown Title";
59   new_subset.description = "No description so far.";
60   new_subset.hide_from_contribs = false;
61   new_subset.save();
62 }
63
64 void LevelSubset::read_info_file(const std::string& info_file)
65 {
66   lisp_object_t* root_obj = lisp_read_from_file(info_file);
67   if (root_obj == NULL)
68     return;
69   lisp_object_t* cur = lisp_car(root_obj);
70
71   if (lisp_symbol_p(cur) && strcmp(lisp_symbol(cur), "supertux-level-subset") == 0)
72     {
73       LispReader reader(lisp_cdr(root_obj));
74
75       reader.read_string("title", title, true);
76       reader.read_string("description", description, true);
77       reader.read_string_vector("levels", levels);
78       hide_from_contribs = false;
79       reader.read_bool("hide-from-contribs", hide_from_contribs);
80     }
81   else
82     {
83       std::cout << "LevelSubset: parse error in info file: " << info_file << std::endl;
84     }
85
86   lisp_free(root_obj);
87 }
88
89 void LevelSubset::load(const std::string& subset)
90 {
91   name = subset;
92   
93   // Check in which directory our subset is located (ie. ~/.supertux/
94   // or SUPERTUX_DATADIR)
95   std::string filename = get_resource_filename(
96       std::string("levels/") + subset + "/info");
97   if(filename == "") {
98     std::stringstream msg;
99     msg << "Couldn't find level subset '" << subset << "'.";
100     throw new std::runtime_error(msg.str());
101   }
102   
103   read_info_file(filename);
104
105   if (levels.empty())
106     { // Level info file doesn't define any levels, so read the
107       // directory to see what we can find
108       std::set<std::string> files;
109   
110       filename = datadir + "/levels/" + subset + "/";
111       files = FileSystem::read_directory(filename);
112
113       filename = st_dir + "/levels/" + subset + "/";
114       std::set<std::string> user_files = FileSystem::read_directory(filename);
115       files.insert(user_files.begin(), user_files.end());
116   
117       for(std::set<std::string>::iterator i = files.begin(); i != files.end(); ++i)
118         {
119           if (has_suffix(*i, ".stl"))
120             levels.push_back(get_resource_filename(
121                   std::string("levels/" + subset+ "/" + *i)));
122         }
123     }
124 }
125
126 void
127 LevelSubset::save()
128 {
129   FILE* fi;
130   std::string filename;
131
132   /* Save data file: */
133   filename = "/levels/" + name + "/";
134
135   FileSystem::fcreatedir(filename.c_str());
136   filename = std::string(st_dir) + "/levels/" + name + "/info";
137   if(!FileSystem::fwriteable(filename.c_str()))
138     filename = datadir + "/levels/" + name + "/info";
139   if(FileSystem::fwriteable(filename.c_str()))
140     {
141       fi = fopen(filename.c_str(), "w");
142       if (fi == NULL)
143         {
144           perror(filename.c_str());
145         }
146
147       /* Write header: */
148       fprintf(fi,";; SuperTux-Level-Subset\n");
149       fprintf(fi,"(supertux-level-subset\n");
150
151       /* Save title info: */
152       fprintf(fi,"  (title \"%s\")\n", title.c_str());
153
154       /* Save the description: */
155       fprintf(fi,"  (description \"%s\")\n", description.c_str());
156
157       /* Save the hide from Contrbis menu boolean: */
158       fprintf(fi,"  (hide-from-contribs %s)\n", hide_from_contribs ? "#t" : "#f");
159
160       fprintf( fi,")");
161       fclose(fi);
162     }
163 }
164
165 void
166 LevelSubset::add_level(const std::string& name)
167 {
168   levels.push_back(name);
169 }
170
171 std::string
172 LevelSubset::get_level_filename(unsigned int num)
173 {
174   assert(num < levels.size());
175   return levels[num];
176 }
177
178 int
179 LevelSubset::get_num_levels() const
180 {
181   return levels.size();
182 }