From: Ingo Ruhnke Date: Wed, 13 Aug 2014 19:50:47 +0000 (+0200) Subject: Renamed WorldState to Savegame and implemented basic load/save for Worldmaps and... X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=c161b88a74b82d755866b5a0294f1a3aaa41d55d;p=supertux.git Renamed WorldState to Savegame and implemented basic load/save for Worldmaps and Levelsets Levelsets themselves are still broken and don't display properly in the menu Worlds without any savegame will be displayed with a *NEW* --- diff --git a/src/supertux/game_manager.cpp b/src/supertux/game_manager.cpp index baa82e2b1..79ffe6f70 100644 --- a/src/supertux/game_manager.cpp +++ b/src/supertux/game_manager.cpp @@ -28,14 +28,14 @@ #include "supertux/screen_fade.hpp" #include "supertux/screen_manager.hpp" #include "supertux/world.hpp" -#include "supertux/world_state.hpp" +#include "supertux/savegame.hpp" #include "util/file_system.hpp" #include "util/log.hpp" #include "worldmap/worldmap.hpp" GameManager::GameManager() : m_world(), - m_world_state() + m_savegame() { } @@ -46,15 +46,15 @@ GameManager::~GameManager() void GameManager::start_level(const std::string& level_filename) { - /* +#ifdef GRUMBEL m_world = std::move(world); - m_world_state.reset(new WorldState); - m_world_state->load(m_world->get_savegame_filename()); + m_savegame.reset(new Savegame); + m_savegame->load(m_world->get_savegame_filename()); std::unique_ptr screen(new GameSession(level_filename, - &m_world_state)); + &m_savegame)); g_screen_manager->push_screen(std::move(screen)); - */ +#endif } void @@ -63,13 +63,12 @@ GameManager::start_game(std::unique_ptr world) try { m_world = std::move(world); - m_world_state.reset(new WorldState); - - m_world_state->load(m_world->get_savegame_filename()); + m_savegame.reset(new Savegame(m_world->get_savegame_filename())); + m_savegame->load(); g_screen_manager->push_screen(std::unique_ptr( new worldmap::WorldMap(m_world->get_worldmap_filename(), - *m_world_state))); + *m_savegame))); } catch(std::exception& e) { diff --git a/src/supertux/game_manager.hpp b/src/supertux/game_manager.hpp index 5e21f8815..e058793c1 100644 --- a/src/supertux/game_manager.hpp +++ b/src/supertux/game_manager.hpp @@ -19,7 +19,7 @@ #include -#include "supertux/world_state.hpp" +#include "supertux/savegame.hpp" #include "util/currenton.hpp" class World; @@ -28,7 +28,7 @@ class GameManager : public Currenton { private: std::unique_ptr m_world; - std::unique_ptr m_world_state; + std::unique_ptr m_savegame; public: GameManager(); diff --git a/src/supertux/game_session.cpp b/src/supertux/game_session.cpp index d0cc12711..77af3771a 100644 --- a/src/supertux/game_session.cpp +++ b/src/supertux/game_session.cpp @@ -40,12 +40,12 @@ #include "supertux/screen_fade.hpp" #include "supertux/screen_manager.hpp" #include "supertux/sector.hpp" -#include "supertux/world_state.hpp" +#include "supertux/savegame.hpp" #include "util/file_system.hpp" #include "util/gettext.hpp" #include "worldmap/worldmap.hpp" -GameSession::GameSession(const std::string& levelfile_, WorldState& world_state, Statistics* statistics) : +GameSession::GameSession(const std::string& levelfile_, Savegame& savegame, Statistics* statistics) : level(), statistics_backdrop(Surface::create("images/engine/menu/score-backdrop.png")), scripts(), @@ -61,7 +61,7 @@ GameSession::GameSession(const std::string& levelfile_, WorldState& world_state, newsector(), newspawnpoint(), best_level_statistics(statistics), - m_world_state(world_state), + m_savegame(savegame), capture_demo_stream(0), capture_file(), playback_demo_stream(0), @@ -81,7 +81,7 @@ GameSession::GameSession(const std::string& levelfile_, WorldState& world_state, int GameSession::restart_level() { - PlayerStatus* currentStatus = m_world_state.get_player_status(); + PlayerStatus* currentStatus = m_savegame.get_player_status(); coins_at_start = currentStatus->coins; bonus_at_start = currentStatus->bonus; max_fire_bullets_at_start = currentStatus->max_fire_bullets; @@ -257,7 +257,7 @@ GameSession::abort_level() MenuManager::instance().clear_menu_stack(); g_screen_manager->pop_screen(); currentsector->player->set_bonus(bonus_at_start); - PlayerStatus *currentStatus = m_world_state.get_player_status(); + PlayerStatus *currentStatus = m_savegame.get_player_status(); currentStatus->coins = coins_at_start; currentStatus->max_fire_bullets = max_fire_bullets_at_start; currentStatus->max_ice_bullets = max_ice_bullets_at_start; @@ -575,7 +575,7 @@ GameSession::start_sequence(const std::string& sequencename) void GameSession::drawstatus(DrawingContext& context) { - m_world_state.get_player_status()->draw(context); + m_savegame.get_player_status()->draw(context); // draw level stats while end_sequence is running if (end_sequence) { diff --git a/src/supertux/game_session.hpp b/src/supertux/game_session.hpp index 2d61b0e1a..725f5e050 100644 --- a/src/supertux/game_session.hpp +++ b/src/supertux/game_session.hpp @@ -34,7 +34,7 @@ class Menu; class PlayerStatus; class Sector; class Statistics; -class WorldState; +class Savegame; /** * Screen that runs a Level, where Players run and jump through Sectors. @@ -43,7 +43,7 @@ class GameSession : public Screen, public Currenton { public: - GameSession(const std::string& levelfile, WorldState& world_state, Statistics* statistics = NULL); + GameSession(const std::string& levelfile, Savegame& savegame, Statistics* statistics = NULL); ~GameSession(); void record_demo(const std::string& filename); @@ -93,7 +93,7 @@ public: */ void force_ghost_mode(); - WorldState& get_world_state() { return m_world_state; } + Savegame& get_savegame() { return m_savegame; } private: void check_end_conditions(); @@ -134,7 +134,7 @@ private: std::string newspawnpoint; Statistics* best_level_statistics; - WorldState& m_world_state; + Savegame& m_savegame; std::ostream* capture_demo_stream; std::string capture_file; diff --git a/src/supertux/main.cpp b/src/supertux/main.cpp index 75c754425..ddbac88b2 100644 --- a/src/supertux/main.cpp +++ b/src/supertux/main.cpp @@ -358,7 +358,7 @@ Main::run(int argc, char** argv) timelog(0); - const std::unique_ptr default_world_state(new WorldState); + const std::unique_ptr default_savegame(new Savegame(std::string())); GameManager game_manager; g_screen_manager = new ScreenManager(); @@ -381,10 +381,10 @@ Main::run(int argc, char** argv) g_config->start_level.compare(g_config->start_level.size() - 5, 5, ".stwm") == 0) { g_screen_manager->push_screen(std::unique_ptr( new worldmap::WorldMap( - FileSystem::basename(g_config->start_level), *default_world_state))); + FileSystem::basename(g_config->start_level), *default_savegame))); } else { std::unique_ptr session ( - new GameSession(FileSystem::basename(g_config->start_level), *default_world_state)); + new GameSession(FileSystem::basename(g_config->start_level), *default_savegame)); g_config->random_seed =session->get_demo_random_seed(g_config->start_demo); init_rand();//initialise generator with seed from session @@ -397,7 +397,7 @@ Main::run(int argc, char** argv) g_screen_manager->push_screen(std::move(session)); } } else { - g_screen_manager->push_screen(std::unique_ptr(new TitleScreen(*default_world_state))); + g_screen_manager->push_screen(std::unique_ptr(new TitleScreen(*default_savegame))); } g_screen_manager->run(context); diff --git a/src/supertux/menu/contrib_menu.cpp b/src/supertux/menu/contrib_menu.cpp index 8e2937f19..cf862bd41 100644 --- a/src/supertux/menu/contrib_menu.cpp +++ b/src/supertux/menu/contrib_menu.cpp @@ -54,14 +54,69 @@ ContribMenu::ContribMenu() : if (!world->hide_from_contribs()) { -#ifdef GRUMBEL - world->load_state(); -#endif + Savegame savegame(world->get_savegame_filename()); + savegame.load(); - 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)); + if (world->is_levelset()) + { + int level_count = 0; + int solved_count = 0; + + const auto& state = savegame.get_levelset_state(world->get_basedir()); + for(const auto& level_state : state.level_states) + { + if (level_state.solved) + { + solved_count += 1; + } + level_count += 1; + } + + std::ostringstream title; + title << "[" << world->get_title() << "]"; + if (level_count == 0) + { + title << " *NEW*"; + } + else + { + title << " (" << solved_count << "/" << level_count << ")"; + } + add_entry(i++, title.str()); + m_contrib_worlds.push_back(std::move(world)); + } + else if (world->is_worldmap()) + { + int level_count = 0; + int solved_count = 0; + + const auto& state = savegame.get_worldmap_state(world->get_worldmap_filename()); + for(const auto& level_state : state.level_states) + { + if (level_state.solved) + { + solved_count += 1; + } + level_count += 1; + } + + std::ostringstream title; + title << world->get_title(); + if (level_count == 0) + { + title << " *NEW*"; + } + else + { + title << " (" << solved_count << "/" << level_count << ")"; + } + add_entry(i++, title.str()); + m_contrib_worlds.push_back(std::move(world)); + } + else + { + log_warning << "unknown World type" << std::endl; + } } } catch(std::exception& e) @@ -84,17 +139,16 @@ ContribMenu::check_menu() int index = check(); if (index != -1) { - World* world = m_contrib_worlds[index].get(); + // reload the World so that we have something that we can safely + // std::move() around without wreaking the ContribMenu + std::unique_ptr world = World::load(m_contrib_worlds[index]->get_basedir()); if (!world->is_levelset()) { - // FIXME: not the most elegant of solutions to std::move() the - // World, but the ContribMenu should get destructed after this, - // so it might be ok - GameManager::current()->start_game(std::move(m_contrib_worlds[index])); + GameManager::current()->start_game(std::move(world)); } else { - MenuManager::instance().push_menu(std::unique_ptr(new ContribWorldMenu(std::move(m_contrib_worlds[index])))); + MenuManager::instance().push_menu(std::unique_ptr(new ContribWorldMenu(std::move(world)))); } } } diff --git a/src/supertux/savegame.cpp b/src/supertux/savegame.cpp new file mode 100644 index 000000000..ba2670cdf --- /dev/null +++ b/src/supertux/savegame.cpp @@ -0,0 +1,371 @@ +// SuperTux +// Copyright (C) 2006 Matthias Braun +// 2014 Ingo Ruhnke +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "supertux/savegame.hpp" + +#include "lisp/lisp.hpp" +#include "lisp/parser.hpp" +#include "lisp/writer.hpp" +#include "physfs/ifile_streambuf.hpp" +#include "scripting/serialize.hpp" +#include "scripting/squirrel_util.hpp" +#include "scripting/squirrel_util.hpp" +#include "supertux/player_status.hpp" +#include "util/file_system.hpp" +#include "util/log.hpp" +#include "worldmap/worldmap.hpp" + +namespace { + +void get_table_entry(HSQUIRRELVM vm, const std::string& name) +{ + sq_pushstring(vm, name.c_str(), -1); + if(SQ_FAILED(sq_get(vm, -2))) + { + throw std::runtime_error("failed to get '" + name + "' table entry"); + } + else + { + // successfully placed result on stack + } +} + +std::vector get_table_keys(HSQUIRRELVM vm) +{ + std::vector worlds; + + sq_pushnull(vm); + while(SQ_SUCCEEDED(sq_next(vm, -2))) + { + //here -1 is the value and -2 is the key + const char* result; + if(SQ_FAILED(sq_getstring(vm, -2, &result))) + { + std::ostringstream msg; + msg << "Couldn't get string value for key"; + throw scripting::SquirrelError(vm, msg.str()); + } + else + { + worlds.push_back(result); + } + + // pops key and val before the next iteration + sq_pop(vm, 2); + } + + return worlds; +} + +std::vector get_level_states(HSQUIRRELVM vm) +{ + std::vector results; + + sq_pushnull(vm); + while(SQ_SUCCEEDED(sq_next(vm, -2))) + { + //here -1 is the value and -2 is the key + const char* result; + if(SQ_FAILED(sq_getstring(vm, -2, &result))) + { + std::ostringstream msg; + msg << "Couldn't get string value"; + throw scripting::SquirrelError(vm, msg.str()); + } + else + { + LevelState level_state; + level_state.filename = result; + scripting::get_bool(vm, "solved", level_state.solved); + scripting::get_bool(vm, "perfect", level_state.perfect); + + results.push_back(level_state); + } + + // pops key and val before the next iteration + sq_pop(vm, 2); + } + + return results; +} + +} // namespace + +Savegame::Savegame(const std::string& filename) : + m_filename(filename), + m_player_status(new PlayerStatus) +{ +} + +Savegame::~Savegame() +{ +} + +void +Savegame::load() +{ + if (m_filename.empty()) + { + log_debug << "no filename set for savegame, skipping load" << std::endl; + return; + } + + if(!PHYSFS_exists(m_filename.c_str())) + { + log_info << m_filename << ": doesn't exist, not loading state" << std::endl; + } + else + { + log_debug << "loading savegame from " << m_filename << std::endl; + + try + { + HSQUIRRELVM vm = scripting::global_vm; + + lisp::Parser parser; + const lisp::Lisp* root = parser.parse(m_filename); + + const lisp::Lisp* lisp = root->get_lisp("supertux-savegame"); + if(lisp == NULL) + { + throw std::runtime_error("file is not a supertux-savegame file"); + } + else + { + int version = 1; + lisp->get("version", version); + if(version != 1) + { + throw std::runtime_error("incompatible savegame version"); + } + else + { + const lisp::Lisp* tux = lisp->get_lisp("tux"); + if(tux == NULL) + { + throw std::runtime_error("No tux section in savegame"); + } + { + m_player_status->read(*tux); + } + + const lisp::Lisp* state = lisp->get_lisp("state"); + if(state == NULL) + { + throw std::runtime_error("No state section in savegame"); + } + else + { + // delete existing state table, if it exists + sq_pushroottable(vm); + sq_pushstring(vm, "state", -1); + if(SQ_FAILED(sq_deleteslot(vm, -2, SQFalse))) + sq_pop(vm, 1); + + // create a new empty state table + sq_pushstring(vm, "state", -1); + sq_newtable(vm); + scripting::load_squirrel_table(vm, -1, *state); + if(SQ_FAILED(sq_createslot(vm, -3))) + throw std::runtime_error("Couldn't create state table"); + sq_pop(vm, 1); + } + } + } + } + catch(const std::exception& e) + { + log_fatal << "Couldn't load savegame: " << e.what() << std::endl; + } + } +} + +void +Savegame::save() +{ + if (m_filename.empty()) + { + log_debug << "no filename set for savegame, skipping save" << std::endl; + return; + } + + log_debug << "saving savegame to " << m_filename << std::endl; + + { // make sure the savegame directory exists + std::string dirname = FileSystem::dirname(m_filename); + if(!PHYSFS_exists(dirname.c_str())) + { + if(!PHYSFS_mkdir(dirname.c_str())) + { + std::ostringstream msg; + msg << "Couldn't create directory for savegames '" + << dirname << "': " <get_title(); + title << " (" << WorldMap::current()->solved_level_count() + << "/" << WorldMap::current()->level_count() << ")"; + writer.write("title", title.str()); + } + + writer.start_list("tux"); + m_player_status->write(writer); + writer.end_list("tux"); + + writer.start_list("state"); + + sq_pushroottable(vm); + sq_pushstring(vm, "state", -1); + if(SQ_SUCCEEDED(sq_get(vm, -2))) + { + scripting::save_squirrel_table(vm, -1, writer); + sq_pop(vm, 1); + } + sq_pop(vm, 1); + writer.end_list("state"); + + writer.end_list("supertux-savegame"); +} + +std::vector +Savegame::get_worldmaps() +{ + std::vector worlds; + + HSQUIRRELVM vm = scripting::global_vm; + int oldtop = sq_gettop(vm); + + try + { + sq_pushroottable(vm); + get_table_entry(vm, "state"); + get_table_entry(vm, "worlds"); + worlds = get_table_keys(vm); + } + catch(const std::exception& err) + { + log_warning << err.what() << std::endl; + } + + sq_settop(vm, oldtop); + + return worlds; +} + +WorldmapState +Savegame::get_worldmap_state(const std::string& name) +{ + WorldmapState result; + + HSQUIRRELVM vm = scripting::global_vm; + int oldtop = sq_gettop(vm); + + try + { + sq_pushroottable(vm); + get_table_entry(vm, "state"); + get_table_entry(vm, "worlds"); + get_table_entry(vm, name); + get_table_entry(vm, "levels"); + + result.level_states = get_level_states(vm); + } + catch(const std::exception& err) + { + log_warning << err.what() << std::endl; + } + + sq_settop(vm, oldtop); + + return result; +} + +std::vector +Savegame::get_levelsets() +{ + std::vector results; + + HSQUIRRELVM vm = scripting::global_vm; + int oldtop = sq_gettop(vm); + + try + { + sq_pushroottable(vm); + get_table_entry(vm, "state"); + get_table_entry(vm, "levelsets"); + results = get_table_keys(vm); + } + catch(const std::exception& err) + { + log_warning << err.what() << std::endl; + } + + sq_settop(vm, oldtop); + + return results; +} + +LevelsetState +Savegame::get_levelset_state(const std::string& name) +{ + LevelsetState result; + + HSQUIRRELVM vm = scripting::global_vm; + int oldtop = sq_gettop(vm); + + try + { + sq_pushroottable(vm); + get_table_entry(vm, "state"); + get_table_entry(vm, "levelsets"); + get_table_entry(vm, name); + get_table_entry(vm, "levels"); + + result.level_states = get_level_states(vm); + } + catch(const std::exception& err) + { + log_warning << err.what() << std::endl; + } + + sq_settop(vm, oldtop); + + return result; +} + +/* EOF */ diff --git a/src/supertux/savegame.hpp b/src/supertux/savegame.hpp new file mode 100644 index 000000000..7c11a0d41 --- /dev/null +++ b/src/supertux/savegame.hpp @@ -0,0 +1,125 @@ +// SuperTux +// Copyright (C) 2006 Matthias Braun +// 2014 Ingo Ruhnke +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef HEADER_SUPERTUX_SUPERTUX_SAVEGAME_HPP +#define HEADER_SUPERTUX_SUPERTUX_SAVEGAME_HPP + +#include +#include +#include + +class PlayerStatus; + +struct LevelState +{ +public: + LevelState() : + filename(), + solved(false), + perfect(false) + {} + + std::string filename; + bool solved; + bool perfect; +}; + +struct LevelsetState +{ +public: + LevelsetState() : + directory(), + level_states() + {} + std::string directory; + std::vector level_states; +}; + +struct WorldmapState +{ +public: + WorldmapState() : + filename(), + level_states() + {} + std::string filename; + std::vector level_states; +}; + +/** +(supertux-savegame + (version 1) + (title "Bonus Island II (0/28)") + (tux + (bonus "none") + (fireflowers 0) + (iceflowers 0) + (coins 110) + ) + (state + ("levelsets" + ("levels/test/" + ("levels" + ("level10.stl" + (perfect #f) + (solved #f) + ) + ("worlds" + ("levels/bonus2/worldmap.stwm" + ("tux" ....) + ("levels" + ("level10.stl" + (perfect #f) + (solved #f) + ) + ("level28.stl" + (perfect #f) + (solved #f) + ) + */ +class Savegame +{ +private: + std::string m_filename; + std::unique_ptr m_player_status; + +public: + Savegame(const std::string& filename); + ~Savegame(); + + /** Returns content of (tux ...) entry */ + PlayerStatus* get_player_status() const { return m_player_status.get(); } + + std::string get_title() const; + + std::vector get_levelsets(); + LevelsetState get_levelset_state(const std::string& name); + + std::vector get_worldmaps(); + WorldmapState get_worldmap_state(const std::string& name); + + void save(); + void load(); + +private: + Savegame(const Savegame&) = delete; + Savegame& operator=(const Savegame&) = delete; +}; + +#endif + +/* EOF */ diff --git a/src/supertux/sector.cpp b/src/supertux/sector.cpp index 1cbffc6af..333a73778 100644 --- a/src/supertux/sector.cpp +++ b/src/supertux/sector.cpp @@ -54,7 +54,7 @@ #include "supertux/level.hpp" #include "supertux/object_factory.hpp" #include "supertux/player_status.hpp" -#include "supertux/world_state.hpp" +#include "supertux/savegame.hpp" #include "supertux/spawn_point.hpp" #include "supertux/tile.hpp" #include "trigger/sequence_trigger.hpp" @@ -86,7 +86,7 @@ Sector::Sector(Level* parent) : camera(0), effect(0) { - add_object(new Player(GameSession::current()->get_world_state().get_player_status(), "Tux")); + add_object(new Player(GameSession::current()->get_savegame().get_player_status(), "Tux")); add_object(new DisplayEffect("Effect")); add_object(new TextObject("Text")); diff --git a/src/supertux/title_screen.cpp b/src/supertux/title_screen.cpp index 8488bff42..ec22c8bf6 100644 --- a/src/supertux/title_screen.cpp +++ b/src/supertux/title_screen.cpp @@ -40,14 +40,14 @@ #include #include -TitleScreen::TitleScreen(WorldState& world_state) : +TitleScreen::TitleScreen(Savegame& savegame) : frame(), controller(), titlesession(), copyright_text() { controller.reset(new CodeController()); - titlesession.reset(new GameSession("levels/misc/menu.stl", world_state)); + titlesession.reset(new GameSession("levels/misc/menu.stl", savegame)); Player* player = titlesession->get_current_sector()->player; player->set_controller(controller.get()); diff --git a/src/supertux/title_screen.hpp b/src/supertux/title_screen.hpp index 40c6d86b4..65f68ea6f 100644 --- a/src/supertux/title_screen.hpp +++ b/src/supertux/title_screen.hpp @@ -27,7 +27,7 @@ class ContribWorldMenu; class Menu; class PlayerStatus; class World; -class WorldState; +class Savegame; /** * Screen that displays the SuperTux logo, lets players start a new game, etc. @@ -35,7 +35,7 @@ class WorldState; class TitleScreen : public Screen { public: - TitleScreen(WorldState& world_state); + TitleScreen(Savegame& savegame); virtual ~TitleScreen(); virtual void setup(); diff --git a/src/supertux/world.cpp b/src/supertux/world.cpp index 02c5b15a1..b6734cc76 100644 --- a/src/supertux/world.cpp +++ b/src/supertux/world.cpp @@ -27,7 +27,7 @@ #include "supertux/screen_fade.hpp" #include "supertux/screen_manager.hpp" #include "supertux/world.hpp" -#include "supertux/world_state.hpp" +#include "supertux/savegame.hpp" #include "util/file_system.hpp" #include "util/reader.hpp" #include "util/string_util.hpp" @@ -60,12 +60,10 @@ World::World() : m_hide_from_contribs(false), m_is_levelset(true) { - std::cout << this << " World()" << std::endl; } World::~World() { - std::cout << this << " ~World()" << std::endl; } void diff --git a/src/supertux/world.hpp b/src/supertux/world.hpp index 47bf2dc1f..6ce0ab17b 100644 --- a/src/supertux/world.hpp +++ b/src/supertux/world.hpp @@ -22,10 +22,9 @@ #include #include -#include "util/currenton.hpp" -#include "supertux/world_state.hpp" +#include "supertux/savegame.hpp" -class World : public Currenton +class World { private: World(); diff --git a/src/supertux/world_state.cpp b/src/supertux/world_state.cpp deleted file mode 100644 index fc927d615..000000000 --- a/src/supertux/world_state.cpp +++ /dev/null @@ -1,243 +0,0 @@ -// SuperTux -// Copyright (C) 2006 Matthias Braun -// 2014 Ingo Ruhnke -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#include "supertux/world_state.hpp" - -#include "lisp/lisp.hpp" -#include "lisp/parser.hpp" -#include "lisp/writer.hpp" -#include "physfs/ifile_streambuf.hpp" -#include "scripting/serialize.hpp" -#include "scripting/squirrel_util.hpp" -#include "supertux/player_status.hpp" -#include "util/file_system.hpp" -#include "util/log.hpp" -#include "worldmap/worldmap.hpp" - -WorldState::WorldState() : - m_player_status(new PlayerStatus) -{ -} - -void -WorldState::load(const std::string& filename) -{ - if(!PHYSFS_exists(filename.c_str())) - { - log_info << filename << ": doesn't exist, not loading state" << std::endl; - } - else - { - try - { - HSQUIRRELVM vm = scripting::global_vm; - - lisp::Parser parser; - const lisp::Lisp* root = parser.parse(filename); - - const lisp::Lisp* lisp = root->get_lisp("supertux-savegame"); - if(lisp == NULL) - { - throw std::runtime_error("file is not a supertux-savegame file"); - } - else - { - int version = 1; - lisp->get("version", version); - if(version != 1) - { - throw std::runtime_error("incompatible savegame version"); - } - else - { - const lisp::Lisp* tux = lisp->get_lisp("tux"); - if(tux == NULL) - { - throw std::runtime_error("No tux section in savegame"); - } - { - m_player_status->read(*tux); - } - - const lisp::Lisp* state = lisp->get_lisp("state"); - if(state == NULL) - { - throw std::runtime_error("No state section in savegame"); - } - else - { - // delete existing state table, if it exists - sq_pushroottable(vm); - sq_pushstring(vm, "state", -1); - if(SQ_FAILED(sq_deleteslot(vm, -2, SQFalse))) - sq_pop(vm, 1); - - // create a new empty state table - sq_pushstring(vm, "state", -1); - sq_newtable(vm); - scripting::load_squirrel_table(vm, -1, *state); - if(SQ_FAILED(sq_createslot(vm, -3))) - throw std::runtime_error("Couldn't create state table"); - sq_pop(vm, 1); - } - } - } - } - catch(const std::exception& e) - { - log_fatal << "Couldn't load savegame: " << e.what() << std::endl; - } - } -} - -void -WorldState::save(const std::string& filename) -{ - { // make sure the savegame directory exists - std::string dirname = FileSystem::dirname(filename); - if(!PHYSFS_exists(dirname.c_str())) - { - if(!PHYSFS_mkdir(dirname.c_str())) - { - std::ostringstream msg; - msg << "Couldn't create directory for savegames '" - << dirname << "': " <get_title(); - title << " (" << WorldMap::current()->solved_level_count() - << "/" << WorldMap::current()->level_count() << ")"; - writer.write("title", title.str()); - } - - writer.start_list("tux"); - m_player_status->write(writer); - writer.end_list("tux"); - - writer.start_list("state"); - - sq_pushroottable(vm); - sq_pushstring(vm, "state", -1); - if(SQ_SUCCEEDED(sq_get(vm, -2))) - { - scripting::save_squirrel_table(vm, -1, writer); - sq_pop(vm, 1); - } - sq_pop(vm, 1); - writer.end_list("state"); - - writer.end_list("supertux-savegame"); -} - -int -WorldState::get_num_levels() const -{ -#ifdef GRUMBEL -#endif - return 5; -} - -int -WorldState::get_num_solved_levels() const -{ - return 3; -#ifdef GRUMBEL - 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, m_worldmap_filename.c_str(), -1); - if(SQ_FAILED(sq_get(vm, -2))) - { - log_warning << "failed to get state.worlds['" << m_worldmap_filename << "']" << std::endl; - } - else - { - sq_pushstring(vm, "levels", -1); - if(SQ_FAILED(sq_get(vm, -2))) - { - log_warning << "failed to get state.worlds['" << m_worldmap_filename << "'].levels" << std::endl; - } - else - { - for(auto level : m_levels) - { - sq_pushstring(vm, level.c_str(), -1); - if(SQ_FAILED(sq_get(vm, -2))) - { - log_warning << "failed to get state.worlds['" << m_worldmap_filename << "'].levels['" - << level << "']" << 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; -#endif -} - -/* EOF */ diff --git a/src/supertux/world_state.hpp b/src/supertux/world_state.hpp deleted file mode 100644 index d78d9d512..000000000 --- a/src/supertux/world_state.hpp +++ /dev/null @@ -1,49 +0,0 @@ -// SuperTux -// Copyright (C) 2006 Matthias Braun -// 2014 Ingo Ruhnke -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#ifndef HEADER_SUPERTUX_SUPERTUX_WORLD_STATE_HPP -#define HEADER_SUPERTUX_SUPERTUX_WORLD_STATE_HPP - -#include -#include - -class PlayerStatus; - -class WorldState -{ -private: - std::unique_ptr m_player_status; - -public: - WorldState(); - - PlayerStatus* get_player_status() const { return m_player_status.get(); } - - int get_num_levels() const; - int get_num_solved_levels() const; - - void save(const std::string& filename); - void load(const std::string& filename); - -private: - WorldState(const WorldState&) = delete; - WorldState& operator=(const WorldState&) = delete; -}; - -#endif - -/* EOF */ diff --git a/src/worldmap/tux.cpp b/src/worldmap/tux.cpp index eda5b4f71..c76af1cd3 100644 --- a/src/worldmap/tux.cpp +++ b/src/worldmap/tux.cpp @@ -21,7 +21,7 @@ #include "sprite/sprite_manager.hpp" #include "supertux/globals.hpp" #include "supertux/player_status.hpp" -#include "supertux/world_state.hpp" +#include "supertux/savegame.hpp" #include "supertux/tile.hpp" #include "worldmap/level.hpp" #include "worldmap/tux.hpp" @@ -60,7 +60,7 @@ Tux::~Tux() void Tux::draw(DrawingContext& context) { - switch (worldmap->get_world_state().get_player_status()->bonus) { + switch (worldmap->get_savegame().get_player_status()->bonus) { case GROWUP_BONUS: sprite->set_action(moving ? "large-walking" : "large-stop"); break; diff --git a/src/worldmap/worldmap.cpp b/src/worldmap/worldmap.cpp index 998695fd5..60dc77967 100644 --- a/src/worldmap/worldmap.cpp +++ b/src/worldmap/worldmap.cpp @@ -59,7 +59,7 @@ #include "supertux/tile_manager.hpp" #include "supertux/tile_set.hpp" #include "supertux/world.hpp" -#include "supertux/world_state.hpp" +#include "supertux/savegame.hpp" #include "util/file_system.hpp" #include "util/gettext.hpp" #include "util/log.hpp" @@ -78,9 +78,9 @@ namespace worldmap { WorldMap* WorldMap::current_ = NULL; -WorldMap::WorldMap(const std::string& filename, WorldState& world_state, const std::string& force_spawnpoint) : +WorldMap::WorldMap(const std::string& filename, Savegame& savegame, const std::string& force_spawnpoint) : tux(), - m_world_state(world_state), + m_savegame(savegame), tileset(NULL), free_tileset(false), camera_offset(), @@ -240,7 +240,7 @@ void WorldMap::change(const std::string& filename, const std::string& force_spawnpoint) { g_screen_manager->pop_screen(); - g_screen_manager->push_screen(std::unique_ptr(new WorldMap(filename, m_world_state, force_spawnpoint))); + g_screen_manager->push_screen(std::unique_ptr(new WorldMap(filename, m_savegame, force_spawnpoint))); } void @@ -695,7 +695,7 @@ WorldMap::update(float delta) // update state and savegame save_state(); - g_screen_manager->push_screen(std::unique_ptr(new GameSession(levelfile, m_world_state, &level->statistics)), + g_screen_manager->push_screen(std::unique_ptr(new GameSession(levelfile, m_savegame, &level->statistics)), std::unique_ptr(new ShrinkFade(shrinkpos, 1.0f))); in_level = true; } catch(std::exception& e) { @@ -830,7 +830,7 @@ WorldMap::draw_status(DrawingContext& context) context.push_transform(); context.set_translation(Vector(0, 0)); - m_world_state.get_player_status()->draw(context); + m_savegame.get_player_status()->draw(context); if (!tux->is_moving()) { for(LevelTiles::iterator i = levels.begin(); i != levels.end(); ++i) { @@ -1032,16 +1032,7 @@ WorldMap::save_state() sq_settop(vm, oldtop); - if (!World::current()) - { - log_fatal << "no World::current(), so can't savegame" << std::endl; - } - else - { -#ifdef GRUMBEL - m_world_state->save_state(); -#endif - } + m_savegame.save(); } void diff --git a/src/worldmap/worldmap.hpp b/src/worldmap/worldmap.hpp index db0749c6e..d0d15d576 100644 --- a/src/worldmap/worldmap.hpp +++ b/src/worldmap/worldmap.hpp @@ -41,7 +41,7 @@ class GameObject; class PlayerStatus; class Sprite; class TileMap; -class WorldState; +class Savegame; namespace worldmap { @@ -78,7 +78,7 @@ private: Tux* tux; - WorldState& m_world_state; + Savegame& m_savegame; TileSet *tileset; bool free_tileset; @@ -124,7 +124,7 @@ private: bool panning; public: - WorldMap(const std::string& filename, WorldState& world_state, const std::string& force_spawnpoint = ""); + WorldMap(const std::string& filename, Savegame& savegame, const std::string& force_spawnpoint = ""); ~WorldMap(); void add_object(GameObject* object); @@ -169,7 +169,7 @@ public: /** returns current Tux incarnation */ Tux* get_tux() { return tux; } - WorldState& get_world_state() { return m_world_state; } + Savegame& get_savegame() { return m_savegame; } LevelTile* at_level(); SpecialTile* at_special_tile();