2 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 // 2014 Ingo Ruhnke <grumbel@gmx.de>
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "supertux/world_state.hpp"
20 #include "lisp/lisp.hpp"
21 #include "lisp/parser.hpp"
22 #include "lisp/writer.hpp"
23 #include "physfs/ifile_streambuf.hpp"
24 #include "scripting/serialize.hpp"
25 #include "scripting/squirrel_util.hpp"
26 #include "supertux/player_status.hpp"
27 #include "util/file_system.hpp"
28 #include "util/log.hpp"
29 #include "worldmap/worldmap.hpp"
31 WorldState::WorldState() :
32 m_player_status(new PlayerStatus)
37 WorldState::load(const std::string& filename)
39 if(!PHYSFS_exists(filename.c_str()))
41 log_info << filename << ": doesn't exist, not loading state" << std::endl;
47 HSQUIRRELVM vm = scripting::global_vm;
50 const lisp::Lisp* root = parser.parse(filename);
52 const lisp::Lisp* lisp = root->get_lisp("supertux-savegame");
55 throw std::runtime_error("file is not a supertux-savegame file");
60 lisp->get("version", version);
63 throw std::runtime_error("incompatible savegame version");
67 const lisp::Lisp* tux = lisp->get_lisp("tux");
70 throw std::runtime_error("No tux section in savegame");
73 m_player_status->read(*tux);
76 const lisp::Lisp* state = lisp->get_lisp("state");
79 throw std::runtime_error("No state section in savegame");
84 sq_pushstring(vm, "state", -1);
85 if(SQ_FAILED(sq_deleteslot(vm, -2, SQFalse)))
88 sq_pushstring(vm, "state", -1);
90 scripting::load_squirrel_table(vm, -1, *state);
91 if(SQ_FAILED(sq_createslot(vm, -3)))
92 throw std::runtime_error("Couldn't create state table");
98 catch(const std::exception& e)
100 log_fatal << "Couldn't load savegame: " << e.what() << std::endl;
106 WorldState::save(const std::string& filename)
108 { // make sure the savegame directory exists
109 std::string dirname = FileSystem::dirname(filename);
110 if(!PHYSFS_exists(dirname.c_str()))
112 if(!PHYSFS_mkdir(dirname.c_str()))
114 std::ostringstream msg;
115 msg << "Couldn't create directory for savegames '"
116 << dirname << "': " <<PHYSFS_getLastError();
117 throw std::runtime_error(msg.str());
121 if(!PHYSFS_isDirectory(dirname.c_str()))
123 std::ostringstream msg;
124 msg << "Savegame path '" << dirname << "' is not a directory";
125 throw std::runtime_error(msg.str());
129 HSQUIRRELVM vm = scripting::global_vm;
131 lisp::Writer writer(filename);
133 writer.start_list("supertux-savegame");
134 writer.write("version", 1);
136 using namespace worldmap;
137 if(WorldMap::current() != NULL)
139 std::ostringstream title;
140 title << WorldMap::current()->get_title();
141 title << " (" << WorldMap::current()->solved_level_count()
142 << "/" << WorldMap::current()->level_count() << ")";
143 writer.write("title", title.str());
146 writer.start_list("tux");
147 m_player_status->write(writer);
148 writer.end_list("tux");
150 writer.start_list("state");
152 sq_pushroottable(vm);
153 sq_pushstring(vm, "state", -1);
154 if(SQ_SUCCEEDED(sq_get(vm, -2)))
156 scripting::save_squirrel_table(vm, -1, writer);
160 writer.end_list("state");
162 writer.end_list("supertux-savegame");