Переглянути джерело

Save/Load improvements:

 - Savefiles are now generated as xml files.
 - Save menu partially implemented. It can't actually save or load games, but save spots are displayed and populated.
 - Location name can be saved.

Other improvements:

 - MPNAM opcode implemented.
 - Map name properly set and displayed in the main menu.
 - ":" character added to digits font.
Iñigo Valentin 3 роки тому
батько
коміт
12119f4884

+ 3 - 3
V-Gears-Installer/src/decompiler/field/instruction/FieldWindowInstruction.cpp

@@ -155,9 +155,9 @@ void FieldWindowInstruction::ProcessWCLSE(CodeGenerator* code_gen){
 }
 
 void FieldWindowInstruction::ProcessMPNAM(CodeGenerator* code_gen){
-    code_gen->AddOutputLine(
-      (boost::format("-- field:map_name(%1%)") % params_[0]->GetUnsigned()).str()
-    );
+    code_gen->AddOutputLine((
+      boost::format("dialog:set_map_name(%1%_%2%)") % script_name % params_[0]->GetUnsigned()
+    ).str());
 }
 
 void FieldWindowInstruction::ProcessMENU2(CodeGenerator* code_gen){

+ 26 - 0
V-Gears/include/core/DialogsManager.h

@@ -326,6 +326,27 @@ class DialogsManager : public Ogre::Singleton<DialogsManager>{
          */
         int GetCursor(const char* d_name) const;
 
+        /**
+         * Sets the map name from a text ID.
+         *
+         * @param[in] text_id The ID of the text to set as map name.
+         */
+        void ScriptSetMapName(const char* text_id);
+
+        /**
+         * Sets the map name from a text ID.
+         *
+         * @param[in] name The new map name.
+         */
+        void SetMapName(std::string name);
+
+        /**
+         * Retrieves the current map name.
+         *
+         * @return The map name.
+         */
+        std::string GetMapName();
+
     private:
 
         /**
@@ -395,5 +416,10 @@ class DialogsManager : public Ogre::Singleton<DialogsManager>{
          * Indicates if the 'down' button has been pressed.
          */
         bool down_pressed_;
+
+        /**
+         * Current map name.
+         */
+        std::string map_name_;
 };
 

+ 1 - 0
V-Gears/include/core/EntityManager.h

@@ -340,6 +340,7 @@ class EntityManager : public Ogre::Singleton<EntityManager>{
          */
         int GetTrack(const int id);
 
+
     private:
 
         /**

+ 86 - 54
V-Gears/include/core/Savemap.h

@@ -37,22 +37,20 @@ class Savemap{
 
         void operator = (const Savemap &to_copy);
 
-        /**
-         * Indicates if the savemap is empty or contains actual data.
-         *
-         * @return True if the savemap is empty, false otherwise.
-         */
-        bool IsEmpty();
-
         /**
          * Reads the savemap data from a file.
+         *
+         * @param[in] file_name The name of the file to read.
          */
         void Read(std::string file_name);
 
         /**
          * Writes the savemap to a file.
+         *
+         * @param[in] slot The slot the savemap is to be written to.
+         * @param[in] file_name Name of the file the savemap is to be written to.
          */
-        void Write(std::string file_name);
+        void Write(int slot, std::string file_name);
 
         /**
          * Retrieves a control string for a savemap.
@@ -113,15 +111,6 @@ class Savemap{
          */
         void SetCountdownTime(const unsigned int seconds);
 
-        /**
-         * Sets the current field of the savemap.
-         *
-         * If set to an empty string, it will be assumed that it was saved in the world map.
-         *
-         * @param[in] field Field map ID, or empty for the world map.
-         */
-        void SetField(const std::string field);
-
         /**
          * Marks a key item as owned or non-owned in the savemap.
          *
@@ -204,10 +193,12 @@ class Savemap{
          * @param[in] z Z coordinate. It's optional, set it to -1 to ignore it.
          * @param[in] triangle Walkmesh triangle ID.
          * @param[in] angle Facing direction.
+         * @param[in] field Field map ID, or empty for the world map.
+         * @param[in] Name of the location to show in the save slot.
          */
         void SetLocation(
           const unsigned int x, const unsigned int y, const int z,
-          const unsigned int triangle, const int angle
+          const unsigned int triangle, const int angle, std::string field, std::string name
         );
 
         /**
@@ -329,6 +320,32 @@ class Savemap{
          */
         void SetData(const unsigned int bank, const unsigned int address, const int value);
 
+        /**
+         * Checks if the savemap is empty.
+         *
+         * @return True if the savemap is empty, false if it contains a saved game.
+         */
+        bool IsEmpty();
+
+        /**
+         * Generates a string with all the required data to generate a preview of the savemap.
+         *
+         * The included information contains the following fields, separated by the character "#":
+         * - Slot
+         * - Control key
+         * - Party money
+         * - Game time (in seconds)
+         * - Location text
+         * - Party member 1 name
+         * - Party member 1 level
+         * - Party member 1 character ID.
+         * - Party member 2 character ID.
+         * - Party member 3 character ID.
+         *
+         * @return The generated string.
+         */
+        std::string GetPreviewData();
+
         /**
          * Character basic stats.
          */
@@ -425,7 +442,7 @@ class Savemap{
         /**
          * Level at which the limit level is full.
          */
-        static const unsigned int MAX_LIMIT_BAR = 255;
+        static const unsigned int MAX_LIMIT_BAR = 254;
 
         /**
          * Maximum number of party member.
@@ -440,7 +457,7 @@ class Savemap{
         /**
          * Number of addresses in each data bank.
          */
-        static const unsigned int BANK_ADDRESS_COUNT = 255;
+        static const unsigned int BANK_ADDRESS_COUNT = 254;
 
         /**
          * MAx colour component value.
@@ -513,17 +530,17 @@ class Savemap{
             /**
              * Battle speed.
              */
-            u8 battle_speed;
+            unsigned int battle_speed;
 
             /**
              * Battle message speed.
              */
-            u8 battle_msg_speed;
+            unsigned int battle_msg_speed;
 
             /**
              * Field message speed
              */
-            u8 msg_speed;
+            unsigned int msg_speed;
 
             /**
              * Magic order.
@@ -553,29 +570,41 @@ class Savemap{
             /**
              * X coordinate.
              */
-            u16 x;
+            unsigned int x;
 
             /**
              * Y coordinate.
              */
-            u16 y;
+            unsigned int y;
 
             /**
              * Z coordinate.
              *
              * Usually unused.
              */
-            u16 z;
+            int z;
 
             /**
              * Triangle in the walkmesh;
              */
-            u16 triangle;
+            unsigned int triangle;
 
             /**
              * Facing direction.
              */
-            u16 angle;
+            unsigned int angle;
+
+            /**
+             * Current field map.
+             *
+             * If null or empty, it means the player is in in the world map.
+             */
+            std::string field;
+
+            /**
+             * Location name. Used for the saveslot.
+             */
+            std::string name;
         };
 
         /**
@@ -591,7 +620,12 @@ class Savemap{
             /**
              * Total AP in the materia.
              */
-            u32 ap;
+            unsigned int ap;
+
+            /**
+             * Indicates if the materia is an enemy skill materia.
+             */
+            bool enemy_skill;
 
             /**
              * Learned enemy skills (only for Enemy Skill materia).
@@ -612,7 +646,7 @@ class Savemap{
             /**
              * Item stock.
              */
-            u16 quantity;
+            unsigned int quantity;
         };
 
         /**
@@ -628,13 +662,13 @@ class Savemap{
                 /**
                  * Stat base value.
                  */
-                u32 base;
+                unsigned int base;
 
                 /**
                  * For STR, VIT, DEX and LCK, it means the source bonus. For HP and MP, it means
                  * the current values.
                  */
-                u32 extra;
+                unsigned int extra;
             };
 
             /**
@@ -656,12 +690,12 @@ class Savemap{
             /**
              * Character ID, sequential.
              */
-            u8 id;
+            unsigned int id;
 
             /**
-             * Character ID, can change with the history.
+             * Character ID, can change with the history. -1 to not use.
              */
-            u8 char_id;
+            int char_id;
 
             /**
              * Indicates if the character has been unlocked for the PHS.
@@ -681,12 +715,12 @@ class Savemap{
             /**
              * Character level.
              */
-            u16 level;
+            unsigned int level;
 
             /**
              * Enemies killed by the character.
              */
-            u32 kills;
+            unsigned int kills;
 
             /**
              * Indicates if the character is in the back_row;
@@ -696,12 +730,12 @@ class Savemap{
             /**
              * Total experience.
              */
-            u32 exp;
+            unsigned int exp;
 
             /**
              * Experience required to reach next level.
              */
-            u32 exp_to_next;
+            unsigned int exp_to_next;
 
             /**
              * STR stat.
@@ -746,12 +780,12 @@ class Savemap{
             /**
              * Current limit level.
              */
-            u8 limit_level;
+            unsigned int limit_level;
 
             /**
              * Current limit bar.
              */
-            u8 limit_bar;
+            unsigned int limit_bar;
 
             /**
              * Learned limits.
@@ -763,7 +797,7 @@ class Savemap{
             /**
              * Uses of techniques in each limit level.
              */
-            u32 limit_uses[MAX_LIMIT_LEVELS];
+            unsigned int limit_uses[MAX_LIMIT_LEVELS];
 
             /**
              * Equipped weapon;
@@ -776,9 +810,9 @@ class Savemap{
             Equipment armor;
 
             /**
-             * Equipped accessory ID. 0 if none equipped.
+             * Equipped accessory ID. -1 if none equipped.
              */
-            u16 accessory;
+            int accessory;
 
             /**
              * Current status list.
@@ -791,6 +825,11 @@ class Savemap{
          */
         bool empty_;
 
+        /**
+         * The slot the savemap is saved at, or -1 if not saved
+         */
+        int slot_;
+
         /**
          * Control string.
          *
@@ -839,24 +878,17 @@ class Savemap{
         /**
          * Current party money.
          */
-        u32 money_;
+        unsigned int money_;
 
         /**
          * Seconds played
          */
-        u32 seconds_;
+        unsigned int seconds_;
 
         /**
          * Current countdown remaining seconds.
          */
-        u32 countdown_;
-
-        /**
-         * Current field map.
-         *
-         * If null or empty, it means the player is in in the world map.
-         */
-        std::string field_map_;
+        unsigned int countdown_;
 
         /**
          * Current location.

+ 35 - 10
V-Gears/include/core/SavemapManager.h

@@ -152,15 +152,6 @@ class SavemapManager : public Ogre::Singleton<SavemapManager>{
          */
         void SetCountdownTime(const unsigned int seconds);
 
-        /**
-         * Sets the current field of the current savemap.
-         *
-         * If set to an empty string, it will be assumed that it was saved in the world map.
-         *
-         * @param[in] field Field map ID, or empty for the world map.
-         */
-        void SetField(const char* field);
-
         /**
          * Marks a key item as owned or non-owned in the current savemap.
          *
@@ -243,10 +234,12 @@ class SavemapManager : public Ogre::Singleton<SavemapManager>{
          * @param[in] z Z coordinate. It's optional, set it to -1 to ignore it.
          * @param[in] triangle Walkmesh triangle ID.
          * @param[in] angle Facing direction.
+         * @param[in] field Field map ID, or empty for the world map.
+         * @param[in] Name of the location to show in the save slot.
          */
         void SetLocation(
           const unsigned int x, const unsigned int y, const int z,
-          const unsigned int triangle, const int angle
+          const unsigned int triangle, const int angle, const char* field, const char* name
         );
 
         /**
@@ -359,6 +352,36 @@ class SavemapManager : public Ogre::Singleton<SavemapManager>{
           const unsigned int id, const unsigned int status, const bool inflicted
         );
 
+        /**
+         * Checks if a slot is empty.
+         *
+         * @return True if the slot is empty, or false if a game is saved there. If an invalid slot
+         * is queried, it will always return true.
+         */
+        bool SlotIsEmpty(const unsigned int slot);
+
+        /**
+         * Generates a string with all the required data to generate a preview of a savemap.
+         *
+         * The included information contains the following fields, separated by the character "#":
+         * - Slot
+         * - Control key
+         * - Party money
+         * - Game time (in seconds)
+         * - Location text
+         * - Party member 1 name
+         * - Party member 1 level
+         * - Party member 1 character ID.
+         * - Party member 2 character ID.
+         * - Party member 3 character ID.
+         *
+         * @param[in]
+         * @return The generated string. An empty string if a wrong slot is specified, or the slot
+         * is empty.
+         */
+        //char* GetPreviewData(const unsigned int slot);
+        std::string GetPreviewData(const unsigned int slot);
+
     private:
 
         /**
@@ -386,6 +409,8 @@ class SavemapManager : public Ogre::Singleton<SavemapManager>{
          */
         bool savemaps_read_;
 
+        //char* temp_;
+
 };
 
 

+ 137 - 123
V-Gears/include/core/ScriptManagerBinds.h

