00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "supertux/level.hpp"
00018
00019 #include "lisp/list_iterator.hpp"
00020 #include "lisp/parser.hpp"
00021 #include "object/bonus_block.hpp"
00022 #include "object/coin.hpp"
00023 #include "supertux/sector.hpp"
00024 #include "supertux/tile_manager.hpp"
00025 #include "supertux/tile_set.hpp"
00026 #include "trigger/secretarea_trigger.hpp"
00027
00028 #include <sstream>
00029 #include <stdexcept>
00030
00031 using namespace std;
00032
00033 Level::Level() :
00034 name("noname"),
00035 author("Mr. X"),
00036 contact(),
00037 license(),
00038 filename(),
00039 on_menukey_script(),
00040 sectors(),
00041 stats(),
00042 tileset(NULL),
00043 free_tileset(false)
00044 {
00045 }
00046
00047 Level::~Level()
00048 {
00049 for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
00050 delete *i;
00051 if(free_tileset)
00052 delete tileset;
00053 }
00054
00055 void
00056 Level::load(const std::string& filepath)
00057 {
00058 try {
00059 filename = filepath;
00060 lisp::Parser parser;
00061 const lisp::Lisp* root = parser.parse(filepath);
00062
00063 const lisp::Lisp* level = root->get_lisp("supertux-level");
00064 if(!level)
00065 throw std::runtime_error("file is not a supertux-level file.");
00066
00067 int version = 1;
00068 level->get("version", version);
00069 if(version == 1) {
00070 log_info << "level uses old format: version 1" << std::endl;
00071 tileset = tile_manager->get_tileset("images/tiles.strf");
00072 load_old_format(*level);
00073 return;
00074 }
00075
00076 const lisp::Lisp* tilesets_lisp = level->get_lisp("tilesets");
00077 if(tilesets_lisp != NULL) {
00078 tileset = tile_manager->parse_tileset_definition(*tilesets_lisp);
00079 free_tileset = true;
00080 }
00081 std::string tileset_name;
00082 if(level->get("tileset", tileset_name)) {
00083 if(tileset != NULL) {
00084 log_warning << "multiple tilesets specified in level" << std::endl;
00085 } else {
00086 tileset = tile_manager->get_tileset(tileset_name);
00087 }
00088 }
00089
00090 if(tileset == NULL) {
00091 tileset = tile_manager->get_tileset("images/tiles.strf");
00092 }
00093 current_tileset = tileset;
00094
00095 contact = "";
00096 license = "";
00097
00098 lisp::ListIterator iter(level);
00099 while(iter.next()) {
00100 const std::string& token = iter.item();
00101 if(token == "version") {
00102 iter.value()->get(version);
00103 if(version > 2) {
00104 log_warning << "level format newer than application" << std::endl;
00105 }
00106 } else if(token == "tileset" || token == "tilesets") {
00107 continue;
00108 } else if(token == "name") {
00109 iter.value()->get(name);
00110 } else if(token == "author") {
00111 iter.value()->get(author);
00112 } else if(token == "contact") {
00113 iter.value()->get(contact);
00114 } else if(token == "license") {
00115 iter.value()->get(license);
00116 } else if(token == "on-menukey-script") {
00117 iter.value()->get(on_menukey_script);
00118 } else if(token == "sector") {
00119 Sector* sector = new Sector(this);
00120 sector->parse(*(iter.lisp()));
00121 add_sector(sector);
00122 } else {
00123 log_warning << "Unknown token '" << token << "' in level file" << std::endl;
00124 }
00125 }
00126
00127 if (license == "") {
00128 log_warning << "The level author did not specify a license for this level. You might not be allowed to share it." << std::endl;
00129
00130 }
00131 } catch(std::exception& e) {
00132 std::stringstream msg;
00133 msg << "Problem when reading level '" << filepath << "': " << e.what();
00134 throw std::runtime_error(msg.str());
00135 }
00136
00137 current_tileset = NULL;
00138 }
00139
00140 void
00141 Level::load_old_format(const Reader& reader)
00142 {
00143 reader.get("name", name);
00144 reader.get("author", author);
00145
00146 Sector* sector = new Sector(this);
00147 sector->parse_old_format(reader);
00148 add_sector(sector);
00149 }
00150
00151 void
00152 Level::add_sector(Sector* sector)
00153 {
00154 Sector* test = get_sector(sector->get_name());
00155 if(test != 0) {
00156 throw std::runtime_error("Trying to add 2 sectors with same name");
00157 }
00158 sectors.push_back(sector);
00159 }
00160
00161 Sector*
00162 Level::get_sector(const std::string& name)
00163 {
00164 for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i) {
00165 Sector* sector = *i;
00166 if(sector->get_name() == name)
00167 return sector;
00168 }
00169
00170 return 0;
00171 }
00172
00173 size_t
00174 Level::get_sector_count()
00175 {
00176 return sectors.size();
00177 }
00178
00179 Sector*
00180 Level::get_sector(size_t num)
00181 {
00182 return sectors.at(num);
00183 }
00184
00185 int
00186 Level::get_total_coins()
00187 {
00188 int total_coins = 0;
00189 for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i) {
00190 Sector* sector = *i;
00191 for(Sector::GameObjects::iterator o = sector->gameobjects.begin();
00192 o != sector->gameobjects.end(); ++o) {
00193 Coin* coin = dynamic_cast<Coin*> (*o);
00194 if(coin)
00195 {
00196 total_coins++;
00197 continue;
00198 }
00199 BonusBlock *block = dynamic_cast<BonusBlock*> (*o);
00200 if(block)
00201 {
00202 if (block->contents == BonusBlock::CONTENT_COIN)
00203 {
00204 total_coins++;
00205 continue;
00206 }
00207 #if 0
00208
00209 else if (block->contents == BonusBlock::CONTENT_1UP)
00210 {
00211 total_coins += 100;
00212 continue;
00213 }
00214 #endif
00215 }
00216 }
00217 }
00218 return total_coins;
00219 }
00220
00221 int
00222 Level::get_total_badguys()
00223 {
00224 int total_badguys = 0;
00225 for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
00226 total_badguys += (*i)->get_total_badguys();
00227 return total_badguys;
00228 }
00229
00230 int
00231 Level::get_total_secrets()
00232 {
00233 int total_secrets = 0;
00234 for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
00235 total_secrets += (*i)->get_total_count<SecretAreaTrigger>();
00236 return total_secrets;
00237 }
00238
00239