home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 February / maximum-cd-2009-02.iso / DiscContents / SMC_1.6_win32.exe / src / user / savegame.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2008-07-01  |  24.9 KB  |  916 lines

  1. /***************************************************************************
  2.  * savegame.cpp  -  Savegame handler
  3.  *
  4.  * Copyright (C) 2003 - 2008 Florian Richter
  5.  ***************************************************************************/
  6. /*
  7.    This program is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 3 of the License, or
  10.    (at your option) any later version.
  11.    
  12.    You should have received a copy of the GNU General Public License
  13.    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  14. */
  15.  
  16. #include "../core/globals.h"
  17. #include "../user/savegame.h"
  18. #include "../user/preferences.h"
  19. #include "../core/game_core.h"
  20. #include "../core/camera.h"
  21. #include "../core/obj_manager.h"
  22. #include "../level/level.h"
  23. #include "../overworld/world_manager.h"
  24. #include "../player/player.h"
  25. #include "../overworld/overworld.h"
  26. #include "../core/sprite_manager.h"
  27. #include "../core/i18n.h"
  28.  
  29. /* *** *** *** *** *** *** *** cSave_Overworld_Waypoint *** *** *** *** *** *** *** *** *** *** */
  30.  
  31. cSave_Overworld_Waypoint :: cSave_Overworld_Waypoint( void )
  32. {
  33.     access = 0;
  34. }
  35.  
  36. cSave_Overworld_Waypoint :: ~cSave_Overworld_Waypoint( void )
  37. {
  38.     
  39. }
  40.  
  41. /* *** *** *** *** *** *** *** cSave_Overworld *** *** *** *** *** *** *** *** *** *** */
  42.  
  43. cSave_Overworld :: cSave_Overworld( void )
  44. {
  45.     
  46. }
  47.  
  48. cSave_Overworld :: ~cSave_Overworld( void )
  49. {
  50.     for( unsigned int i = 0; i < Waypoints.size(); i++ )
  51.     {
  52.         delete Waypoints[i];
  53.     }
  54.  
  55.     Waypoints.clear();
  56. }
  57.  
  58. /* *** *** *** *** *** *** *** cSave_Level_Object *** *** *** *** *** *** *** *** *** *** */
  59.  
  60. cSave_Level_Object_Property :: cSave_Level_Object_Property( string nName /* = "" */, string nValue /* = "" */ )
  61. {
  62.     Name = nName;
  63.     Value = nValue;
  64. }
  65.  
  66. /* *** *** *** *** *** *** *** cSave_Level_Object *** *** *** *** *** *** *** *** *** *** */
  67.  
  68. cSave_Level_Object :: cSave_Level_Object( void )
  69. {
  70.     type = TYPE_UNDEFINED;
  71. }
  72.  
  73. cSave_Level_Object :: ~cSave_Level_Object( void )
  74. {
  75.     properties.clear();
  76. }
  77.  
  78. bool cSave_Level_Object :: exists( string val_name )
  79. {
  80.     for( unsigned int i = 0; i < properties.size(); i++ )
  81.     {
  82.         if( properties[i].Name.compare( val_name ) == 0 )
  83.         {
  84.             // found
  85.             return 1;
  86.         }
  87.     }
  88.  
  89.     // not found
  90.     return 0;
  91. }
  92.  
  93. string cSave_Level_Object :: Get_Value( string val_name )
  94. {
  95.     for( unsigned int i = 0; i < properties.size(); i++ )
  96.     {
  97.         if( properties[i].Name.compare( val_name ) == 0 )
  98.         {
  99.             // found
  100.             return properties[i].Value;
  101.         }
  102.     }
  103.  
  104.     // not found
  105.     return "";
  106. }
  107.  
  108. /* *** *** *** *** *** *** *** cSave *** *** *** *** *** *** *** *** *** *** */
  109.  
  110. cSave :: cSave( void )
  111. {
  112.     Clear();
  113. }
  114.  
  115. cSave :: ~cSave( void )
  116. {
  117.     Clear();
  118. }
  119.  
  120. void cSave :: Clear( void )
  121. {
  122.     // save
  123.     description.clear();
  124.     save_time = 0;
  125.     version = 0;
  126.  
  127.     // player
  128.     lives = 0;
  129.     points = 0;
  130.     goldpieces = 0;
  131.     player_type = 0;
  132.     player_state = 0;
  133.     itembox_item = 0;
  134.     
  135.     // level
  136.     level_name.clear();
  137.     level_posx = 0;
  138.     level_posy = 0;
  139.  
  140.     for( unsigned int i = 0; i < level_objects.size(); i++ )
  141.     {
  142.         delete level_objects[i];
  143.     }
  144.  
  145.     level_objects.clear();
  146.  
  147.     // overworld
  148.     overworld_active.clear();
  149.     overworld_current_waypoint = 0;
  150.  
  151.     for( unsigned int i = 0; i < Overworlds.size(); i++ )
  152.     {
  153.         delete Overworlds[i];
  154.     }
  155.  
  156.     Overworlds.clear();
  157. }
  158.  
  159. cSavegame :: cSavegame( void )
  160. {
  161.     error_count = 0;
  162.     save_temp = NULL;
  163.     debug = 0;
  164.  
  165.     savegame_dir = user_data_dir + USER_SAVEGAME_DIR;
  166. }
  167.  
  168. cSavegame :: ~cSavegame( void )
  169. {
  170.     //
  171. }
  172.  
  173. int cSavegame :: Load_Game( unsigned int save_slot )
  174. {
  175.     cSave *savegame = Load( save_slot );
  176.     
  177.     // check if unsupported save
  178.     if( savegame->version <= SAVEGAME_VERSION_UNSUPPORTED )
  179.     {
  180.         printf( "Warning : Savegame %d : Versions %d and below are unsupported\n", save_slot, SAVEGAME_VERSION_UNSUPPORTED );
  181.     }
  182.  
  183.     // level available
  184.     if( savegame->level_name.length() )
  185.     {
  186.         string level_name = savegame->level_name;
  187.  
  188.         // level not found
  189.         if( !pActive_Level->Get_Path( level_name ) )
  190.         {
  191.             printf( "Warning : Savegame %d : Level not found : %s\n", save_slot, level_name.c_str() );
  192.         }
  193.     }
  194.  
  195.     // unload level
  196.     pActive_Level->Unload();
  197.     // reset player
  198.     pPlayer->Reset_Save();
  199.  
  200.     // #### Overworld ####
  201.  
  202.     // if no overworld is set
  203.     if( savegame->Overworlds.size() == 0 )
  204.     {
  205.         // Use first Overworld
  206.         cSave_Overworld *save_overworld = new cSave_Overworld();
  207.         save_overworld->name = pOverworld_Manager->Get_Pointer( 0 )->description->path;
  208.  
  209.         savegame->Overworlds.push_back( save_overworld );
  210.     }
  211.     // set overworld progress
  212.     else
  213.     {
  214.         for( Save_OverworldList::iterator itr = savegame->Overworlds.begin(), itr_end = savegame->Overworlds.end(); itr != itr_end; ++itr )
  215.         {
  216.             // get savegame overworld pointer
  217.             cSave_Overworld *save_overworld = (*itr);
  218.  
  219.             // get overworld
  220.             cOverworld *overworld = pOverworld_Manager->Get_from_Name( save_overworld->name );
  221.  
  222.             if( !overworld )
  223.             {
  224.                 printf( "Warning : Savegame %d : Overworld %s not found\n", save_slot, save_overworld->name.c_str() );
  225.                 continue;
  226.             }
  227.  
  228.             for( Save_Overworld_WaypointList::iterator wp_itr = save_overworld->Waypoints.begin(), wp_itr_end = save_overworld->Waypoints.end(); wp_itr != wp_itr_end; ++wp_itr )
  229.             {
  230.                 // get savegame waypoint pointer
  231.                 cSave_Overworld_Waypoint *save_waypoint = (*wp_itr);
  232.  
  233.                 // get overworld waypoint
  234.                 cWaypoint *waypoint = overworld->Get_Waypoint( overworld->Get_Waypoint_Num( save_waypoint->destination ) );
  235.  
  236.                 // not found
  237.                 if( !waypoint )
  238.                 {
  239.                     printf( "Warning : Savegame %d : Overworld %s Waypoint %s not found\n", save_slot, save_overworld->name.c_str(), save_waypoint->destination.c_str() );
  240.                     continue;
  241.                 }
  242.  
  243.                 // set access
  244.                 waypoint->Set_Access( save_waypoint->access );
  245.             }
  246.         }
  247.     }
  248.  
  249.     // Set Active Overworld
  250.     if( !pOverworld_Manager->Set_Active( savegame->overworld_active ) )
  251.     {
  252.         printf( "Warning : Savegame %d : Couldn't set Overworld active %s\n", save_slot, savegame->overworld_active.c_str() );
  253.     }
  254.  
  255.     // Current Waypoint
  256.     if( !pOverworld_Player->Set_Waypoint( savegame->overworld_current_waypoint ) )
  257.     {
  258.         printf( "Warning : Savegame %d : Overworld Current Waypoint %d is invalid\n", save_slot, savegame->overworld_current_waypoint );
  259.     }
  260.  
  261.  
  262.     // #### Player ####
  263.  
  264.     // below version 8 the sate was the type
  265.     if( savegame->version < 8 )
  266.     {
  267.         // type
  268.         pPlayer->Set_Type( (Maryo_type)savegame->player_state, 0, 0 );
  269.     }
  270.     else
  271.     {
  272.         // type
  273.         pPlayer->Set_Type( (Maryo_type)savegame->player_type, 0, 0 );
  274.         // state
  275.         pPlayer->state = (Moving_state)savegame->player_state;
  276.     }
  277.  
  278.  
  279.     // in a level
  280.     if( !savegame->level_name.empty() )
  281.     {
  282.         // load level
  283.         if( pActive_Level->Load( savegame->level_name ) )
  284.         {
  285.             // position
  286.             pPlayer->Set_Pos( savegame->level_posx, savegame->level_posy - static_cast<float>(game_res_h) );
  287.  
  288.             // Level Objects
  289.             for( Save_Level_ObjectList::iterator itr = savegame->level_objects.begin(), itr_end = savegame->level_objects.end(); itr != itr_end; ++itr )
  290.             {
  291.                 // get object pointer
  292.                 cSave_Level_Object *save_object = (*itr);
  293.  
  294.                 // get position
  295.                 int posx = string_to_int( save_object->Get_Value( "posx" ) );
  296.                 int posy = string_to_int( save_object->Get_Value( "posy" ) );
  297.  
  298.                 // get level object
  299.                 cSprite *level_object = pActive_Level->pSprite_Manager->Get_from_Position( posx, posy, save_object->type );
  300.  
  301.                 // if not anymore available
  302.                 if( !level_object )
  303.                 {
  304.                     printf( "Warning : Savegame object type %d on x %d, y %d not available\n", save_object->type, posx, posy );
  305.                     continue;
  306.                 }
  307.  
  308.                 level_object->Load_from_Savegame( save_object );
  309.             }
  310.  
  311.             // invincible for a second
  312.             pPlayer->invincible = speedfactor_fps;
  313.         }
  314.         else
  315.         {
  316.             printf( "Error : Couldn't load Savegame Level %s\n", savegame->level_name.c_str() );
  317.         }
  318.     }
  319.     
  320.     pointsdisplay->Set_Points( savegame->points );
  321.     golddisplay->Set_Gold( savegame->goldpieces );
  322.     livedisplay->Set_Lives( savegame->lives );
  323.     Itembox->Set_Item( (SpriteType)savegame->itembox_item, 0 );
  324.  
  325.     pActive_Camera->Center();
  326.  
  327.     pHud_Manager->Update();
  328.  
  329.     debugdisplay->Set_Text( _("Savegame ") + int_to_string( save_slot ) + _(" loaded") );
  330.  
  331.     // default is level save
  332.     int retval = 1;
  333.  
  334.     // if Overworld Save
  335.     if( savegame->level_name.empty() )
  336.     {
  337.         retval = 2;
  338.     }
  339.  
  340.     delete savegame;
  341.     return retval;
  342. }
  343.  
  344. bool cSavegame :: Save_Game( unsigned int save_slot, string description )
  345. {
  346.     if( pPlayer->maryo_type == MARYO_DEAD || pPlayer->lives < 0 )
  347.     {
  348.         printf( "Error : Couldn't save savegame %s because of invalid game state\n", description.c_str() );
  349.         return 0;
  350.     }
  351.  
  352.     cSave *savegame = new cSave();
  353.  
  354.     // Description
  355.     savegame->description = description;
  356.     // Goldpieces
  357.     savegame->goldpieces = pPlayer->goldpieces;
  358.  
  359.     // Level
  360.     if( pActive_Level->Is_Loaded() )
  361.     {
  362.         // name
  363.         savegame->level_name = Get_Filename( pActive_Level->data_file, 0, 0 );
  364.  
  365.         // position
  366.         savegame->level_posx = pPlayer->posx;
  367.         savegame->level_posy = pPlayer->posy + game_res_h - 5;
  368.  
  369.         // Level Objects
  370.         for( SpriteList::iterator itr = pActive_Level->pSprite_Manager->objects.begin(), itr_end = pActive_Level->pSprite_Manager->objects.end(); itr != itr_end; ++itr )
  371.         {
  372.             // get object pointer
  373.             cSprite *object = (*itr);
  374.  
  375.             // get save data
  376.             cSave_Level_Object *save_object = object->Save_to_Savegame();
  377.  
  378.             // nothing to save
  379.             if( !save_object )
  380.             {
  381.                 continue;
  382.             }
  383.  
  384.             // add
  385.             savegame->level_objects.push_back( save_object );
  386.         }
  387.     }
  388.  
  389.     // Lives
  390.     savegame->lives = pPlayer->lives;
  391.     // Points
  392.     savegame->points = pPlayer->points;
  393.  
  394.     // Player type
  395.     savegame->player_type = pPlayer->maryo_type;
  396.     // Player state
  397.     savegame->player_state = pPlayer->state;
  398.     // Itembox Item
  399.     savegame->itembox_item = Itembox->item_id;
  400.  
  401.     // save overworld progress
  402.     for( vector<cOverworld *>::iterator itr = pOverworld_Manager->objects.begin(), itr_end = pOverworld_Manager->objects.end(); itr != itr_end; ++itr )
  403.     {
  404.         // Get Overworld
  405.         cOverworld *overworld = (*itr);
  406.  
  407.         // create Overworld
  408.         cSave_Overworld *save_overworld = new cSave_Overworld();
  409.         // name
  410.         save_overworld->name = overworld->description->name;
  411.         
  412.         // Waypoints
  413.         for( SpriteList::iterator wp_itr = overworld->sprite_manager->objects.begin(), wp_itr_end = overworld->sprite_manager->objects.end(); wp_itr != wp_itr_end; ++wp_itr )
  414.         {
  415.             // get waypoint
  416.             cSprite *obj = static_cast<cSprite *>(*wp_itr);
  417.  
  418.             if( obj->type != TYPE_OW_WAYPOINT )
  419.             {
  420.                 continue;
  421.             }
  422.  
  423.             // get waypoint
  424.             cWaypoint *waypoint = static_cast<cWaypoint *>(obj);
  425.  
  426.             // create savegame waypoint
  427.             cSave_Overworld_Waypoint *save_waypoint = new cSave_Overworld_Waypoint();
  428.             
  429.             // destination
  430.             save_waypoint->destination = waypoint->Get_Destination();
  431.             // set access
  432.             save_waypoint->access = waypoint->access;
  433.             // save
  434.             save_overworld->Waypoints.push_back( save_waypoint );
  435.         }
  436.  
  437.         // save
  438.         savegame->Overworlds.push_back( save_overworld );
  439.     }
  440.  
  441.     // if an overworld active
  442.     if( pActive_Overworld )
  443.     {
  444.         // which OverWorld
  445.         savegame->overworld_active = pActive_Overworld->description->name;
  446.  
  447.         // if valid waypoint
  448.         if( pOverworld_Player->current_waypoint >= 0 )
  449.         {
  450.             // Overworld current Waypoint
  451.             savegame->overworld_current_waypoint = pOverworld_Player->current_waypoint;
  452.         }
  453.     }
  454.  
  455.     // Time ( seconds since 1970 )
  456.     savegame->save_time = time( NULL );
  457.     // Version
  458.     savegame->version = SAVEGAME_VERSION;
  459.  
  460.     // Save it
  461.     Save( save_slot, savegame );
  462.  
  463.     // Print
  464.     if( debugdisplay )
  465.     {
  466.         debugdisplay->Set_Text( _("Saved to Slot ") + int_to_string( save_slot ) );
  467.     }
  468.  
  469.     // Clear
  470.     delete savegame;
  471.  
  472.     return 1;
  473. }
  474.  
  475. cSave *cSavegame :: Load( unsigned int save_slot )
  476. {
  477.     save_temp = new cSave();
  478.  
  479.     string filename = savegame_dir + "/" + int_to_string( save_slot ) + ".save";
  480.  
  481.     if( !File_Exists( filename ) )
  482.     {
  483.         printf( "Error : Savegame Loading : No Savegame found at Slot : %s\n", filename.c_str() );
  484.         return save_temp;
  485.     }
  486.  
  487.     try
  488.     {
  489.         CEGUI::System::getSingleton().getXMLParser()->parseXMLFile( *this, filename.c_str(), DATA_DIR "/" GAME_SCHEMA_DIR "/Savegame.xsd", "" );
  490.     }
  491.     // catch CEGUI Exceptions
  492.     catch( CEGUI::Exception &ex )
  493.     {
  494.         printf( "Loading Savegame %s CEGUI Exception %s\n", filename.c_str(), ex.getMessage().c_str() );
  495.         debugdisplay->Set_Text( _("Savegame Loading failed : ") + (string)ex.getMessage().c_str() );
  496.     }
  497.  
  498.     // unknown savegame data found
  499.     if( error_count )
  500.     {
  501.         printf( "Warning : Savegame Loading : Errors found at Slot : %d\n", save_slot );
  502.         save_temp->description.insert( 0, _("Unsupported : ") );
  503.     }
  504.  
  505.     // if no description is available
  506.     if( !save_temp->description.length() )
  507.     {
  508.         save_temp->description = _("No Description");
  509.     }
  510.  
  511.     cSave *savegame =  save_temp;
  512.     save_temp = NULL;
  513.     return savegame;
  514. }
  515.  
  516. int cSavegame :: Save( unsigned int save_slot, cSave *savegame )
  517. {
  518.     string filename = savegame_dir + "/" + int_to_string( save_slot ) + ".save";
  519.  
  520.     if( File_Exists( filename ) )
  521.     {
  522.         ifstream ifs( filename.c_str(), ios::trunc ); // Delete existing
  523.         ifs.close();
  524.     }
  525.  
  526.     // empty overworld active
  527.     if( savegame->overworld_active.empty() )
  528.     {
  529.         printf( "Warning : Savegame %s saving : Empty Overworld Active\n", savegame->description.c_str() );
  530.     }
  531.  
  532.     ofstream file( filename.c_str(), ios::out );
  533.     
  534.     if( !file.is_open() )
  535.     {
  536.         printf( "Error : Couldn't open savegame file for saving. Is the file read-only ?" );
  537.         return 0;
  538.     }
  539.  
  540.     // xml info
  541.     file << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
  542.     // begin Savegame
  543.     file << "<Savegame>" << std::endl;
  544.  
  545.     // begin Information
  546.     file << "\t<Information>" << std::endl;
  547.         // Description
  548.         file << "\t\t<Property Name=\"description\" Value=\"" << savegame->description << "\" />" << std::endl;
  549.         // Version
  550.         file << "\t\t<Property Name=\"version\" Value=\"" << savegame->version << "\" />" << std::endl;
  551.         // Time
  552.         file << "\t\t<Property Name=\"save_time\" Value=\"" << savegame->save_time << "\" />" << std::endl;
  553.     // end Information
  554.     file << "\t</Information>" << std::endl;
  555.  
  556.     if( !savegame->level_name.empty() )
  557.     {
  558.         // begin Level
  559.         file << "\t<Level>" << std::endl;
  560.  
  561.         // Level name
  562.         file << "\t\t<Property Name=\"level_name\" Value=\"" << savegame->level_name << "\" />" << std::endl;
  563.         // Level position
  564.         file << "\t\t<Property Name=\"player_posx\" Value=\"" << savegame->level_posx << "\" />" << std::endl;
  565.         file << "\t\t<Property Name=\"player_posy\" Value=\"" << savegame->level_posy << "\" />" << std::endl;
  566.  
  567.         // Level Objects
  568.         for( Save_Level_ObjectList::iterator itr = savegame->level_objects.begin(), itr_end = savegame->level_objects.end(); itr != itr_end; ++itr )
  569.         {
  570.             // get object pointer
  571.             cSave_Level_Object *object = (*itr);
  572.  
  573.             // begin Level Object
  574.             file << "\t\t<Level_Object>" << std::endl;
  575.  
  576.             // Object type
  577.             file << "\t\t\t<Property Name=\"type\" Value=\"" << object->type << "\" />" << std::endl;
  578.  
  579.             // Properties
  580.             for( Save_Level_Object_ProprtyList::iterator prop_itr = object->properties.begin(), prop_itr_end = object->properties.end(); prop_itr != prop_itr_end; ++prop_itr )
  581.             {
  582.                 // get properties pointer
  583.                 cSave_Level_Object_Property Property = (*prop_itr);
  584.  
  585.                 // property
  586.                 file << "\t\t\t<Property Name=\"" << Property.Name <<"\" Value=\"" << Property.Value << "\" />" << std::endl;
  587.             }
  588.  
  589.             // end Level Object
  590.             file << "\t\t</Level_Object>" << std::endl;
  591.         }
  592.         // end Level
  593.         file << "\t</Level>" << std::endl;
  594.     }
  595.  
  596.     // begin Player
  597.     file << "\t<Player>" << std::endl;
  598.         // Lives
  599.         file << "\t\t<Property Name=\"lives\" Value=\"" << savegame->lives << "\" />" << std::endl;
  600.         // Points
  601.         file << "\t\t<Property Name=\"points\" Value=\"" << savegame->points << "\" />" << std::endl;
  602.         // Goldpieces
  603.         file << "\t\t<Property Name=\"goldpieces\" Value=\"" << savegame->goldpieces << "\" />" << std::endl;
  604.         // type
  605.         file << "\t\t<Property Name=\"type\" Value=\"" << savegame->player_type << "\" />" << std::endl;
  606.         // state
  607.         file << "\t\t<Property Name=\"state\" Value=\"" << savegame->player_state << "\" />" << std::endl;
  608.         // Itembox item
  609.         file << "\t\t<Property Name=\"itembox_item\" Value=\"" << savegame->itembox_item << "\" />" << std::endl;
  610.     // end Player
  611.     file << "\t</Player>" << std::endl;
  612.  
  613.     // begin Overworld_Data
  614.     file << "\t<Overworld_Data>" << std::endl;
  615.         // active Overworld
  616.         file << "\t\t<Property Name=\"active\" Value=\"" << savegame->overworld_active << "\" />" << std::endl;
  617.         // current Overworld Waypoint
  618.         file << "\t\t<Property Name=\"current_waypoint\" Value=\"" << savegame->overworld_current_waypoint << "\" />" << std::endl;
  619.     // end Overworld_Data
  620.     file << "\t</Overworld_Data>" << std::endl;
  621.  
  622.     // Overworlds
  623.     for( Save_OverworldList::iterator itr = savegame->Overworlds.begin(), itr_end = savegame->Overworlds.end(); itr != itr_end; ++itr )
  624.     {
  625.         // get object pointer
  626.         cSave_Overworld *overworld = (*itr);
  627.  
  628.         // begin Overworld
  629.         file << "\t<Overworld>" << std::endl;
  630.  
  631.         // current Overworld
  632.         file << "\t\t<Property Name=\"name\" Value=\"" << overworld->name << "\" />" << std::endl;
  633.  
  634.         for( Save_Overworld_WaypointList::iterator wp_itr = overworld->Waypoints.begin(), wp_itr_end = overworld->Waypoints.end(); wp_itr != wp_itr_end; ++wp_itr )
  635.         {
  636.             // get object pointer
  637.             cSave_Overworld_Waypoint *overworld_waypoint = (*wp_itr);
  638.  
  639.             // skip empty waypoints
  640.             if( overworld_waypoint->destination.empty() )
  641.             {
  642.                 continue;
  643.             }
  644.  
  645.             // begin Overworld Level
  646.             file << "\t\t<Overworld_Level>" << std::endl;
  647.  
  648.             // destination
  649.             file << "\t\t\t<Property Name=\"destination\" Value=\"" << overworld_waypoint->destination << "\" />" << std::endl;
  650.             // access
  651.             file << "\t\t\t<Property Name=\"access\" Value=\"" << overworld_waypoint->access << "\" />" << std::endl;
  652.  
  653.             // end Overworld Level
  654.             file << "\t\t</Overworld_Level>" << std::endl;
  655.         }
  656.  
  657.         // end Overworld
  658.         file << "\t</Overworld>" << std::endl;
  659.     }
  660.  
  661.     // end Savegame
  662.     file << "</Savegame>" << std::endl;
  663.  
  664.     file.close();
  665.     
  666.     if( debug )
  667.     {
  668.         printf( "Saved Savegame %s to slot %d\n", filename.c_str(), save_slot );
  669.     }
  670.     
  671.     return 1;
  672. }
  673.  
  674. string cSavegame :: Get_Description( unsigned int save_slot, bool only_description /* = 0 */ )
  675. {
  676.     string savefile, str_description;
  677.  
  678.     savefile = savegame_dir + "/" + int_to_string( save_slot ) + ".save";
  679.  
  680.     if( !File_Exists( savefile ) )
  681.     {
  682.         str_description = int_to_string( save_slot ) + ". Free Save";
  683.         return str_description;
  684.     }
  685.     
  686.     cSave *temp_savegame = Load( save_slot );
  687.  
  688.     if( temp_savegame->lives < 0 )
  689.     {
  690.         str_description = int_to_string( save_slot ) + ". Broken Save";
  691.         return str_description;
  692.     }
  693.  
  694.     // complete description
  695.     if( !only_description )
  696.     {
  697.         str_description = int_to_string( save_slot ) + ". " + temp_savegame->description;
  698.  
  699.         if( temp_savegame->level_name.empty() )
  700.         {
  701.             str_description += " - " + temp_savegame->overworld_active;
  702.         }
  703.         else
  704.         {
  705.             str_description += _(" -  Level ") + temp_savegame->level_name;
  706.         }
  707.  
  708.         str_description += _(" - Date ") + Time_to_String( temp_savegame->save_time, "%Y-%m-%d  %H:%M:%S" );
  709.     }
  710.     // only the user description
  711.     else
  712.     {
  713.         return temp_savegame->description;
  714.     }
  715.  
  716.     delete temp_savegame;
  717.     return str_description;
  718. }
  719.  
  720. bool cSavegame :: Is_Valid( unsigned int save_slot )
  721. {
  722.     return File_Exists( savegame_dir + "/" + int_to_string( save_slot ) + ".save" );
  723. }
  724.  
  725. // XML element start
  726. void cSavegame :: elementStart( const CEGUI::String &element, const CEGUI::XMLAttributes &attributes )
  727. {
  728.     // Property/Item/Tag of an Element
  729.     if( element == "Property" )
  730.     {
  731.         xml_attributes.add( attributes.getValueAsString( "Name" ), attributes.getValueAsString( "Value" ) );
  732.     }
  733. }
  734.  
  735. // XML element end
  736. void cSavegame :: elementEnd( const CEGUI::String &element )
  737. {
  738.     if( element != "Property" )
  739.     {
  740.         if( element == "Information" )
  741.         {
  742.             save_temp->description = xml_attributes.getValueAsString( "description" ).c_str();
  743.             save_temp->version = xml_attributes.getValueAsInteger( "version" );
  744.             save_temp->save_time = xml_attributes.getValueAsInteger( "save_time" );
  745.         }
  746.         else if( element == "Level" )
  747.         {
  748.             Handle_Level( xml_attributes );
  749.         }
  750.         else if( element == "Level_Object" )
  751.         {
  752.             Handle_Level_Object( xml_attributes );
  753.             // don't clear attributes
  754.             return;
  755.         }
  756.         else if( element == "Player" )
  757.         {
  758.             Handle_Player( xml_attributes );
  759.         }
  760.         else if( element == "Overworld_Data" )
  761.         {
  762.             Handle_Overworld_Data( xml_attributes );
  763.         }
  764.         else if( element == "Overworld" )
  765.         {
  766.             Handle_Overworld( xml_attributes );
  767.         }
  768.         else if( element == "Overworld_Level" )
  769.         {
  770.             Handle_Overworld_Level( xml_attributes );
  771.             // don't clear attributes
  772.             return;
  773.         }
  774.         else if( element == "Savegame" )
  775.         {
  776.             // ignore
  777.         }
  778.         else if( element.length() )
  779.         {
  780.             printf( "Warning : Savegame Unknown Element : %s\n", element.c_str() );
  781.         }
  782.  
  783.         // clear
  784.         xml_attributes = CEGUI::XMLAttributes();
  785.     }
  786. }
  787.  
  788. void cSavegame :: Handle_Level( const CEGUI::XMLAttributes &attributes )
  789. {
  790.     save_temp->level_name = xml_attributes.getValueAsString( "level_name" ).c_str();
  791.     save_temp->level_posx = xml_attributes.getValueAsFloat( "player_posx" );
  792.     save_temp->level_posy = xml_attributes.getValueAsFloat( "player_posy" );
  793.  
  794.     // set level objects
  795.     save_temp->level_objects.swap( level_objects );
  796.     level_objects.clear();
  797. }
  798.  
  799. void cSavegame :: Handle_Level_Object( const CEGUI::XMLAttributes &attributes )
  800. {
  801.     int type = xml_attributes.getValueAsInteger( "type" );
  802.  
  803.     if( type <= 0 )
  804.     {
  805.         printf( "Warning : Unknown Savegame Level Object type %d\n", type );
  806.         return;
  807.     }
  808.  
  809.     cSave_Level_Object *object = new cSave_Level_Object();
  810.  
  811.     // type
  812.     object->type = (SpriteType)type;
  813.     xml_attributes.remove( "type" );
  814.  
  815.  
  816.     // Get Properties
  817.     for( unsigned int i = 0; i < xml_attributes.getCount(); i++ )
  818.     {
  819.         // get property
  820.         string property_name = xml_attributes.getName( i ).c_str();
  821.  
  822.         // ignore level attributes
  823.         if( property_name.compare( "level_name" ) == 0 || property_name.compare( "player_posx" ) == 0 || property_name.compare( "player_posy" ) == 0 )
  824.         {
  825.             continue;
  826.         }
  827.  
  828.         object->properties.push_back( cSave_Level_Object_Property( property_name, xml_attributes.getValue( i ).c_str() ) );
  829.     }
  830.  
  831.     // remove used Properties
  832.     for( Save_Level_Object_ProprtyList::iterator prop_itr = object->properties.begin(), prop_itr_end = object->properties.end(); prop_itr != prop_itr_end; ++prop_itr )
  833.     {
  834.         // get property pointer
  835.         cSave_Level_Object_Property Property = (*prop_itr);
  836.  
  837.         xml_attributes.remove( Property.Name );
  838.     }
  839.  
  840.     // add object
  841.     level_objects.push_back( object );
  842. }
  843.  
  844. void cSavegame :: Handle_Player( const CEGUI::XMLAttributes &attributes )
  845. {
  846.     save_temp->lives = xml_attributes.getValueAsInteger( "lives" );
  847.     save_temp->points = xml_attributes.getValueAsInteger( "points" );
  848.     save_temp->goldpieces = xml_attributes.getValueAsInteger( "goldpieces" );
  849.     save_temp->player_type = xml_attributes.getValueAsInteger( "type" );
  850.     save_temp->player_state = xml_attributes.getValueAsInteger( "state" );
  851.     save_temp->itembox_item = xml_attributes.getValueAsInteger( "itembox_item" );
  852. }
  853.  
  854. void cSavegame :: Handle_Overworld_Data( const CEGUI::XMLAttributes &attributes )
  855. {
  856.     save_temp->overworld_active = xml_attributes.getValueAsString( "active" ).c_str();
  857.     save_temp->overworld_current_waypoint = xml_attributes.getValueAsInteger( "current_waypoint" );
  858. }
  859.  
  860. void cSavegame :: Handle_Overworld( const CEGUI::XMLAttributes &attributes )
  861. {
  862.     string name = xml_attributes.getValueAsString( "name" ).c_str();
  863.  
  864.     // Search if Overworld is available
  865.     cOverworld *overworld = pOverworld_Manager->Get_from_Name( name );
  866.  
  867.     if( !overworld )
  868.     {
  869.         printf( "Warning : Savegame %s Overworld %s not found\n", save_temp->description.c_str(), name.c_str() );
  870.     }
  871.  
  872.     // Create Savegame Overworld
  873.     cSave_Overworld *save_overworld = new cSave_Overworld();
  874.     // set name
  875.     save_overworld->name = name;
  876.     // set waypoints
  877.     save_overworld->Waypoints.swap( active_waypoints );
  878.     active_waypoints.clear();
  879.     // save
  880.     save_temp->Overworlds.push_back( save_overworld );
  881. }
  882.  
  883. void cSavegame :: Handle_Overworld_Level( const CEGUI::XMLAttributes &attributes )
  884. {
  885.     bool access = xml_attributes.getValueAsBool( "access" );
  886.  
  887.     cSave_Overworld_Waypoint *waypoint = new cSave_Overworld_Waypoint();
  888.  
  889.     // destination ( level_name and world_name is pre 0.99.6 )
  890.     if( xml_attributes.exists( "world_name" ) )
  891.     {
  892.         waypoint->destination = xml_attributes.getValueAsString( "world_name" ).c_str();
  893.     }
  894.     else if( xml_attributes.exists( "level_name" ) )
  895.     {
  896.         waypoint->destination = xml_attributes.getValueAsString( "level_name" ).c_str();
  897.     }
  898.     // default
  899.     else
  900.     {
  901.         waypoint->destination = xml_attributes.getValueAsString( "destination" ).c_str();
  902.     }
  903.  
  904.     waypoint->access = access;
  905.  
  906.     active_waypoints.push_back( waypoint );
  907.  
  908.     // clear
  909.     xml_attributes.remove( "level_name" );
  910.     xml_attributes.remove( "world_name" );
  911. }
  912.  
  913. /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
  914.  
  915. cSavegame *pSavegame = NULL;
  916.