@@ -279,129 +279,136 @@ void ScriptManager::InitBinds(){
     // Commands for the savemap manager.
     luabind::module(lua_state_)[
         luabind::class_<SavemapManager>("SavemapManager")
-        .def(
-          "get_current_savemap", (Savemap*(SavemapManager::*)()) &SavemapManager::GetCurrentSavemap
-        )
-        .def(
-          "get_savemap",
-          (Savemap*(SavemapManager::*)(const unsigned int)) &SavemapManager::GetSavemap
-        )
-        .def(
-          "set_data",
-          (void(SavemapManager::*)(const unsigned int, const unsigned int, const int))
-            &SavemapManager::SetData
-        )
-        .def(
-          "set_control_key", (void(SavemapManager::*)(const char*)) &SavemapManager::SetControlKey
-        )
-        .def(
-          "set_window_colours",
-          (void(SavemapManager::*)(
-            const unsigned int, const unsigned int, const unsigned int,
-            const unsigned int, const unsigned int, const unsigned int,
-            const unsigned int, const unsigned int, const unsigned int,
-            const unsigned int, const unsigned int, const unsigned int
-          )) &SavemapManager::SetWindowColours
-        )
-        .def("set_money", (void(SavemapManager::*)(const unsigned int)) &SavemapManager::SetMoney)
-        .def(
-          "set_game_time",
-          (void(SavemapManager::*)(const unsigned int)) &SavemapManager::SetGameTime
-        )
-        .def(
-          "set_countdown_time",
-          (void(SavemapManager::*)(const unsigned int)) &SavemapManager::SetCountdownTime
-        )
-        .def(
-          "set_field", (void(SavemapManager::*)(const char*)) &SavemapManager::SetField
-        )
-        .def(
-          "set_key_item",
-          (void(SavemapManager::*)(const unsigned int, const bool)) &SavemapManager::SetKeyItem
-        )
-        .def(
-          "set_party",
-          (void(SavemapManager::*)(const int, const int, const int)) &SavemapManager::SetParty
-        )
-        .def(
-          "set_item",
-          (void(SavemapManager::*)(const unsigned int, const unsigned int, const unsigned int))
-            &SavemapManager::SetItem
-        )
-        .def(
-          "set_materia",
-          (void(SavemapManager::*)(const unsigned int, const unsigned int, const unsigned int))
-            &SavemapManager::SetMateria
-        )
-        .def(
-          "set_e_skill_materia",
-          (void(SavemapManager::*)(const unsigned int, const unsigned int, const bool))
-            &SavemapManager::SetESkillMateria
-        )
-        .def(
-          "set_materia_stash",
-          (void(SavemapManager::*)(const unsigned int, const unsigned int, const unsigned int))
-            &SavemapManager::SetMateriaStash
-        )
-        .def(
-          "set_e_skill_materia_stash",
-          (void(SavemapManager::*)(const unsigned int, const unsigned int, const bool))
-            &SavemapManager::SetESkillMateriaStash
-        )
-        .def(
-          "set_location",
-          (void(SavemapManager::*)(
-            const unsigned int, const unsigned int, const int, const unsigned int, const int)
-          ) &SavemapManager::SetLocation
-        )
-        .def(
-          "set_setting",
-          (void(SavemapManager::*)(const unsigned int, const unsigned int))
-            &SavemapManager::SetSetting
-        )
-        .def(
-          "set_character_info",
-          (void(SavemapManager::*)(
-            const unsigned int, const int, const char*, const bool, const bool, const unsigned int,
-            const unsigned int, const bool, const unsigned int, const unsigned int,
-            const unsigned int, const unsigned int, const unsigned int, const unsigned int,
-            const int
-          )) &SavemapManager::SetCharacterInfo
-        )
-        .def(
-          "set_character_stat",
-          (void(SavemapManager::*)(
-            const unsigned int, const unsigned int, const unsigned int, const unsigned int
-          )) &SavemapManager::SetCharacterStat
-        )
-        .def(
-          "set_character_limit_learned",
-          (void(SavemapManager::*)(
-            const unsigned int, const unsigned int, const unsigned int,
-            const bool, const unsigned int
-          )) &SavemapManager::SetCharacterLimitLearned
-        )
-        .def(
-          "set_character_materia",
-          (void(SavemapManager::*)(
-            const unsigned int, const bool, const unsigned int,
-            const unsigned int, const unsigned int
-          )) &SavemapManager::SetCharacterMateria
-        )
-        .def(
-          "set_character_e_skill_materia",
-          (void(SavemapManager::*)(
-            const unsigned int, const bool, const unsigned int, const unsigned int, const bool
-          )) &SavemapManager::SetCharacterESkillMateria
-        )
-        .def(
-          "set_character_status",
-          (void(SavemapManager::*)(const unsigned int, const unsigned int, const bool))
-            &SavemapManager::SetCharacterStatus
-        )
-        .def(
-          "save", (bool(SavemapManager::*)(const unsigned int, const bool)) &SavemapManager::Save
-        )
+          .def(
+            "get_current_savemap",
+            (Savemap*(SavemapManager::*)()) &SavemapManager::GetCurrentSavemap
+          )
+          .def(
+            "get_savemap",
+            (Savemap*(SavemapManager::*)(const unsigned int)) &SavemapManager::GetSavemap
+          )
+          .def(
+            "set_data",
+            (void(SavemapManager::*)(const unsigned int, const unsigned int, const int))
+              &SavemapManager::SetData
+          )
+          .def(
+            "set_control_key", (void(SavemapManager::*)(const char*)) &SavemapManager::SetControlKey
+          )
+          .def(
+            "set_window_colours",
+            (void(SavemapManager::*)(
+              const unsigned int, const unsigned int, const unsigned int,
+              const unsigned int, const unsigned int, const unsigned int,
+              const unsigned int, const unsigned int, const unsigned int,
+              const unsigned int, const unsigned int, const unsigned int
+            )) &SavemapManager::SetWindowColours
+          )
+          .def("set_money", (void(SavemapManager::*)(const unsigned int)) &SavemapManager::SetMoney)
+          .def(
+            "set_game_time",
+            (void(SavemapManager::*)(const unsigned int)) &SavemapManager::SetGameTime
+          )
+          .def(
+            "set_countdown_time",
+            (void(SavemapManager::*)(const unsigned int)) &SavemapManager::SetCountdownTime
+          )
+          .def(
+            "set_key_item",
+            (void(SavemapManager::*)(const unsigned int, const bool)) &SavemapManager::SetKeyItem
+          )
+          .def(
+            "set_party",
+            (void(SavemapManager::*)(const int, const int, const int)) &SavemapManager::SetParty
+          )
+          .def(
+            "set_item",
+            (void(SavemapManager::*)(const unsigned int, const unsigned int, const unsigned int))
+              &SavemapManager::SetItem
+          )
+          .def(
+            "set_materia",
+            (void(SavemapManager::*)(const unsigned int, const unsigned int, const unsigned int))
+              &SavemapManager::SetMateria
+          )
+          .def(
+            "set_e_skill_materia",
+            (void(SavemapManager::*)(const unsigned int, const unsigned int, const bool))
+              &SavemapManager::SetESkillMateria
+          )
+          .def(
+            "set_materia_stash",
+            (void(SavemapManager::*)(const unsigned int, const unsigned int, const unsigned int))
+              &SavemapManager::SetMateriaStash
+          )
+          .def(
+            "set_e_skill_materia_stash",
+            (void(SavemapManager::*)(const unsigned int, const unsigned int, const bool))
+              &SavemapManager::SetESkillMateriaStash
+          )
+          .def(
+            "set_location",
+            (void(SavemapManager::*)(
+              const unsigned int, const unsigned int, const int, const unsigned int, const int,
+              const char*, const char*
+            )) &SavemapManager::SetLocation
+          )
+          .def(
+            "set_setting",
+            (void(SavemapManager::*)(const unsigned int, const unsigned int))
+              &SavemapManager::SetSetting
+          )
+          .def(
+            "set_character_info",
+            (void(SavemapManager::*)(
+              const unsigned int, const int, const char*, const bool, const bool, const unsigned int,
+              const unsigned int, const bool, const unsigned int, const unsigned int,
+              const unsigned int, const unsigned int, const unsigned int, const unsigned int,
+              const int
+            )) &SavemapManager::SetCharacterInfo
+          )
+          .def(
+            "set_character_stat",
+            (void(SavemapManager::*)(
+              const unsigned int, const unsigned int, const unsigned int, const unsigned int
+            )) &SavemapManager::SetCharacterStat
+          )
+          .def(
+            "set_character_limit_learned",
+            (void(SavemapManager::*)(
+              const unsigned int, const unsigned int, const unsigned int,
+              const bool, const unsigned int
+            )) &SavemapManager::SetCharacterLimitLearned
+          )
+          .def(
+            "set_character_materia",
+            (void(SavemapManager::*)(
+              const unsigned int, const bool, const unsigned int,
+              const unsigned int, const unsigned int
+            )) &SavemapManager::SetCharacterMateria
+          )
+          .def(
+            "set_character_e_skill_materia",
+            (void(SavemapManager::*)(
+              const unsigned int, const bool, const unsigned int, const unsigned int, const bool
+            )) &SavemapManager::SetCharacterESkillMateria
+          )
+          .def(
+            "set_character_status",
+            (void(SavemapManager::*)(const unsigned int, const unsigned int, const bool))
+              &SavemapManager::SetCharacterStatus
+          )
+          .def(
+            "save", (bool(SavemapManager::*)(const unsigned int, const bool)) &SavemapManager::Save
+          )
+          .def(
+            "slot_is_empty",
+            (bool(SavemapManager::*)(const unsigned int)) &SavemapManager::SlotIsEmpty
+          )
+          .def(
+            "get_preview_data",
+             (std::string(SavemapManager::*)(const unsigned int)) &SavemapManager::GetPreviewData
+           )
     ];
 
     // 2D background and camera commands
@@ -496,6 +503,13 @@ void ScriptManager::InitBinds(){
             luabind::value("TRANSPARENT", MSL_TRANSPARENT),
             luabind::value("NONE", MSL_NONE)
           ]
+          .def(
+              "set_map_name",
+              (void(DialogsManager::*)(const char*)) &DialogsManager::ScriptSetMapName
+            )
+            .def(
+              "get_map_name", (std::string(DialogsManager::*)()) &DialogsManager::GetMapName
+            )
     ];
 
     // UI widget commands

+ 8 - 0
V-Gears/include/core/TextManager.h

@@ -103,6 +103,14 @@ class TextManager : public Ogre::Singleton<TextManager>{
          */
         TiXmlNode* GetDialog(const Ogre::String& name, float &width, float& height) const;
 
+        /**
+         * Retrieves a dialog text by name.
+         *
+         * @param[in] name Text name or identifier.
+         * @return Dialog text, an empty string if there is none by the specified ID.
+         */
+        std::string GetDialogText(const std::string name);
+
         /**
          * Deletes all texts in the manager.
          */

+ 13 - 1
V-Gears/src/core/DialogsManager.cpp

@@ -37,7 +37,8 @@ DialogsManager::DialogsManager():
   next_repeated_(false),
   up_pressed_(false),
   down_pressed_(false),
-  limit_area_(NULL)
+  limit_area_(NULL),
+  map_name_("")
 {LOG_TRIVIAL("DialogsManager created.");}
 
 DialogsManager::~DialogsManager(){
@@ -93,6 +94,17 @@ void DialogsManager::Input(const VGears::Event& input){
         down_pressed_ = true;
 }
 
+void DialogsManager::ScriptSetMapName(const char* text_id){
+    std::string text = TextManager::getSingleton().GetDialogText(text_id);
+    SetMapName(text);
+}
+
+void DialogsManager::SetMapName(std::string name){
+    map_name_ = name;
+}
+
+std::string DialogsManager::GetMapName(){return map_name_;}
+
 void DialogsManager::Update(){
     for (unsigned int i = 0; i < messages_.size(); ++ i){
         switch(messages_[i]->state){

+ 953 - 132
V-Gears/src/core/Savemap.cpp

@@ -16,34 +16,102 @@
 #include <string>
 #include <iostream>
 #include <algorithm>
+#include <tinyxml.h>
 #include "core/Savemap.h"
+#include "core/Logger.h"
+#include "core/XmlFile.h"
 #include "common/TypeDefine.h"
 
 Savemap::Savemap():
-  empty_(true), control_(""), money_(0), seconds_(0), countdown_(0), field_map_("")
+  empty_(true), control_("X"), money_(0), seconds_(0), countdown_(0), slot_(-1)
 {
     for (int i = 0; i < 4; i ++){
         window_colours_[i][0] = 0;
         window_colours_[i][1] = 0;
         window_colours_[i][2] = 0;
     }
-    // TODO: Characters? Needed to initialize?
     party_[0] = -1;
     party_[1] = -1;
     party_[2] = -1;
-    for (int i = 0; i < 500; i ++){
+    location_.x = 0;
+    location_.y = 0;
+    location_.z = -1;
+    location_.triangle = 0;
+    location_.angle = 0;
+    location_.field = "";
+    location_.name = "";
+    for (int i = 0; i < MAX_ITEM_SLOTS; i ++){
         items_[i].id = -1;
         items_[i].quantity = 0;
+    }
+    for (int i = 0; i < MAX_MATERIA_SLOTS; i ++){
         materia_[i].id = -1;
         materia_[i].ap = 0;
+        materia_[i].enemy_skill = false;
+        for (int s = 0; s < MAX_ENEMY_SKILLS; s ++) materia_[i].enemy_skill_learned[s] = false;
+    }
+    for (int i = 0; i < MAX_STASH_SLOTS; i ++){
         materia_stash_[i].id = -1;
         materia_stash_[i].ap = 0;
+        materia_stash_[i].enemy_skill = false;
+        for (int s = 0; s < MAX_ENEMY_SKILLS; s ++)
+            materia_stash_[i].enemy_skill_learned[s] = false;
     }
-    for (int i = 0; i < 50; i ++){
+    for (int i = 0; i < MAX_KEY_ITEM_SLOTS; i ++){
         key_items_[i] = false;
     }
-    for (int b = 0; b < 15; b ++){
-        for (int a = 0; a < 15; a ++){
+    for (int i = 0; i < MAX_CHARACTERS; i ++){
+        characters_[i].id = i;
+        characters_[i].char_id = 0;
+        characters_[i].enabled = false;
+        characters_[i].locked = false;
+        characters_[i].name = "";
+        characters_[i].level = 1;
+        characters_[i].kills = 0;
+        characters_[i].back_row = false;
+        characters_[i].exp = 0;
+        characters_[i].exp_to_next = 1;
+        characters_[i].str.base = 0;
+        characters_[i].str.extra = 0;
+        characters_[i].vit.base = 0;
+        characters_[i].vit.extra = 0;
+        characters_[i].mag.base = 0;
+        characters_[i].mag.extra = 0;
+        characters_[i].spr.base = 0;
+        characters_[i].spr.extra = 0;
+        characters_[i].dex.base = 0;
+        characters_[i].dex.extra = 0;
+        characters_[i].lck.base = 0;
+        characters_[i].lck.extra = 0;
+        characters_[i].hp.base = 0;
+        characters_[i].hp.extra = 0;
+        characters_[i].mp.base = 0;
+        characters_[i].mp.extra = 0;
+        characters_[i].limit_level = 1;
+        characters_[i].limit_bar = 0;
+        for (int l = 0; l < MAX_LIMIT_LEVELS; l ++){
+            for (int t = 0; t < MAX_LIMIT_TECHNIQUES; t ++)
+                characters_[i].limits_learned[l][t] = false;
+            characters_[i].limit_uses[l] = 0;
+        }
+        characters_[i].weapon.id = 0;
+        characters_[i].armor.id = 0;
+        characters_[i].accessory = -1;
+        for (int s = 0; s < MAX_EQUIP_SLOTS; s ++){
+            characters_[i].weapon.materia[s].id = -1;
+            characters_[i].armor.materia[s].id = -1;
+            characters_[i].weapon.materia[s].ap = 0;
+            characters_[i].armor.materia[s].ap = 0;
+            characters_[i].weapon.materia[s].enemy_skill = false;
+            characters_[i].armor.materia[s].enemy_skill = false;
+            for (int e = 0; e < MAX_ENEMY_SKILLS; e ++){
+                characters_[i].weapon.materia[s].enemy_skill_learned[e] = false;
+                characters_[i].armor.materia[s].enemy_skill_learned[e] = false;
+            }
+        }
+    }
+    for (int b = 0; b < BANK_COUNT; b ++){
+        for (int a = 0; a < BANK_ADDRESS_COUNT; a ++){
             data_[b][a] = 0;
         }
     }
@@ -63,17 +131,14 @@ void Savemap::operator = (const Savemap &to_copy){
     for (int i = 0; i < 3; i ++) party_[i] = to_copy.party_[i];
 }
 
-bool Savemap::IsEmpty(){return empty_;}
-
-void Savemap::Read(std::string file_name){
-    // TODO
-}
-
 void Savemap::SetData(const unsigned int bank, const unsigned int address, const int value){
     if (bank < BANK_COUNT && address < BANK_ADDRESS_COUNT) data_[bank][address] = value;
 }
 
-void Savemap::SetControlKey(const std::string control){control_ = control;}
+void Savemap::SetControlKey(const std::string control){
+    control_ = control;
+    empty_ = false;
+}
 
 /**
  * Sets the window colours in the current savemap.
@@ -119,8 +184,6 @@ void Savemap::SetGameTime(const unsigned int seconds){seconds_ = seconds;}
 
 void Savemap::SetCountdownTime(const unsigned int seconds){countdown_ = seconds;}
 
-void Savemap::SetField(const std::string field){field_map_ = field;}
-
 void Savemap::SetKeyItem(const unsigned int item, const bool owned){
     if (item < MAX_KEY_ITEM_SLOTS) key_items_[item] = owned;
 }
@@ -142,6 +205,7 @@ void Savemap::SetMateria(const unsigned int slot, const int id, const unsigned i
     if (slot < MAX_MATERIA_SLOTS){
         materia_[slot].id = id;
         materia_[slot].ap = ap;
+        materia_[slot].enemy_skill = false;
         for (int i = 0; i < MAX_ENEMY_SKILLS; i ++) materia_[slot].enemy_skill_learned[i] = false;
     }
 }
@@ -151,6 +215,7 @@ void Savemap::SetESkillMateria(const unsigned slot, const unsigned int skill, co
         // TODO: Maybe set enemy skill materia ID here?
         materia_[slot].ap = 0;
         materia_[slot].enemy_skill_learned[skill] = learned;
+        if (learned) materia_[slot].enemy_skill = true;
     }
 }
 
@@ -158,6 +223,7 @@ void Savemap::SetMateriaStash(const unsigned int slot, const int id, const unsig
     if (slot < MAX_STASH_SLOTS){
         materia_stash_[slot].id = id;
         materia_stash_[slot].ap = ap;
+        materia_stash_[slot].enemy_skill = false;
         for (int i = 0; i < MAX_ENEMY_SKILLS; i ++)
             materia_stash_[slot].enemy_skill_learned[i] = false;
     }
@@ -170,12 +236,13 @@ void Savemap::SetESkillMateriaStash(
         // TODO: Maybe set enemy skill materia ID here?
         materia_stash_[slot].ap = 0;
         materia_stash_[slot].enemy_skill_learned[skill] = learned;
+        if (learned) materia_stash_[slot].enemy_skill = true;
     }
 }
 
 void Savemap::SetLocation(
   const unsigned int x, const unsigned int y, const int z,
-  const unsigned int triangle, const int angle
+  const unsigned int triangle, const int angle, std::string field, std::string name
 ){
     if (z >= -1 && angle >= -360 && angle <= 360){
         location_.x = x;
@@ -183,6 +250,8 @@ void Savemap::SetLocation(
         location_.z = z;
         location_.triangle = triangle;
         location_.angle = angle;
+        location_.field = field;
+        location_.name = name;
     }
 }
 
@@ -274,12 +343,14 @@ void Savemap::SetCharacterMateria(
         if (weapon){
             characters_[id].weapon.materia[slot].id = id;
             characters_[id].weapon.materia[slot].ap = ap;
+            characters_[id].weapon.materia[slot].enemy_skill = false;
             for (int i = 0; i < MAX_ENEMY_SKILLS; i ++)
                 characters_[id].weapon.materia[slot].enemy_skill_learned[i] = false;
         }
         else{
             characters_[id].armor.materia[slot].id = id;
             characters_[id].armor.materia[slot].ap = ap;
+            characters_[id].armor.materia[slot].enemy_skill = false;
             for (int i = 0; i < MAX_ENEMY_SKILLS; i ++)
                 characters_[id].armor.materia[slot].enemy_skill_learned[i] = false;
         }
@@ -295,11 +366,13 @@ void Savemap::SetCharacterESkillMateria(
             // TODO: Maybe set enemy skill materia ID here?
             characters_[id].weapon.materia[slot].ap = 0;
             characters_[id].weapon.materia[slot].enemy_skill_learned[skill] = learned;
+            if (learned) characters_[id].weapon.materia[slot].enemy_skill = true;
         }
         else{
             // TODO: Maybe set enemy skill materia ID here?
             characters_[id].armor.materia[slot].ap = 0;
             characters_[id].armor.materia[slot].enemy_skill_learned[skill] = learned;
+            if (learned) characters_[id].armor.materia[slot].enemy_skill = true;
         }
     }
 }
@@ -310,130 +383,878 @@ void Savemap::SetCharacterStatus(
     //TODO
 }
 
-void Savemap::Write(std::string file_name){
-    std::fstream file;
-    file.open(file_name, std::ios::out);
-    if (!file) return;
-    file
-      << "Savemap = {\n"
-      << "    control = \"" << control_ << "\",\n"
-      << "    window_colours = {},\n"
-      << "    party = {" << party_[0] << ", " << party_[1] << ", " << party_[2] << "},\n"
-      << "    characters = {\n";
-    for (int c = 0; c < 9; c ++){
-        int total_count; // Utility to count in loops.
-        Character character = characters_[c];
-        file
-          << "        [" << c << "] = {\n"
-          << "            char_id = " << static_cast<int>(character.char_id) << ",\n"
-          << "            name = \"" << character.name << "\",\n"
-          << "            enabled = " << (character.enabled ? "true" : "false") << ",\n"
-          << "            locked = " << (character.locked ? "true" : "false") << ",\n"
-          << "            level = " << static_cast<int>(character.level) << ",\n"
-          << "            kills = " << character.kills << ",\n"
-          << "            back_row = " << (character.back_row ? "true" : "false") << ",\n"
-          << "            exp = " << character.exp << ",\n"
-          << "            exp_to_next = " << character.exp_to_next << " ,\n"
-          << "            stats = {\n"
-          << "                str = {base = " << character.str.base
-          << ", bonus = " << character.str.extra
-          << ", total = " << (character.str.base + character.str.extra) << "},\n"
-          << "                vit = {base = " << character.vit.base
-          << ", bonus = " << character.vit.extra
-          << ", total = " << (character.vit.base + character.vit.extra) << "},\n"
-          << "                mag = {base = " << character.mag.base
-          << ", bonus = " << character.mag.extra
-          << ", total = " << (character.mag.base + character.mag.extra) << "},\n"
-          << "                spr = {base = " << character.spr.base
-          << ", bonus = " << character.spr.extra
-          << ", total = " << (character.spr.base + character.spr.extra) << "},\n"
-          << "                dex = {base = " << character.dex.base
-          << ", bonus = " << character.dex.extra
-          << ", total = " << (character.dex.base + character.dex.extra) << "},\n"
-          << "                lck = {base = " << character.lck.base
-          << ", bonus = " << character.lck.extra
-          << ", total = " << (character.lck.base + character.lck.extra) << "},\n"
-          << "                hp = {current = " << character.hp.extra
-          << ", base = " << character.hp.base << ", max = 0},\n"
-          << "                mp = {current = " << character.mp.extra
-          << ", base = " << character.mp.base << ", max = 0},\n"
-          << "                atk = 0,\n"
-          << "                acc = 0,\n"
-          << "                def = 0,\n"
-          << "                eva = 0,\n"
-          << "                matk = 0,\n"
-          << "                mdef = 0,\n"
-          << "                meva = 0\n"
-          << "            },\n"
-          << "            limit = {\n"
-          << "                current = " << static_cast<int>(character.limit_level) << ",\n"
-          << "                bar = " << static_cast<int>(character.limit_bar) << ",\n"
-          << "                learned = {\n"
-          << "                    [1] = {[1] = "
-          << (character.limits_learned[0][0] == 1 ? "true" : "false")
-          << ", [2] = " << (character.limits_learned[0][1] == 1 ? "true" : "false") << "},\n"
-          << "                [2] = {[1] = "
-          << (character.limits_learned[1][0] == 1 ? "true" : "false")
-          << ", [2] = " << (character.limits_learned[1][1] == 1 ? "true" : "false") << "},\n"
-          << "                [3] = {[1] = "
-          << (character.limits_learned[2][0] == 1 ? "true" : "false")
-          << ", [2] = " << (character.limits_learned[2][1] == 1 ? "true" : "false") << "},\n"
-          << "                [4] = {[1] = "
-          << (character.limits_learned[3][0] == 1 ? "true" : "false")
-          << ", [2] = " << (character.limits_learned[3][1] == 1 ? "true" : "false") << "}\n"
-          << "                },\n"
-          << "                uses = {[1] = " << character.limit_uses[0] << ", [2] = "
-          << character.limit_uses[1] << ", [3] = " << character.limit_uses[2] << ", [4] = 0}\n"
-          << "            },\n"
-          << "            weapon = {\n"
-          << "                id = " << static_cast<int>(character.weapon.id) << ",\n"
-          << "                materia = {";
-        total_count = 0;
-        for (int m = 0; m < 8; m ++){
-            if (character.weapon.materia[m].id < 255){
-                total_count ++;
-                file << "\n                    [" << m << "] = {id = "
-                  << static_cast<int>(character.weapon.materia[m].id) << ", ap = "
-                  << character.weapon.materia[m].ap << "},";
-                // TODO: Enemy skills
+bool Savemap::IsEmpty(){return empty_;}
+
+std::string Savemap::GetPreviewData(){
+    std::string data = "";
+    data += std::to_string(slot_) + "#" + control_ + "#" + std::to_string(money_) + "#"
+      + std::to_string(seconds_) + "#" + location_.name + "#" + characters_[party_[0]].name + "#" +
+      std::to_string(characters_[party_[0]].level) + "#" + std::to_string(party_[0]) + "#"
+      + std::to_string(party_[1]) + "#" + std::to_string(party_[2]);
+    return data;
+}
+
+void Savemap::Write(int slot, std::string file_name){
+    TiXmlDocument xml;
+    std::unique_ptr<TiXmlElement> container(new TiXmlElement("Savemap"));
+    // Basic data
+    container->SetAttribute("slot", slot);
+    container->SetAttribute("key", control_);
+
+    // Window colours
+    std::unique_ptr<TiXmlElement> colours(new TiXmlElement("WindowColours"));
+    std::unique_ptr<TiXmlElement> colour_t_l(new TiXmlElement("Corner"));
+    colour_t_l->SetAttribute("position", "top_left");
+    colour_t_l->SetAttribute("red", window_colours_[0][0]);
+    colour_t_l->SetAttribute("green", window_colours_[0][1]);
+    colour_t_l->SetAttribute("blue", window_colours_[0][2]);
+    colours->LinkEndChild(colour_t_l.release());
+    std::unique_ptr<TiXmlElement> colour_t_r(new TiXmlElement("Corner"));
+    colour_t_r->SetAttribute("position", "top_right");
+    colour_t_r->SetAttribute("red", window_colours_[1][0]);
+    colour_t_r->SetAttribute("green", window_colours_[1][1]);
+    colour_t_r->SetAttribute("blue", window_colours_[1][2]);
+    colours->LinkEndChild(colour_t_r.release());
+    std::unique_ptr<TiXmlElement> colour_b_r(new TiXmlElement("Corner"));
+    colour_b_r->SetAttribute("position", "bottom_right");
+    colour_b_r->SetAttribute("red", window_colours_[2][0]);
+    colour_b_r->SetAttribute("green", window_colours_[2][1]);
+    colour_b_r->SetAttribute("blue", window_colours_[2][2]);
+    colours->LinkEndChild(colour_b_r.release());
+    std::unique_ptr<TiXmlElement> colour_b_l(new TiXmlElement("Corner"));
+    colour_b_l->SetAttribute("position", "bottom_left");
+    colour_b_l->SetAttribute("red", window_colours_[3][0]);
+    colour_b_l->SetAttribute("green", window_colours_[3][1]);
+    colour_b_l->SetAttribute("blue", window_colours_[3][2]);
+    colours->LinkEndChild(colour_b_l.release());
+    container->LinkEndChild(colours.release());
+
+    // Single data (when applicable)
+    if (money_ > 0){
+        std::unique_ptr<TiXmlElement> money(new TiXmlElement("Money"));
+        money->SetAttribute("quantity", money_);
+        container->LinkEndChild(money.release());
+    }
+    if (seconds_ > 0){
+        std::unique_ptr<TiXmlElement> time(new TiXmlElement("GameTime"));
+        time->SetAttribute("seconds", seconds_);
+        container->LinkEndChild(time.release());
+    }
+    if (seconds_ > 0){
+        std::unique_ptr<TiXmlElement> countdown(new TiXmlElement("Countdown"));
+        countdown->SetAttribute("seconds", countdown_);
+        container->LinkEndChild(countdown.release());
+    }
+
+    // Location.
+    std::unique_ptr<TiXmlElement> location(new TiXmlElement("Location"));
+    location->SetAttribute("x", location_.x);
+    location->SetAttribute("y", location_.y);
+    if (location_.z >= 0) location->SetAttribute("z", location_.z);
+    location->SetAttribute("triangle", location_.triangle);
+    location->SetAttribute("orientation", location_.angle);
+    location->SetAttribute("field", location_.field);
+    location->SetAttribute("name", location_.name);
+    container->LinkEndChild(location.release());
+
+    // Party.
+    std::unique_ptr<TiXmlElement> party(new TiXmlElement("Party"));
+    for (int p = 0; p < 3; p ++){
+        if (party_[p] >= 0 && party_[p] < MAX_CHARACTERS){
+            std::unique_ptr<TiXmlElement> member(new TiXmlElement("Member"));
+            member->SetAttribute("position", p);
+            member->SetAttribute("character_id", party_[p]);
+            party->LinkEndChild(member.release());
+        }
+    }
+    container->LinkEndChild(party.release());
+
+    // Items.
+    std::unique_ptr<TiXmlElement> items(new TiXmlElement("Items"));
+    for (int i = 0; i < MAX_ITEM_SLOTS; i ++){
+        if (items_[i].quantity > 0){
+            std::unique_ptr<TiXmlElement> item(new TiXmlElement("Item"));
+            item->SetAttribute("slot", i);
+            item->SetAttribute("id", items_[i].id);
+            item->SetAttribute("quantity", items_[i].quantity);
+            items->LinkEndChild(item.release());
+        }
+    }
+    container->LinkEndChild(items.release());
+
+    // Key items.
+    std::unique_ptr<TiXmlElement> key_items(new TiXmlElement("KeyItems"));
+    for (int i = 0; i < MAX_KEY_ITEM_SLOTS; i ++){
+        if (key_items_[i]){
+            std::unique_ptr<TiXmlElement> key_item(new TiXmlElement("Item"));
+            key_item->SetAttribute("id", key_items_[i]);
+            key_item->SetAttribute("owned", true);
+            key_items->LinkEndChild(key_item.release());
+        }
+    }
+    container->LinkEndChild(key_items.release());
+
+    // Materia.
+    std::unique_ptr<TiXmlElement> materias(new TiXmlElement("Materia"));
+    for (int i = 0; i < MAX_MATERIA_SLOTS; i ++){
+        if (materia_[i].id >= 0){
+            std::unique_ptr<TiXmlElement> materia(new TiXmlElement("Materia"));
+            materia->SetAttribute("slot", i);
+            materia->SetAttribute("id", materia_[i].id);
+            materia->SetAttribute("ap", materia_[i].ap);
+            if (materia_[i].enemy_skill){
+                materia->SetAttribute("enemy_skill", true);
+                std::unique_ptr<TiXmlElement> enemy_skills(new TiXmlElement("EnemySkill"));
+                for (int s = 0; s < MAX_ENEMY_SKILLS; s ++){
+                    if (materia_[i].enemy_skill_learned[s]){
+                        std::unique_ptr<TiXmlElement> enemy_skill(new TiXmlElement("Skill"));
+                        enemy_skill->SetAttribute("id", s);
+                        enemy_skill->SetAttribute("learned", true);
+                        enemy_skills->LinkEndChild(enemy_skill.release());
+                    }
+                    materia->LinkEndChild(enemy_skills.release());
+                }
+            }
+            materias->LinkEndChild(materia.release());
+        }
+    }
+    container->LinkEndChild(materias.release());
+
+    // Materia stash.
+    std::unique_ptr<TiXmlElement> stash(new TiXmlElement("MateriaStash"));
+    for (int i = 0; i < MAX_STASH_SLOTS; i ++){
+        if (materia_stash_[i].id >= 0){
+            std::unique_ptr<TiXmlElement> materia(new TiXmlElement("Materia"));
+            materia->SetAttribute("slot", i);
+            materia->SetAttribute("id", materia_[i].id);
+            materia->SetAttribute("ap", materia_[i].ap);
+            if (materia_stash_[i].enemy_skill){
+                materia->SetAttribute("enemy_skill", true);
+                std::unique_ptr<TiXmlElement> enemy_skills(new TiXmlElement("EnemySkill"));
+                for (int s = 0; s < MAX_ENEMY_SKILLS; s ++){
+                    if (materia_stash_[i].enemy_skill_learned[s]){
+                        std::unique_ptr<TiXmlElement> enemy_skill(new TiXmlElement("Skill"));
+                        enemy_skill->SetAttribute("id", s);
+                        enemy_skill->SetAttribute("learned", true);
+                        enemy_skills->LinkEndChild(enemy_skill.release());
+                    }
+                    materia->LinkEndChild(enemy_skills.release());
+                }
+            }
+            stash->LinkEndChild(materia.release());
+        }
+    }
+    container->LinkEndChild(stash.release());
+
+    // TODO: Settings
+
+    // Characters
+    std::unique_ptr<TiXmlElement> characters(new TiXmlElement("Characters"));
+    for (int c = 0; c < MAX_CHARACTERS; c ++){
+        if (characters_[c].char_id == -1) continue;
+
+        std::unique_ptr<TiXmlElement> character(new TiXmlElement("Character"));
+
+        // Basic information.
+        character->SetAttribute("id", characters_[c].id);
+        character->SetAttribute("char_id", characters_[c].char_id);
+        character->SetAttribute("name", characters_[c].name);
+        character->SetAttribute("level", characters_[c].level);
+        character->SetAttribute("enabled", characters_[c].enabled);
+        character->SetAttribute("locked", characters_[c].locked);
+        character->SetAttribute("kills", characters_[c].kills);
+        character->SetAttribute("back_row", characters_[c].back_row);
+        character->SetAttribute("exp", characters_[c].exp);
+        character->SetAttribute("exp_to_next", characters_[c].exp_to_next);
+
+        // Stats.
+        std::unique_ptr<TiXmlElement> character_stats(new TiXmlElement("Stats"));
+        std::unique_ptr<TiXmlElement> character_stats_str(new TiXmlElement("Stat"));
+        character_stats_str->SetAttribute("id", "str");
+        character_stats_str->SetAttribute("base", characters_[c].str.base);
+        character_stats_str->SetAttribute("bonus", characters_[c].str.extra);
+        character_stats->LinkEndChild(character_stats_str.release());
+        std::unique_ptr<TiXmlElement> character_stats_vit(new TiXmlElement("Stat"));
+        character_stats_vit->SetAttribute("id", "vit");
+        character_stats_vit->SetAttribute("base", characters_[c].vit.base);
+        character_stats_vit->SetAttribute("bonus", characters_[c].vit.extra);
+        character_stats->LinkEndChild(character_stats_vit.release());
+        std::unique_ptr<TiXmlElement> character_stats_mag(new TiXmlElement("Stat"));
+        character_stats_mag->SetAttribute("id", "mag");
+        character_stats_mag->SetAttribute("base", characters_[c].mag.base);
+        character_stats_mag->SetAttribute("bonus", characters_[c].mag.extra);
+        character_stats->LinkEndChild(character_stats_mag.release());
+        std::unique_ptr<TiXmlElement> character_stats_spr(new TiXmlElement("Stat"));
+        character_stats_spr->SetAttribute("id", "spr");
+        character_stats_spr->SetAttribute("base", characters_[c].spr.base);
+        character_stats_spr->SetAttribute("bonus", characters_[c].spr.extra);
+        character_stats->LinkEndChild(character_stats_spr.release());
+        std::unique_ptr<TiXmlElement> character_stats_dex(new TiXmlElement("Stat"));
+        character_stats_dex->SetAttribute("id", "dex");
+        character_stats_dex->SetAttribute("base", characters_[c].dex.base);
+        character_stats_dex->SetAttribute("bonus", characters_[c].dex.extra);
+        character_stats->LinkEndChild(character_stats_dex.release());
+        std::unique_ptr<TiXmlElement> character_stats_lck(new TiXmlElement("Stat"));
+        character_stats_lck->SetAttribute("id", "lck");
+        character_stats_lck->SetAttribute("base", characters_[c].lck.base);
+        character_stats_lck->SetAttribute("bonus", characters_[c].lck.extra);
+        character_stats->LinkEndChild(character_stats_lck.release());
+        std::unique_ptr<TiXmlElement> character_stats_hp(new TiXmlElement("Stat"));
+        character_stats_hp->SetAttribute("id", "hp");
+        character_stats_hp->SetAttribute("base", characters_[c].hp.base);
+        character_stats_hp->SetAttribute("current", characters_[c].hp.extra);
+        character_stats->LinkEndChild(character_stats_hp.release());
+        std::unique_ptr<TiXmlElement> character_stats_mp(new TiXmlElement("Stat"));
+        character_stats_mp->SetAttribute("id", "mp");
+        character_stats_mp->SetAttribute("base", characters_[c].mp.base);
+        character_stats_mp->SetAttribute("current", characters_[c].mp.extra);
+        character_stats->LinkEndChild(character_stats_mp.release());
+        character->LinkEndChild(character_stats.release());
+
+        // Limit information.
+        std::unique_ptr<TiXmlElement> character_limits(new TiXmlElement("Limits"));
+        character_limits->SetAttribute("current", characters_[c].limit_level);
+        character_limits->SetAttribute("bar", characters_[c].limit_bar);
+        for (int l = 0; l < MAX_LIMIT_LEVELS; l ++){
+            std::unique_ptr<TiXmlElement> character_limits_level(new TiXmlElement("Level"));
+            character_limits_level->SetAttribute("level", l);
+            character_limits_level->SetAttribute("uses", characters_[c].limit_uses[l]);
+            for (int t = 0; t < MAX_LIMIT_TECHNIQUES; t ++){
+                if (characters_[c].limits_learned[l][t]){
+                    std::unique_ptr<TiXmlElement> character_limits_level_technique(
+                      new TiXmlElement("Technique")
+                    );
+                    character_limits_level_technique->SetAttribute("id", t);
+                    character_limits_level_technique->SetAttribute("learned", true);
+                    character_limits_level->LinkEndChild(
+                      character_limits_level_technique.release()
+                    );
+                }
             }
+            character_limits->LinkEndChild(character_limits_level.release());
         }
-        if (total_count > 0) file << "\n                }\n        },\n";
-        else file << "        }\n        },\n";
-        file
-          << "            armor = {\n"
-          << "                id = " << static_cast<int>(character.armor.id) << ",\n"
-          << "                materia = {";
-        total_count = 0;
-        for (int m = 0; m < 8; m ++){
-            if (character.armor.materia[m].id < 255){
-                total_count ++;
-                file << "\n                    [" << m << "] = {id = "
-                  << static_cast<int>(character.armor.materia[m].id) << ", ap = "
-                  << character.armor.materia[m].ap << "},";
-                // TODO: Enemy skills
+        character->LinkEndChild(character_limits.release());
+
+        // Weapon.
+        std::unique_ptr<TiXmlElement> character_weapon(new TiXmlElement("Weapon"));
+        character_weapon->SetAttribute("id", characters_[c].weapon.id);
+        std::unique_ptr<TiXmlElement> character_weapon_materia(new TiXmlElement("Materia"));
+        for (int m = 0; m < MAX_EQUIP_SLOTS; m ++){
+            if (characters_[c].weapon.materia[m].id >= 0){
+                std::unique_ptr<TiXmlElement> materia(new TiXmlElement("Materia"));
+                materia->SetAttribute("slot", m);
+                materia->SetAttribute("id", characters_[c].weapon.materia[m].id);
+                materia->SetAttribute("ap", characters_[c].weapon.materia[m].ap);
+                if (characters_[c].weapon.materia[m].enemy_skill){
+                    materia->SetAttribute("enemy_skill", true);
+                    std::unique_ptr<TiXmlElement> character_weapon_enemy_skills(
+                      new TiXmlElement("EnemySkill")
+                    );
+                    for (int s = 0; s < MAX_ENEMY_SKILLS; s ++){
+                        if (characters_[c].weapon.materia[m].enemy_skill_learned[s]){
+                            std::unique_ptr<TiXmlElement> enemy_skill(new TiXmlElement("Skill"));
+                            enemy_skill->SetAttribute("id", s);
+                            enemy_skill->SetAttribute("learned", true);
+                            character_weapon_enemy_skills->LinkEndChild(enemy_skill.release());
+                        }
+                        materia->LinkEndChild(character_weapon_enemy_skills.release());
+                    }
+                }
+                character_weapon_materia->LinkEndChild(materia.release());
             }
         }
-        if (total_count > 0) file << "\n                }\n        },\n";
-        else file << "        }\n        },\n";
-        file << "            accessory = ";
-        if (character.accessory < 0xFF) file << static_cast<int>(character.accessory);
-        else file << "nil";
-        file << ",\n            status = {";
-        // TODO: Loop statuses
-        //if (character.fury) file << FURY;
-        //if (character.sadness) file << SADNESS;
-        file << "}\n        },\n";
+        character_weapon->LinkEndChild(character_weapon_materia.release());
+        character->LinkEndChild(character_weapon.release());
+
+        // Armor.
+        std::unique_ptr<TiXmlElement> character_armor(new TiXmlElement("Armor"));
+        character_armor->SetAttribute("id", characters_[c].armor.id);
+        std::unique_ptr<TiXmlElement> character_armor_materia(new TiXmlElement("Materia"));
+        for (int m = 0; m < MAX_EQUIP_SLOTS; m ++){
+            if (characters_[c].armor.materia[m].id >= 0){
+                std::unique_ptr<TiXmlElement> materia(new TiXmlElement("Materia"));
+                materia->SetAttribute("slot", m);
+                materia->SetAttribute("id", characters_[c].armor.materia[m].id);
+                materia->SetAttribute("ap", characters_[c].armor.materia[m].ap);
+                if (characters_[c].armor.materia[m].enemy_skill){
+                    materia->SetAttribute("enemy_skill", true);
+                    std::unique_ptr<TiXmlElement> character_armor_enemy_skills(
+                      new TiXmlElement("EnemySkill")
+                    );
+                    for (int s = 0; s < MAX_ENEMY_SKILLS; s ++){
+                        if (characters_[c].armor.materia[m].enemy_skill_learned[s]){
+                            std::unique_ptr<TiXmlElement> enemy_skill(new TiXmlElement("Skill"));
+                            enemy_skill->SetAttribute("id", s);
+                            enemy_skill->SetAttribute("learned", true);
+                            character_armor_enemy_skills->LinkEndChild(enemy_skill.release());
+                        }
+                        materia->LinkEndChild(character_armor_enemy_skills.release());
+                    }
+                }
+                character_armor_materia->LinkEndChild(materia.release());
+            }
+        }
+        character_armor->LinkEndChild(character_armor_materia.release());
+        character->LinkEndChild(character_armor.release());
+
+        // Accessory.
+        if (characters_[c].accessory >= 0){
+            std::unique_ptr<TiXmlElement> character_accessory(new TiXmlElement("Accessory"));
+            character_accessory->SetAttribute("id", characters_[c].accessory);
+            character->LinkEndChild(character_accessory.release());
+        }
+        characters->LinkEndChild(character.release());
 
+        // TODO: Statuses
     }
-    file << "    },\n    data = {\n";
+    container->LinkEndChild(characters.release());
+
+    // Data banks.
+    std::unique_ptr<TiXmlElement> banks(new TiXmlElement("DataBanks"));
     for (int b = 0; b < BANK_COUNT; b ++){
-        file << "        [" << b << "] = {\n";
+        std::unique_ptr<TiXmlElement> bank(new TiXmlElement("Bank"));
+        bank->SetAttribute("id", b);
         for (int a = 0; a < BANK_ADDRESS_COUNT; a ++){
-            if (data_[b][a] != 0) file << "            [" << a << "] = " << data_[b][a] << ",\n";
+            if (data_[b][a] != 0){
+                std::unique_ptr<TiXmlElement> address(new TiXmlElement("Address"));
+                address->SetAttribute("address", a);
+                address->SetAttribute("value", data_[b][a]);
+                bank->LinkEndChild(address.release());
+            }
+        }
+        banks->LinkEndChild(bank.release());
+    }
+    container->LinkEndChild(banks.release());
+
+    // Save
+    xml.LinkEndChild(container.release());
+    xml.SaveFile(file_name);
+    slot_ = slot;
+    return;
+
+}
+
+void Savemap::Read(std::string file_name){
+    // TODO: This need a try/catch, it's impossible to validate every value and type in the file.
+    TiXmlDocument xml_file(file_name);
+    if (xml_file.LoadFile() == false){
+        empty_ = true;
+        return;
+    }
+
+    TiXmlNode* node = xml_file.RootElement();
+    if (node == nullptr || node->ValueStr() != "Savemap"){
+        LOG_ERROR(
+          "Savemap: " + file_name + " is not a valid savemap file! No <Savemap> in root."
+        );
+        empty_ = true;
+        return;
+    }
+
+    slot_ = node->ToElement()->QueryIntAttribute("slot", &slot_);
+    control_ = node->ToElement()->QueryStringAttribute("slot", &control_);
+    // Make sure that control is not just a null character!
+    // This would break many things,
+    if (control_.size() < 2) control_ = "X";
+    empty_ = false;
+
+    node = node->FirstChild();
+    while (node != nullptr){
+        if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "WindowColours"){
+            TiXmlNode* colour_node = node->FirstChild();
+            while (colour_node != nullptr){
+                if (
+                  colour_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                  && colour_node->ValueStr() == "Corner"
+                ){
+                    std::string position;
+                    TiXmlElement* colour_elm = colour_node->ToElement();
+                    colour_elm->QueryStringAttribute("position", &position);
+                    int colour;
+                    if (position == "top_left"){
+                        colour = -1;
+                        colour_elm->QueryIntAttribute("red", &colour);
+                        if (colour >= 0 && colour < MAX_COLOUR) window_colours_[0][0] = colour;
+                        colour = -1;
+                        colour_elm->QueryIntAttribute("green", &colour);
+                        if (colour >= 0 && colour < MAX_COLOUR) window_colours_[0][1] = colour;
+                        colour = -1;
+                        colour_elm->QueryIntAttribute("blue", &colour);
+                        if (colour >= 0 && colour < MAX_COLOUR) window_colours_[0][2] = colour;
+                    }
+                    else if (position == "top_right"){
+                        colour = -1;
+                        colour_elm->QueryIntAttribute("red", &colour);
+                        if (colour >= 0 && colour < MAX_COLOUR) window_colours_[1][0] = colour;
+                        colour = -1;
+                        colour_elm->QueryIntAttribute("green", &colour);
+                        if (colour >= 0 && colour < MAX_COLOUR) window_colours_[1][1] = colour;
+                        colour = -1;
+                        colour_elm->QueryIntAttribute("blue", &colour);
+                        if (colour >= 0 && colour < MAX_COLOUR) window_colours_[1][2] = colour;
+                    }
+                    else if (position == "bottom_right"){
+                        colour = -1;
+                        colour_elm->QueryIntAttribute("red", &colour);
+                        if (colour >= 0 && colour < MAX_COLOUR) window_colours_[2][0] = colour;
+                        colour = -1;
+                        colour_elm->QueryIntAttribute("green", &colour);
+                        if (colour >= 0 && colour < MAX_COLOUR) window_colours_[2][1] = colour;
+                        colour = -1;
+                        colour_elm->QueryIntAttribute("blue", &colour);
+                        if (colour >= 0 && colour < MAX_COLOUR) window_colours_[2][2] = colour;
+                    }
+                    else if (position == "bottol_left"){
+                        colour = -1;
+                        colour_elm->QueryIntAttribute("red", &colour);
+                        if (colour >= 0 && colour < MAX_COLOUR) window_colours_[3][0] = colour;
+                        colour = -1;
+                        colour_elm->QueryIntAttribute("green", &colour);
+                        if (colour >= 0 && colour < MAX_COLOUR) window_colours_[3][1] = colour;
+                        colour = -1;
+                        colour_elm->QueryIntAttribute("blue", &colour);
+                        if (colour >= 0 && colour < MAX_COLOUR) window_colours_[3][2] = colour;
+                    }
+                }
+                colour_node = colour_node->NextSibling();
+            }
+        }
+        else if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "Money"){
+            int money = -1;
+            node->ToElement()->QueryIntAttribute("quantity", &money);
+            if (money >= 0) money_ = money;
+        }
+        else if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "GameTime"){
+            int seconds = -1;
+            node->ToElement()->QueryIntAttribute("seconds", &seconds);
+            if (seconds >= 0) seconds_ = seconds;
+        }
+        else if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "Countdown"){
+            int seconds = -1;
+            node->ToElement()->QueryIntAttribute("seconds", &seconds);
+            if (seconds >= 0) countdown_ = seconds;
+        }
+        else if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "Location"){
+            int val = -1;
+            node->ToElement()->QueryIntAttribute("x", &val);
+            if (val >= 0) location_.x = val;
+            val = -1;
+            node->ToElement()->QueryIntAttribute("y", &val);
+            if (val >= 0) location_.y = val;
+            val = -1;
+            node->ToElement()->QueryIntAttribute("z", &val);
+            if (val >= -1) location_.z = val;
+            val = -1;
+            node->ToElement()->QueryIntAttribute("triangle", &val);
+            if (val >= 0) location_.triangle = val;
+            val = -1;
+            node->ToElement()->QueryIntAttribute("angle", &val);
+            if (val >= -360 && val <=360) location_.angle = val;
+            node->ToElement()->QueryStringAttribute("field", &location_.field);
+            node->ToElement()->QueryStringAttribute("name", &location_.name);
+        }
+        else if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "Party"){
+            TiXmlNode* party_node = node->FirstChild();
+            while (party_node != nullptr){
+                if (
+                    party_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                  && party_node->ValueStr() == "Member"
+                ){
+                    int position = -1;
+                    int member = -1;
+                    TiXmlElement* party_elm = party_node->ToElement();
+                    party_elm->QueryIntAttribute("position", &position);
+                    party_elm->QueryIntAttribute("character_id", &member);
+                    if (
+                      position >= 0 && position < MAX_PARTY_MEMBERS
+                      && member >= 0 && member < MAX_CHARACTERS
+                    ){
+                        party_[position] = member;
+                    }
+                }
+                party_node = party_node->NextSibling();
+            }
+        }
+        else if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "Items"){
+            TiXmlNode* item_node = node->FirstChild();
+            while (item_node != nullptr){
+                if (
+                  item_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                  && item_node->ValueStr() == "Item"
+                ){
+                    int slot = -1;
+                    int id = -1;
+                    int quantity = -1;
+                    TiXmlElement* item_elm = item_node->ToElement();
+                    item_elm->QueryIntAttribute("slot", &slot);
+                    item_elm->QueryIntAttribute("id", &id);
+                    item_elm->QueryIntAttribute("quantity", &quantity);
+                    if (slot >= 0 && slot < MAX_ITEM_SLOTS && id >= 0 && quantity > 0){
+                        items_[slot].id = id;
+                        items_[slot].quantity = quantity;
+                    }
+                }
+                item_node = item_node->NextSibling();
+            }
+        }
+        else if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "KeyItems"){
+            TiXmlNode* item_node = node->FirstChild();
+            while (item_node != nullptr){
+                if (
+                  item_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                  && item_node->ValueStr() == "Item"
+                ){
+                    int id;
+                    int owned;
+                    TiXmlElement* item_elm = item_node->ToElement();
+                    item_elm->QueryIntAttribute("id", &id);
+                    item_elm->QueryIntAttribute("owned", &owned);
+                    if (id >= 0 && id < MAX_KEY_ITEM_SLOTS && owned == 1) key_items_[id] = true;
+                }
+                item_node = item_node->NextSibling();
+            }
+        }
+        else if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "Materia"){
+            TiXmlNode* materia_node = node->FirstChild();
+            while (materia_node != nullptr){
+                if (
+                  materia_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                  && materia_node->ValueStr() == "Materia"
+                ){
+                    int slot = -1;
+                    int id = -2;
+                    int ap = -1;
+                    int eskill = 0;
+                    TiXmlElement* materia_elm = materia_node->ToElement();
+                    materia_elm->QueryIntAttribute("slot", &slot);
+                    materia_elm->QueryIntAttribute("id", &id);
+                    materia_elm->QueryIntAttribute("ap", &ap);
+                    materia_elm->QueryIntAttribute("enemy_skill", &ap);
+                    if (
+                      slot >= 0 && slot < MAX_MATERIA_SLOTS && id >= -1
+                      && ap >= 0 && (eskill == 0 | eskill == 1)
+                    ){
+                        materia_[slot].id = id;
+                        materia_[slot].ap = ap;
+                        materia_[slot].enemy_skill = (eskill == 1);
+                        // TODO: For enemy skill, get learned.
+                    }
+                }
+                materia_node = materia_node->NextSibling();
+            }
+        }
+        else if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "MateriaStash"){
+            TiXmlNode* materia_node = node->FirstChild();
+            while (materia_node != nullptr){
+                if (
+                    materia_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                  && materia_node->ValueStr() == "Materia"
+                ){
+                    int slot = -1;
+                    int id = -2;
+                    int ap = -1;
+                    int eskill = 0;
+                    TiXmlElement* materia_elm = materia_node->ToElement();
+                    materia_elm->QueryIntAttribute("slot", &slot);
+                    materia_elm->QueryIntAttribute("id", &id);
+                    materia_elm->QueryIntAttribute("ap", &ap);
+                    materia_elm->QueryIntAttribute("enemy_skill", &ap);
+                    if (
+                      slot >= 0 && slot < MAX_STASH_SLOTS && id >= -1
+                      && ap >= 0 && (eskill == 0 | eskill == 1)
+                    ){
+                        materia_stash_[slot].id = id;
+                        materia_stash_[slot].ap = ap;
+                        materia_stash_[slot].enemy_skill = (eskill == 1);
+                        // TODO: For enemy skill, get learned.
+                    }
+                }
+                materia_node = materia_node->NextSibling();
+            }
+        }
+        else if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "Characters"){
+            TiXmlNode* character_node = node->FirstChild();
+            while (character_node != nullptr){
+                if (
+                    character_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                  && character_node->ValueStr() == "Character"
+                ){
+                    int id = -1;
+                    TiXmlElement* character_elm = character_node->ToElement();
+                    character_elm->QueryIntAttribute("id", &id);
+                    if (id >= 0 && id < MAX_CHARACTERS){
+                        characters_[id].id = id;
+                        int val = -2;
+                        character_elm->QueryIntAttribute("char_id", &val);
+                        if (val >= -1) characters_[id].char_id = val;
+                        character_elm->QueryStringAttribute("name", &characters_[id].name);
+                        val = -1;
+                        character_elm->QueryIntAttribute("enabled", &val);
+                        if (val == 1) characters_[id].enabled = true;
+                        else characters_[id].enabled = false;
+                        val = -1;
+                        character_elm->QueryIntAttribute("locked", &val);
+                        characters_[id].locked = (val == 1);
+                        val = -1;
+                        character_elm->QueryIntAttribute("level", &val);
+                        if (val > 0) characters_[id].level = val;
+                        val = -1;
+                        character_elm->QueryIntAttribute("kills", &val);
+                        if (val >= 0) characters_[id].kills = val;
+                        val = -1;
+                        character_elm->QueryIntAttribute("back_row", &val);
+                        characters_[id].back_row = (val == 1);
+                        val = -1;
+                        character_elm->QueryIntAttribute("exp", &val);
+                        if (val >= 0) characters_[id].exp = val;
+                        val = -1;
+                        character_elm->QueryIntAttribute("exp_to_next", &val);
+                        if (val >= 0) characters_[id].exp_to_next = val;
+                        TiXmlNode* char_node = character_node->FirstChild();
+                        while (char_node != nullptr){
+                            if (
+                              char_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                              && char_node->ValueStr() == "Stats"
+                            ){
+                                TiXmlNode* stat_node = char_node->FirstChild();
+                                while (stat_node != nullptr){
+                                    if (
+                                      char_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                                      && char_node->ValueStr() == "Stat"
+                                    ){
+                                        std::string stat = "";
+                                        int base = -1;
+                                        int extra = -1;
+                                        TiXmlElement* stat_elm = stat_node->ToElement();
+                                        stat_elm->QueryStringAttribute("id", &stat);
+                                        if (stat == "str"){
+                                            stat_elm->QueryIntAttribute("base", &base);
+                                            stat_elm->QueryIntAttribute("bonus", &extra);
+                                            if (base >= 0 && extra >= 0){
+                                                characters_[id].str.base = base;
+                                                characters_[id].str.extra = extra;
+                                            }
+                                        }
+
+                                        else if (stat == "vit"){
+                                            stat_elm->QueryIntAttribute("base", &base);
+                                            stat_elm->QueryIntAttribute("bonus", &extra);
+                                            if (base >= 0 && extra >= 0){
+                                                characters_[id].vit.base = base;
+                                                characters_[id].vit.extra = extra;
+                                            }
+                                        }
+                                        else if (stat == "mag"){
+                                            stat_elm->QueryIntAttribute("base", &base);
+                                            stat_elm->QueryIntAttribute("bonus", &extra);
+                                            if (base >= 0 && extra >= 0){
+                                                characters_[id].mag.base = base;
+                                                characters_[id].mag.extra = extra;
+                                            }
+                                        }
+                                        else if (stat == "spr"){
+                                            stat_elm->QueryIntAttribute("base", &base);
+                                            stat_elm->QueryIntAttribute("bonus", &extra);
+                                            if (base >= 0 && extra >= 0){
+                                                characters_[id].spr.base = base;
+                                                characters_[id].spr.extra = extra;
+                                            }
+                                        }
+                                        else if (stat == "dex"){
+                                            stat_elm->QueryIntAttribute("base", &base);
+                                            stat_elm->QueryIntAttribute("bonus", &extra);
+                                            if (base >= 0 && extra >= 0){
+                                                characters_[id].dex.base = base;
+                                                characters_[id].dex.extra = extra;
+                                            }
+                                        }
+                                        else if (stat == "lck"){
+                                            stat_elm->QueryIntAttribute("base", &base);
+                                            stat_elm->QueryIntAttribute("bonus", &extra);
+                                            if (base >= 0 && extra >= 0){
+                                                characters_[id].lck.base = base;
+                                                characters_[id].lck.extra = extra;
+                                            }
+                                        }
+                                        else if (stat == "hp"){
+                                            stat_elm->QueryIntAttribute("base", &base);
+                                            stat_elm->QueryIntAttribute("current", &extra);
+                                            if (base > 0 && extra >= 0){
+                                                characters_[id].hp.base = base;
+                                                characters_[id].hp.extra = extra;
+                                            }
+                                        }
+                                        else if (stat == "mp"){
+                                            stat_elm->QueryIntAttribute("base", &base);
+                                            stat_elm->QueryIntAttribute("current", &extra);
+                                            if (base > 0 && extra >= 0){
+                                                characters_[id].mp.base = base;
+                                                characters_[id].mp.extra = extra;
+                                            }
+                                        }
+                                    }
+                                    stat_node = stat_node->NextSibling();
+                                }
+                            }
+                            else if (
+                              char_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                              && char_node->ValueStr() == "Limits"
+                            ){
+                                int val = -1;
+                                char_node->ToElement()->QueryIntAttribute("current", &val);
+                                if (val >= 0 && val < MAX_LIMIT_LEVELS)
+                                    characters_[id].limit_level = val;
+                                val = -1;
+                                char_node->ToElement()->QueryIntAttribute("bar", &val);
+                                if (val >= 0 && val <= MAX_LIMIT_BAR)
+                                    characters_[id].limit_bar = val;
+                                TiXmlNode* limits_node = char_node->FirstChild();
+                                while (limits_node != nullptr){
+                                    if (
+                                        limits_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                                      && limits_node->ValueStr() == "Level"
+                                    ){
+                                        int level = -1;
+                                        int uses = -1;
+                                        limits_node->ToElement()->QueryIntAttribute(
+                                          "level", &level
+                                        );
+                                        limits_node->ToElement()->QueryIntAttribute(
+                                          "uses", &uses
+                                        );
+                                        if (level >= 0 && level < MAX_LIMIT_LEVELS){
+                                            if (uses >= 0) characters_[id].limit_uses[level] = uses;
+                                            TiXmlNode* tech_node = limits_node->FirstChild();
+                                            while (tech_node != nullptr){
+                                                if (
+                                                  tech_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                                                  && tech_node->ValueStr() == "Technique"
+                                                ){
+                                                    int tech = -1;
+                                                    int learned = -1;
+                                                    tech_node->ToElement()->QueryIntAttribute(
+                                                      "id", &tech
+                                                    );
+                                                    tech_node->ToElement()->QueryIntAttribute(
+                                                      "learned", &learned
+                                                    );
+                                                    if (tech >= 0 && tech < MAX_LIMIT_TECHNIQUES){
+                                                        characters_[id].limits_learned[level][tech]
+                                                          = (learned == 1);
+                                                    }
+                                                }
+                                                tech_node = tech_node->NextSibling();
+                                            }
+                                        }
+                                    }
+                                    limits_node = limits_node->NextSibling();
+                                }
+                            }
+                            else if (
+                              char_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                              && char_node->ValueStr() == "Weapon"
+                            ){
+                                int wpn = -1;
+                                char_node->ToElement()->QueryIntAttribute("id", &wpn);
+                                if (wpn >= 0) characters_[id].weapon.id = wpn;
+                                TiXmlNode* mats_node = char_node->FirstChild();
+                                if (
+                                  mats_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                                  && mats_node->ValueStr() == "Materia"
+                                ){
+                                    TiXmlNode* mat_node = mats_node->FirstChild();
+                                    while (mat_node != nullptr){
+                                        if (
+                                          mat_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                                          && mat_node->ValueStr() == "Materia"
+                                        ){
+                                            int slot = -1;
+                                            int id = -2;
+                                            int ap = -1;
+                                            int eskill = 0;
+                                            TiXmlElement* mat_elm = mat_node->ToElement();
+                                            mat_elm->QueryIntAttribute("slot", &slot);
+                                            mat_elm->QueryIntAttribute("id", &id);
+                                            mat_elm->QueryIntAttribute("ap", &ap);
+                                            mat_elm->QueryIntAttribute("enemy_skill", &ap);
+                                            if (
+                                              slot >= 0 && slot < MAX_EQUIP_SLOTS && id >= -1
+                                              && ap >= 0 && (eskill == 0 | eskill == 1)
+                                            ){
+                                                characters_[id].weapon.materia[slot].id = id;
+                                                characters_[id].weapon.materia[slot].ap = ap;
+                                                characters_[id].weapon.materia[slot].enemy_skill
+                                                  = (eskill == 1);
+                                                // TODO: For enemy skill, get learned.
+                                            }
+                                        }
+                                        mat_node = mat_node->NextSibling();
+                                    }
+                                }
+                            }
+                            else if (
+                              char_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                              && char_node->ValueStr() == "Armor"
+                            ){
+                                int arm = -1;
+                                char_node->ToElement()->QueryIntAttribute("id", &arm);
+                                if (arm >= 0) characters_[id].armor.id = arm;
+                                TiXmlNode* mats_node = char_node->FirstChild();
+                                if (
+                                  mats_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                                  && mats_node->ValueStr() == "Materia"
+                                ){
+                                    TiXmlNode* mat_node = mats_node->FirstChild();
+                                    while (mat_node != nullptr){
+                                        if (
+                                          mat_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                                          && mat_node->ValueStr() == "Materia"
+                                        ){
+                                            int slot = -1;
+                                            int id = -2;
+                                            int ap = -1;
+                                            int eskill = 0;
+                                            TiXmlElement* mat_elm = mat_node->ToElement();
+                                            mat_elm->QueryIntAttribute("slot", &slot);
+                                            mat_elm->QueryIntAttribute("id", &id);
+                                            mat_elm->QueryIntAttribute("ap", &ap);
+                                            mat_elm->QueryIntAttribute("enemy_skill", &ap);
+                                            if (
+                                              slot >= 0 && slot < MAX_EQUIP_SLOTS && id >= -1
+                                              && ap >= 0 && (eskill == 0 | eskill == 1)
+                                            ){
+                                                characters_[id].armor.materia[slot].id = id;
+                                                characters_[id].armor.materia[slot].ap = ap;
+                                                characters_[id].armor.materia[slot].enemy_skill
+                                                  = (eskill == 1);
+                                                // TODO: For enemy skill, get learned.
+                                            }
+                                        }
+                                        mat_node = mat_node->NextSibling();
+                                    }
+                                }
+                            }
+                            else if (
+                              char_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                              && char_node->ValueStr() == "Accessory"
+                            ){
+                                int acc = -2;
+                                char_node->ToElement()->QueryIntAttribute("id", &acc);
+                                if (acc >= -1) characters_[id].accessory = acc;
+                            }
+                            else if (
+                              char_node->Type() == TiXmlNode::TINYXML_ELEMENT
+                              && char_node->ValueStr() == "Status"
+                            ){
+                                  // TODO
+                            }
+                            char_node = char_node->NextSibling();
+                        }
+                    }
+                }
+                character_node = character_node->NextSibling();
+            }
         }
-        file << "        },\n";
+        node = node->NextSibling();
     }
-    file << "    }\n}\n";
-    file.close();
 }

+ 66 - 11
V-Gears/src/core/SavemapManager.cpp

@@ -49,6 +49,7 @@ std::vector<Savemap*> SavemapManager::GetSavemaps(){
 }
 
 bool SavemapManager::Save(unsigned int slot, bool force){
+    if (current_savemap_ == nullptr) return false;
     if (slot >= MAX_SAVE_SLOTS) return false;
     if (!savemaps_read_) ReadSavemaps();
     if (
@@ -59,7 +60,7 @@ bool SavemapManager::Save(unsigned int slot, bool force){
     }
     else{
         saved_savemaps_[slot] = current_savemap_;
-        saved_savemaps_[slot]->Write(SAVE_PATH + std::to_string(slot) + ".lua");
+        saved_savemaps_[slot]->Write(slot, SAVE_PATH + std::to_string(slot) + ".xml");
         return true;
     }
 }
@@ -76,7 +77,7 @@ bool SavemapManager::Save(Savemap savemap, unsigned int slot, bool force){
     else{
         *current_savemap_ = savemap;
         saved_savemaps_[slot] = current_savemap_;
-        saved_savemaps_[slot]->Write(SAVE_PATH + std::to_string(slot) + ".lua");
+        saved_savemaps_[slot]->Write(slot, SAVE_PATH + std::to_string(slot) + ".xml");
         return true;
     }
 }
@@ -90,8 +91,8 @@ void SavemapManager::Release(){
 void SavemapManager::ReadSavemaps(){
     saved_savemaps_.clear();
     for (int i = 0; i < MAX_SAVE_SLOTS; i ++){
-        Savemap* savemap;
-        savemap->Read(SAVE_PATH + std::to_string(i) + ".save");
+        Savemap* savemap = new Savemap();
+        savemap->Read(SAVE_PATH + std::to_string(i) + ".xml");
         saved_savemaps_.push_back(savemap);
     }
     savemaps_read_ = true;
@@ -133,11 +134,6 @@ void SavemapManager::SetCountdownTime(const unsigned int seconds){
     current_savemap_->SetCountdownTime(seconds);
 }
 
-void SavemapManager::SetField(const char* field){
-    if (current_savemap_ == nullptr) current_savemap_ = new Savemap();
-    current_savemap_->SetField(std::string(field));
-}
-
 void SavemapManager::SetKeyItem(const unsigned int item, const bool owned){
     if (current_savemap_ == nullptr) current_savemap_ = new Savemap();
     current_savemap_->SetKeyItem(item, owned);
@@ -181,10 +177,10 @@ void SavemapManager::SetESkillMateriaStash(
 
 void SavemapManager::SetLocation(
   const unsigned int x, const unsigned int y, const int z,
-  const unsigned int triangle, const int angle
+  const unsigned int triangle, const int angle, const char* field, const char* name
 ){
     if (current_savemap_ == nullptr) current_savemap_ = new Savemap();
-    current_savemap_->SetLocation(x, y, z, triangle, angle);
+    current_savemap_->SetLocation(x, y, z, triangle, angle, std::string(field), std::string(name));
 }
 
 void SavemapManager::SetSetting(const unsigned int key, const unsigned int value){
@@ -244,3 +240,62 @@ void SavemapManager::SetCharacterStatus(
     if (current_savemap_ == nullptr) current_savemap_ = new Savemap();
     current_savemap_->SetCharacterStatus(id, status, inflicted);
 }
+
+bool SavemapManager::SlotIsEmpty(const unsigned int slot){
+    if (slot >= MAX_SAVE_SLOTS) return true;
+    if (savemaps_read_ == false) ReadSavemaps();
+    return saved_savemaps_[slot]->IsEmpty();
+}
+
+/*char* SavemapManager::GetPreviewData(const unsigned int slot){
+    std::cout << "[PREV_DATA] Start\n";
+    std::string data = "X";
+    std::cout << "[PREV_DATA] 1\n";
+    //char *empty_cstr= new char[1];
+    //strcpy(empty_cstr, data.c_str());
+    if (slot >= MAX_SAVE_SLOTS){
+        strcpy(temp_, data.c_str());
+        std::cout << "[PREV_DATA] RET 1 " << temp_ << " \n";
+        return temp_;
+    }
+    std::cout << "[PREV_DATA] 2\n";
+    if (savemaps_read_ == false) ReadSavemaps();
+    std::cout << "[PREV_DATA] 3\n";
+    if (saved_savemaps_[slot]->IsEmpty()){
+        strcpy(temp_, data.c_str());
+        std::cout << "[PREV_DATA] RET 2 " << temp_ << " \n";
+        return temp_;
+    }
+    std::cout << "[PREV_DATA] 4\n";
+    data = saved_savemaps_[slot]->GetPreviewData();
+    std::cout << "[PREV_DATA] 5\n";
+
+    //char cstr[data.length() + 1];
+    //strcpy(cstr, data.c_str());
+    //cstr[data.length()] = '\0';
+    temp_ = (char*) malloc(data.size() + 1);
+    for (int c = 0; c < data.size(); c ++){
+        temp_[c] = data[c];
+        std::cout << "    " << data[c] << " -> " << temp_[c] << "\n";
+    }
+    temp_[data.size()] = '\0';
+    strcpy(temp_, data.c_str());
+    std::cout << "[PREV_DATA] : " << data << " == " << std::string(temp_) << "\n";
+    return temp_;
+}*/
+
+std::string SavemapManager::GetPreviewData(const unsigned int slot){
+    std::string data = "";
+    if (slot >= MAX_SAVE_SLOTS) return data;
+    if (savemaps_read_ == false) ReadSavemaps();
+    if (saved_savemaps_[slot]->IsEmpty()) return data;
+    data = saved_savemaps_[slot]->GetPreviewData();
+    return data;
+}
+
+
+
+
+
+
+

+ 11 - 0
V-Gears/src/core/TextManager.cpp

@@ -82,6 +82,16 @@ TiXmlNode* TextManager::GetDialog(const Ogre::String& name, float &width, float&
     return NULL;
 }
 
+std::string TextManager::GetDialogText(const std::string name){
+    std::string text = "";
+    for (unsigned int i = 0; i < dialogs_.size(); ++ i){
+        if (dialogs_[i].name == name){
+            text = dialogs_[i].node->FirstChild()->ToText()->Value();
+            break;
+        }
+    }
+    return text;
+}
 void TextManager::UnloadTexts(){
     for (unsigned int i = 0; i < texts_.size(); ++ i) delete texts_[i].node;
     texts_.clear();
@@ -112,3 +122,4 @@ void TextManager::SetParty(int char_1, int char_2, int char_3){
     current_party_[2] = char_2;
     current_party_[3] = char_3;
 }
+

+ 1 - 1
V-Gears/src/core/XmlScreensFile.cpp

@@ -32,7 +32,7 @@ void XmlScreensFile::LoadScreens(){
     }
     node = node->FirstChild();
     while (node != nullptr){
-        if (node->Type() == TiXmlNode::TINYXML_ELEMENT&& node->ValueStr() == "prototype"){
+        if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "prototype"){
             XmlPrototypesFile prototypes("./data/" + GetString(node, "file_name"));
             prototypes.LoadPrototypes();
         }

BIN
data/data/fonts/ffvii_digits.png


+ 1 - 0
data/data/fonts/ffvii_digits.xml

@@ -13,4 +13,5 @@
     <char name="-" x="88" y="0" width="7" height="8" pre="0" post="0" />
     <char name="+" x="96" y="0" width="7" height="8" pre="0" post="0" />
     <char name="%" x="104" y="0" width="7" height="8" pre="0" post="0" />
+    <char name=":" x="112" y="0" width="7" height="8" pre="0" post="0" />
 </font>

+ 2 - 1
data/data/screens.xml

@@ -12,7 +12,8 @@
     <screen file_name="screens/equip_menu/equip_menu.xml" />
     <screen file_name="screens/materia_menu/materia_menu.xml" />
     <screen file_name="screens/name_menu/name_menu.xml" />
-
+    <screen file_name="screens/save_menu/save_menu.xml" />
+    <prototype file_name="screens/save_menu/prototypes.xml" />
     <!-- Dialogs -->
     <prototype file_name="screens/dialog/prototypes.xml" />
     <screen file_name="screens/dialog/dialog.xml" />

+ 1 - 1
data/data/screens/main_menu/main_menu.xml

@@ -112,7 +112,7 @@
 
         <widget name="Location" x="100%-200" y="100%-54" width="180" height="24" visible="true">
             <prototype name="Window" />
-            <text_area name="Text" x="8" y="6" text_name="MainMenuLocation" font="FFVIIFont" visible="true" />
+            <text_area name="Text" x="8" y="6" font="FFVIIFont" visible="true" />
             <animation name="Appear" length="0.3" y="0:-200%,0.3:100%-54" />
             <animation name="Disappear" length="0.3" y="0:100%-54,0.3:-200%" />
         </widget>

+ 30 - 0
data/data/screens/save_menu/prototypes.xml

@@ -0,0 +1,30 @@
+<prototypes>
+    <prototype name="SaveSlot">
+        <widget name="Slot" width="100%" height="100%" x="0" y="0" visible="true">
+            <prototype name="Window" />
+            <widget name="Party" x="15" y="50%-24" visible="true">
+                <sprite name="Portrait1" image="images/other/choco.png" x="0" y="0" width="42" height="48" visible="true" />
+                <sprite name="Portrait2" image="images/other/choco.png" x="45" y="0" width="42" height="48" visible="true" />
+                <sprite name="Portrait3" image="images/other/choco.png" x="90" y="0" width="42" height="48" visible="true" />
+            </widget>
+            <text_area name="Name" x="160" y="20%" font="FFVIIFont" visible="true" />
+            <text_area name="LvTag" x="170" y="20%+20" text_name="SaveMenuLevel" colour="0 0.9 0.9" font="FFVIIFont" visible="true" />
+            <text_area name="LvNumber" x="200" y="20%+20" font="FFVIIMenuDigits" visible="true" />
+            <widget name="Location" x="100%-190" y="100%-25" width="190" height="25" visible="true">
+                <prototype name="Window" />
+                <text_area name="Name" x="15" y="6" text_name="CharacterDataHp" font="FFVIIFont" visible="true" />
+            </widget>
+            <widget name="TimeMoney" x="100%-100" y="100%-61" width="100" height="36" visible="true">
+                <prototype name="Window" />
+                <text_area name="TimeLbl" x="6" y="6" text_name="SaveMenuTime" font="FFVIIFont" visible="true" />
+                <text_area name="Time" x="52" y="8" font="FFVIIMenuDigits" visible="true" />
+                <text_area name="MoneyLbl" x="6" y="20" text_name="SaveMenuMoney" font="FFVIIFont" visible="true" />
+                <text_area name="Money" x="45" y="22" font="FFVIIMenuDigits" visible="true" />
+            </widget>
+        </widget>
+        <widget name="Empty" width="100%" height="100%" x="0" y="0" visible="true">
+            <prototype name="Window" />
+            <text_area name="Label" text_name="SaveMenuEmptySlot" x="50" y="50%-5" font="FFVIIFont" visible="true" />
+        </widget>
+    </prototype>
+</prototypes>

+ 29 - 0
data/data/screens/save_menu/save_menu.xml

@@ -0,0 +1,29 @@
+<screen name="SaveMenu" script="scripts/menu/save_menu.lua" visible="false">
+    <sprite name="Background" x="0" y="0" width="100%" height="100%" colour="0 0 0" visible="true"/>
+    <widget name="Container" width="40%" height="40%" x="0" y="0" align="left" valign="top" scale="2.5 2.5" visible="true">
+        <widget name="TopBar" x="0" y="0" width="100%" height="24" visible="true">
+            <prototype name="Window" />
+            <text_area name="DescSave" x="36" y="6" text_name="SaveMenuDescSave" font="FFVIIFont" visible="true" />
+            <text_area name="DescLoad" x="36" y="6" text_name="SaveMenuDescLoad" font="FFVIIFont" visible="true" />
+        </widget>
+        <widget name="Title" x="100%-86" y="0" width="86" height="24" visible="true">
+            <prototype name="Window" />
+            <text_area name="TitleSave" x="16" y="6" text_name="SaveMenuTitleSave" font="FFVIIFont" visible="true" />
+            <text_area name="TitleLoad" x="16" y="6" text_name="SaveMenuTitleLoad" font="FFVIIFont" visible="true" />
+        </widget>
+        <widget name="Slot1" x="5%" y="28" width="90%" height="30%-8" visible="true">
+            <prototype name="SaveSlot" />
+        </widget>
+        <widget name="Slot2" x="5%" y="33%+20" width="90%" height="30%-8" visible="true">
+            <prototype name="SaveSlot" />
+        </widget>
+        <widget name="Slot3" x="5%" y="66%+12" width="90%" height="30%-8" visible="true">
+            <prototype name="SaveSlot" />
+        </widget>
+        <sprite name="Cursor" image="images/icons/cursor.png" x="2" y="15%+12" width="24" height="17" visible="true">
+            <animation name="Position1" length="0" y="0:15%+12" />
+            <animation name="Position2" length="0" y="0:48%+12" />
+            <animation name="Position3" length="0" y="0:81%+12" />
+        </sprite>
+    </widget>
+</screen>

+ 6 - 2
data/data/scripts/menu/main_menu.lua

@@ -54,8 +54,9 @@ UiContainer.MainMenu = {
                         audio_manager:play_sound("Error")
                         print("TODO: Open PHS menu")
                     elseif self.position == 10 then -- Save menu
-                        audio_manager:play_sound("Error")
-                        print("TODO: Open save menu")
+                        audio_manager:play_sound("Cursor")
+                        UiContainer.SaveMenu.operation = "save"
+                        script:request_end_sync(Script.UI, "SaveMenu", "show", 0)
                     else -- Any other menu that needs a character
                         audio_manager:play_sound("Cursor")
                         self.select_character_for_menu = self.position
@@ -165,6 +166,9 @@ UiContainer.MainMenu = {
         --ui_manager:get_widget("MainMenu.Container.Menu.PHSText"):set_visible(false)
         ui_manager:get_widget("MainMenu.Container.Menu.SaveText"):set_colour(0.4, 0.4, 0.4)
 
+        -- Set location
+        ui_manager:get_widget("MainMenu.Container.Location.Text"):set_text((dialog:get_map_name()))
+
         -- Set money
         local money_str = tostring(Inventory.money)
         while #(money_str) < 8 do

+ 8 - 0
data/data/scripts/menu/menu_helpers.lua

@@ -8,6 +8,14 @@ UiContainer.pad_value = function(value, length)
     return str
 end
 
+UiContainer.zero_pad_value = function(value, length)
+    local str = tostring(value)
+    while #(str) < length do
+        str = "0" .. str
+    end
+    return str
+end
+
 --- Populates a character data.
 --
 -- @param widget Name of the widget with the character data.

+ 159 - 0
data/data/scripts/menu/save_menu.lua

@@ -0,0 +1,159 @@
+if UiContainer == nil then UiContainer = {} end
+
+--- The item menu.
+UiContainer.SaveMenu = {
+
+    --- Current operation ("save/load")
+    operation = "save",
+
+    --- Current cursor position in the top bar (1-3).
+    position = 1,
+
+    --- Max cursor position in the top bar.
+    position_total = 3,
+
+    --- Maximum scroll position.
+    max_slots = 15,
+
+    --- First visible save slot.
+    first_visible = 1,
+
+    --- Run when the menu is creaded.
+    --
+    -- It does nothing.
+    on_start = function(self)
+        return 0
+    end,
+
+    --- Handles button events.
+    --
+    -- For the current submenu, handles directional keys, enter and escape events.
+    -- @param button Pressed button string key. "Up", "Left", "Enter" and "Escape" are handled.
+    -- @param event Trigger event. Normally, "Press".
+    on_button = function(self, button, event)
+        if UiContainer.current_menu == "save" then
+            if UiContainer.current_submenu == "" then
+                if button == "Escape" and event == "Press" then
+                    audio_manager:play_sound("Back")
+                    script:request_end_sync(Script.UI, "SaveMenu", "hide", 0)
+                elseif button == "Enter" then
+                    self.action(self, self.first_visible - 1 + self.position)
+                    audio_manager:play_sound("Cursor")
+                elseif button == "Down" then
+                    if self.position < self.position_total and self.first_visible + self.position < self.max_slots then
+                        -- Move cursor down
+                        self.position = self.position + 1
+                        ui_manager:get_widget("SaveMenu.Container.Cursor"):set_default_animation("Position" .. self.position)
+                        audio_manager:play_sound("Cursor")
+                    elseif self.position == self.position_total and self.first_visible + self.position < self.max_slots then
+                        self.first_visible = self.first_visible + 1
+                        self.populate_slots(self)
+                        audio_manager:play_sound("Cursor")
+                    else
+                        audio_manager:play_sound("Error")
+                    end
+                elseif button == "Up" then
+                    if self.position > 1 then
+                        -- Move cursor up
+                        self.position = self.position - 1
+                        ui_manager:get_widget("SaveMenu.Container.Cursor"):set_default_animation("Position" .. self.position)
+                        audio_manager:play_sound("Cursor")
+                    elseif self.position == 1 and self.first_visible > 1 then
+                        self.first_visible = self.first_visible - 1
+                        self.populate_slots(self)
+                        audio_manager:play_sound("Cursor")
+                    else
+                        audio_manager:play_sound("Error")
+                    end
+                end
+            elseif UiContainer.current_submenu == "confirm" then
+            end
+        end
+        return 0
+    end,
+
+    --- Opens the save menu.
+    --
+    -- Populates and updates displayed data before opening.
+    show = function(self)
+        if self.operation ~= "save" and self.operation ~= "load" then
+            print("Error: Tried to open the save menu without setting an operation.")
+            print("Do:")
+            print("    UiContainer.SaveMenu.operation = \"save\"")
+            print("or")
+            print("    UiContainer.SaveMenu.operation = \"load\"")
+            print("before calling show()")
+            return 0
+        end
+        if self.operation == "load" then
+            ui_manager:get_widget("SaveMenu.Container.TopBar.DescSave"):set_visible(false)
+            ui_manager:get_widget("SaveMenu.Container.TopBar.DescLoad"):set_visible(true)
+            ui_manager:get_widget("SaveMenu.Container.Title.TitleSave"):set_visible(false)
+            ui_manager:get_widget("SaveMenu.Container.Title.TitleLoad"):set_visible(true)
+        else
+            ui_manager:get_widget("SaveMenu.Container.TopBar.DescSave"):set_visible(true)
+            ui_manager:get_widget("SaveMenu.Container.TopBar.DescLoad"):set_visible(false)
+            ui_manager:get_widget("SaveMenu.Container.Title.TitleSave"):set_visible(true)
+            ui_manager:get_widget("SaveMenu.Container.Title.TitleLoad"):set_visible(false)
+        end
+        ui_manager:get_widget("SaveMenu"):set_visible(true)
+        UiContainer.current_menu = "save"
+        self.position = 1
+        self.first_visible = 1
+        ui_manager:get_widget("SaveMenu.Container.Cursor"):set_default_animation("Position" .. self.position)
+        self.populate_slots(self)
+        return 0;
+    end,
+
+    populate_slots = function(self)
+        for s = 1, 3 do
+            local slot = self.first_visible - 1 + s -- 0-index
+            if savemap_manager:slot_is_empty(slot) == true then
+                ui_manager:get_widget("SaveMenu.Container.Slot" .. tostring(s) .. ".Slot"):set_visible(false)
+                ui_manager:get_widget("SaveMenu.Container.Slot" .. tostring(s) .. ".Empty"):set_visible(true)
+            else
+                local slot_id = "SaveMenu.Container.Slot" .. tostring(s) .. ".Slot."
+                local info = self.split_preview_data(savemap_manager:get_preview_data(slot))
+                ui_manager:get_widget(slot_id .. "TimeMoney.Money"):set_text(UiContainer.pad_value(info[3], 7))
+                local time = UiContainer.pad_value(math.floor(info[4] / 3600), 3) .. ":" .. UiContainer.zero_pad_value(math.floor((info[4] % 3600) / 60), 2)
+                ui_manager:get_widget(slot_id .. "TimeMoney.Time"):set_text(time)
+                ui_manager:get_widget(slot_id .. "Location.Name"):set_text(tostring(info[5]))
+                ui_manager:get_widget(slot_id .. "Name"):set_text(tostring(info[6]))
+                ui_manager:get_widget(slot_id .. "LvNumber"):set_text(UiContainer.pad_value(info[7], 3))
+                for c = 1, 3 do
+                    if tonumber(info[7 + c]) ~= -1 and Characters[info[7 + c] + 1] ~= nil then
+                        ui_manager:get_widget(slot_id .. "Party.Portrait" .. tostring(c)):set_image("images/characters/" .. tostring(info[7 + c]) .. ".png")
+                        ui_manager:get_widget(slot_id .. "Party.Portrait" .. tostring(c)):set_visible(true)
+                    else
+                        ui_manager:get_widget(slot_id .. "Party.Portrait" .. tostring(c)):set_visible(false)
+                    end
+                end
+                ui_manager:get_widget("SaveMenu.Container.Slot" .. tostring(s) .. ".Slot"):set_visible(true)
+                ui_manager:get_widget("SaveMenu.Container.Slot" .. tostring(s) .. ".Empty"):set_visible(false)
+            end
+        end
+    end,
+
+    split_preview_data = function(data)
+        local sep = "#"
+        local t={}
+        for str in string.gmatch(data, "([^"..sep.."]+)") do
+            table.insert(t, str)
+        end
+        return t
+    end,
+
+
+    action = function(self, slot)
+        print("ACTION " .. self.operation .. " ON SLOT " .. tostring(slot))
+    end,
+
+    --- Hides the item menu and goes back to the main menu.
+    hide = function(self)
+        ui_manager:get_widget("SaveMenu"):set_visible(false)
+        UiContainer.current_menu = "main"
+        UiContainer.current_submenu = ""
+        savemap_manager:release()
+        return 0;
+    end,
+}

+ 1 - 4
data/data/scripts/save.lua

@@ -4,7 +4,6 @@ save_game = function(slot)
     savemap_manager:set_money(Inventory.money)
     savemap_manager:set_game_time(123456) -- TODO Actual data
     savemap_manager:set_countdown_time(0) -- TODO Actual data
-    savemap_manager:set_field("FIELD_ID") -- TODO Actual data
     for i = 1, 50 do
        if Inventory.key[i] == true then
            savemap_manager:set_key_item(i - 1, true)
@@ -29,7 +28,7 @@ save_game = function(slot)
         end
     end
     -- TODO: Materia stash, when implemented.
-    savemap_manager:set_location(10, 20, -1, 3, 120) -- TODO Actual data
+    savemap_manager:set_location(10, 20, -1, 3, 120, "FIELD_ID", dialog:get_map_name()) -- TODO Actual data
     -- TODO Settings, when implemented
     for i = 0, 11 do
         if Characters[i] ~= nil and Characters[i].char_id ~= nil then
@@ -72,11 +71,9 @@ save_game = function(slot)
             -- TODO: Character statuses
         end
     end
-    print("TO_DATA")
     for b = 0, 14 do
         for a = 0, 254 do
             if (Banks[b] ~= nil and Banks[b][a] ~= nil and Banks[b][a] ~= 0) then
-                print("DATA " .. tostring(b) .. "." .. tostring(a))
                 savemap_manager:set_data(b, a, tonumber(Banks[b][a]))
             end