Bladeren bron

Battle backgrounds!

Battle background are properly extracted with the installer, and can be loaded in battles. Also, some improvements to the battle UI and scripts.
Iñigo Valentin 3 jaren geleden
bovenliggende
commit
1a1ccc8b80

+ 5 - 0
README.md

@@ -22,6 +22,11 @@ Note that, while these are actual screenshots of V-Gears, none of the images, sp
 |**Transparencies**|**Timers**|**Choices**|
 |[<img src="https://v-gears.inigovalentin.com/img/screenshot/transparent_dialogs.png" alt="Transparency" width="250"/>](https://v-gears.inigovalentin.com/img/screenshot/transparent_dialogs.png "Transparency")|[<img src="https://v-gears.inigovalentin.com/img/screenshot/timers.png" alt="Timers" width="250"/>](https://v-gears.inigovalentin.com/img/screenshot/timers.png "Timers")|[<img src="https://v-gears.inigovalentin.com/img/screenshot/choices.png" alt="Choices" width="250"/>](https://v-gears.inigovalentin.com/img/screenshot/choices.png "Choices")|
 
+### Battle:
+|**Battle UI**|
+|--|
+|[<img src="https://v-gears.inigovalentin.com/img/screenshot/battle.png" alt="Battle UI" width="250"/>](https://v-gears.inigovalentin.com/img/screenshot/battle.png "Battle UI")|
+
 ### Menus:
 |**Begin**|**Main**|**Name**|
 |--|--|--|

BIN
data/data/images/system/blank.png


+ 1 - 1
data/data/screens/battle/prototypes.xml

@@ -11,7 +11,7 @@
                 <text_area name="HpMax" x="55%" y="0%" font="FFVIIMenuDigits" visible="true" />
                 <sprite name="HpLine" x="0" y="10" width="100%" height="2" colour="0.3 0 0" visible="true" />
                 <sprite name="HpLineCurrent" x="0" y="10" width="100%" height="2" colours="0 0.5 1, 0.78 0.78 0.78, 0.78 0.78 0.78, 0 0.5 1" visible="true" />
-                <sprite name="HpLineShadow" x="0" y="15" width="100%" height="1" colour="0 0 0" visible="true" />
+                <sprite name="HpLineShadow" x="0" y="11" width="100%" height="1" colour="0 0 0" visible="true" />
             </widget>
             <widget name="Mp" x="40%" y="0%" width="16%" height="100%" visible="true">
                 <text_area name="MpCurrent" x="0%" y="0%" width="100%" colour="0.9 0.9 0.9" font="FFVIIMenuDigits" visible="true" />

+ 1 - 1
data/data/scripts/battle.lua

@@ -110,7 +110,7 @@ end
 Battle.finish = function()
     print("Ending battle")
     battle_manager:end_battle()
-    script:request_end_sync(Script.UI, "Battle", "hide", 0)
+    script:request_end_sync(Script.UI, "BattleUi", "hide", 0)
     return 0
 end
 

+ 11 - 10
data/data/scripts/battle/battle_ui.lua

@@ -3,6 +3,9 @@ if UiContainer == nil then UiContainer = {} end
 --- The main menu.
 UiContainer.BattleUi = {
 
+    --- Indicates if the battle UI is active.
+    active = false,
+
     --- Current cursor position in the main menu (1-10).
     position = 1,
 
@@ -24,7 +27,6 @@ UiContainer.BattleUi = {
     --
     -- It does nothing.
     on_start = function(self)
-        print("BattleUi start")
         return 0
     end,
 
@@ -34,6 +36,12 @@ UiContainer.BattleUi = {
     -- @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 self.active == false then
+            do return 0 end
+        end
+        if button == "K" then
+            Battle.finish()
+        end
         return 0
     end,
 
@@ -42,8 +50,8 @@ UiContainer.BattleUi = {
     -- Populates and updates displayed data.
     show = function(self)
         self:populate()
-        print("POPULATED")
         ui_manager:get_widget("BattleUi"):set_visible(true)
+        self.active = true;
         --local characters  = ui_manager:get_widget("MainMenu.Container.Characters")
         --local menu = ui_manager:get_widget("MainMenu.Container.Menu")
         --local menu_cursor = ui_manager:get_widget("MainMenu.Container.Menu.Cursor")
@@ -106,6 +114,7 @@ UiContainer.BattleUi = {
         --location:animation_sync()
 
         ui_manager:get_widget("BattleUi"):set_visible(false)
+        self.active = false
 
         --MenuSettings.pause_available = true
         --entity_manager:set_paused(false)
@@ -124,25 +133,17 @@ UiContainer.BattleUi = {
             return str
         end
 
-        print("POPULATING")
-
         for c = 1, 3 do
-            print("POPULATING " .. tostring(c))
             if Party[c] ~= nil then
-                print("POPULATING " .. tostring(c) .. " NOT NULL")
                 ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(c)):set_visible(true)
-                print("POPULATING " .. tostring(c) .. " NAME")
                 ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(c) .. ".Left.Name"):set_text(Characters[Party[c]].name)
-                print("POPULATING " .. tostring(c) .. " HP")
                 ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(c) .. ".Right.Hp.HpCurrent"):set_text(space_pad(Characters[Party[c]].stats.hp.current, 5))
                 ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(c) .. ".Right.Hp.HpMax"):set_text(space_pad(Characters[Party[c]].stats.hp.base, 5))
-                print("POPULATING " .. tostring(c) .. " MP")
                 ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(c) .. ".Right.Mp.MpCurrent"):set_text(space_pad(Characters[Party[c]].stats.mp.current, 5))
             else
                 ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(c)):set_visible(false)
             end
         end
-        print("POPULATING END")
         return 0
     end
 }

+ 10 - 5
src/core/BattleManager.cpp

@@ -42,7 +42,9 @@ template<>BattleManager *Ogre::Singleton<BattleManager>::msSingleton = nullptr;
 ConfigVar cv_debug_battle_grid("debug_battle_grid", "Draw debug battle grid", "false");
 ConfigVar cv_debug_battle_axis("debug_battle_axis", "Draw debug battle axis", "false");
 
-const float BattleManager::MODEL_SCALE = 0.0015f;
+const float BattleManager::MODEL_SCALE = 0.002f;
+
+const float BattleManager::SCENE_SCALE = 0.0012f;
 
 BattleManager::BattleManager(){
     LOG_TRIVIAL("BattleManager created.");
@@ -171,7 +173,7 @@ void BattleManager::AddEnemy(
     EntityManager::getSingleton().AddBattleEntity(
       enemy->GetName() + "_" + std::to_string(enemies_.size() - 1),
       "enemies/" + enemy->GetModel() + ".mesh", enemy->GetPos(), Ogre::Degree(0),
-      Ogre::Vector3(MODEL_SCALE, MODEL_SCALE, MODEL_SCALE), id, visible
+      Ogre::Vector3(MODEL_SCALE, MODEL_SCALE, MODEL_SCALE), id, visible, false
     );
 }
 
@@ -248,7 +250,10 @@ void BattleManager::SetLocation(const int id, const Ogre::String name){
         LOG_ERROR("Tried to set a location in the BattleManager, but it's not in battle mode.");
         return;
     }
-    // TODO
+    EntityManager::getSingleton().AddBattleEntity(
+      "Background", "scenes/oi_grassland.mesh", Ogre::Vector3(0, 0, 0), Ogre::Degree(0),
+      Ogre::Vector3(SCENE_SCALE, SCENE_SCALE, SCENE_SCALE), 999, true, true
+    );
 }
 
 void BattleManager::SetArenaBattle(const bool arena){
@@ -279,7 +284,7 @@ void BattleManager::LoadParty(){
     // Randomize party member positions.
     std::random_shuffle(positions.begin(), positions.end());
 
-    // TODO: Find a way to do this during the instalallation
+    // TODO: Read this from data/gamedata/characters.xml
     for (int i = 0; i < positions.size(); i ++){
         std::string name = "";
         std::string model = "";
@@ -321,6 +326,7 @@ void BattleManager::LoadParty(){
                 name = "party_ketcy";
                 model = "characters/ry_cait_sith.mesh";
                 break;
+            default: continue;
         }
         EntityManager::getSingleton().AddBattleEntity(
           name, model, position, Ogre::Degree(0),
@@ -330,7 +336,6 @@ void BattleManager::LoadParty(){
         // Next position in Y axis
         position.x += ((i + 1) * (i % 2 == 0 ? 5 : -5));
 
-
     }
 }
 

+ 6 - 1
src/core/BattleManager.h

@@ -340,10 +340,15 @@ class BattleManager : public Manager, public Ogre::Singleton<BattleManager>{
         void UpdateWorld() override;
 
         /**
-         * Scale factor for all battle models.
+         * Scale factor for battle character and enemy models.
          */
         static const float MODEL_SCALE;
 
+        /**
+         * Scale factor for battle background models.
+         */
+        static const float SCENE_SCALE;
+
         /**
          * The scene node.
          */

+ 38 - 22
src/core/CameraManager.cpp

@@ -42,8 +42,7 @@ CameraManager::CameraManager():
 {
     LOG_TRIVIAL("CameraManager started.");
     InitCommands();
-    camera_ = Ogre::Root::getSingleton().getSceneManager("Scene")
-      ->createCamera("Camera");
+    camera_ = Ogre::Root::getSingleton().getSceneManager("Scene")->createCamera("Camera");
     position_initial_
       = Ogre::Vector3(camera_->getPosition().x, camera_->getPosition().y, camera_->getPosition().z);
     orientation_initial_ = Ogre::Quaternion(
@@ -59,12 +58,10 @@ CameraManager::CameraManager():
     //camera_->lookAt(Ogre::Vector3(0, 0, 0));
     Ogre::Root::getSingleton().getSceneManager("Scene")->getRootSceneNode()
       ->lookAt(Ogre::Vector3(0, 0, 0), Ogre::Node::TS_LOCAL);
-    viewport_ = VGears::Application::getSingleton().getRenderWindow()
-      ->addViewport(camera_, 0);
+    viewport_ = VGears::Application::getSingleton().getRenderWindow()->addViewport(camera_, 0);
     viewport_->setBackgroundColour(Ogre::ColourValue(0, 0, 0));
     camera_->setAspectRatio(
-      Ogre::Real(viewport_->getActualWidth())
-      / Ogre::Real(viewport_->getActualHeight())
+      Ogre::Real(viewport_->getActualWidth()) / Ogre::Real(viewport_->getActualHeight())
     );
 }
 
@@ -99,18 +96,17 @@ void CameraManager::Input(const VGears::Event& event, Ogre::Real time_since_last
             //camera_->moveRelative(Ogre::Vector3(speed, 0, 0));
             rootScene->translate(Ogre::Vector3(speed, 0, 0), Ogre::Node::TS_LOCAL);
         }
+        //else if (event.type == 1)
         else if (event.type == VGears::ET_MOUSE_PRESS && event.param1 == OIS::MB_Right)
             camera_free_rotate_ = true;
+        //else if (event.type == 5)
         else if (event.type == VGears::ET_MOUSE_RELEASE && event.param1 == OIS::MB_Right)
             camera_free_rotate_ = false;
+        //else if (event.type == 8 && camera_free_rotate_ == true){
         else if (event.type == VGears::ET_MOUSE_MOVE && camera_free_rotate_ == true){
-            //camera_->rotate(
-            //  Ogre::Vector3::UNIT_Z, Ogre::Radian(Ogre::Degree(-event.param1 * 0.13f))
-            //);
             rootScene->rotate(
               Ogre::Vector3::UNIT_Z, Ogre::Radian(Ogre::Degree(-event.param1 * 0.13f))
             );
-            //camera_->pitch(Ogre::Degree(-event.param2 * 0.13f));
             rootScene->pitch(Ogre::Degree(-event.param2 * 0.13f));
         }
     }
@@ -178,13 +174,20 @@ void CameraManager::Set2DCamera(
 void CameraManager::StartBattleCamera(
   const Ogre::Vector3 position, const Ogre::Vector3 orientation
 ){
+    /*
+     * TODO: Something is wrong here. The camera look 'mostly' okay, but it's still weird.
+     * Also, there are variations and it doesn't look the same on successive calls.
+     * I thinks it's something related to the lookAt functions.
+     * Try to fix it. First, replace the deprecated calls, and see what happens.
+     */
     if (module_ != Module::BATTLE){
         LOG_ERROR("Tried to start battle camera but the CameraManager is already in battle mode");
         return;
     }
-    std::cout << "CAMERA BATTLE START: " << camera_->getPosition().x << ", " << camera_->getPosition().y << ", " << camera_->getPosition().z << ", "
-        << camera_->getOrientation().w << ", "<< camera_->getOrientation().x << ", " << camera_->getOrientation().y << ", "
-        << camera_->getOrientation().z << std::endl;
+    /*std::cout << "CAMERA BATTLE START: " << camera_->getPosition().x << ", "
+      << camera_->getPosition().y << ", " << camera_->getPosition().z << ", "
+      << camera_->getOrientation().w << ", "<< camera_->getOrientation().x << ", "
+      << camera_->getOrientation().y << ", " << camera_->getOrientation().z << std::endl;*/
     position_backup_ = Ogre::Vector3(
       camera_->getPosition().x, camera_->getPosition().y, camera_->getPosition().z
     );
@@ -195,26 +198,39 @@ void CameraManager::StartBattleCamera(
     camera_->setPosition(position);
     //CameraManager::getSingleton().GetCurrentCamera()->setFixedYawAxis(true, Ogre::Vector3::UNIT_Y);
     camera_->lookAt(orientation);
+    camera_->roll(Ogre::Angle(90));
+
+    /*Ogre::SceneNode* rootScene =
+              Ogre::Root::getSingleton().getSceneManager("Scene") ->getRootSceneNode();
+    rootScene->setPosition(position);//, Ogre::Node::TS_LOCAL);
+    rootScene->lookAt(orientation, Ogre::Node::TS_WORLD);*/
 
+    /*std::cout << "CAMERA BATTLE START FINISH: " << camera_->getPosition().x << ", "
+      << camera_->getPosition().y << ", " << camera_->getPosition().z << ", "
+      << camera_->getOrientation().w << ", "<< camera_->getOrientation().x << ", "
+      << camera_->getOrientation().y << ", " << camera_->getOrientation().z << std::endl;*/
 
-    std::cout << "CAMERA BATTLE START FINISH: " << camera_->getPosition().x << ", " << camera_->getPosition().y << ", " << camera_->getPosition().z << ", "
-            << camera_->getOrientation().w << ", "<< camera_->getOrientation().x << ", " << camera_->getOrientation().y << ", "
-            << camera_->getOrientation().z << std::endl;
+    /*std::cout << "CAMERA BATTLE START FINISH: " << rootScene->getPosition().x << ", "
+      << rootScene->getPosition().y << ", " << rootScene->getPosition().z << ", "
+      << rootScene->getOrientation().w << ", "<< rootScene->getOrientation().x << ", "
+      << rootScene->getOrientation().y << ", " << rootScene->getOrientation().z << std::endl;*/
 }
 
 void CameraManager::EndBattleCamera(){
-        std::cout << "CAMERA BATTLE END: " << camera_->getPosition().x << ", " << camera_->getPosition().y << ", " << camera_->getPosition().z << ", "
-            << camera_->getOrientation().w << ", "<< camera_->getOrientation().x << ", " << camera_->getOrientation().y << ", "
-            << camera_->getOrientation().z << std::endl;
+    /*std::cout << "CAMERA BATTLE END: " << camera_->getPosition().x << ", "
+      << camera_->getPosition().y << ", " << camera_->getPosition().z << ", "
+      << camera_->getOrientation().w << ", "<< camera_->getOrientation().x << ", "
+      << camera_->getOrientation().y << ", " << camera_->getOrientation().z << std::endl;*/
     CameraManager::getSingleton().GetCurrentCamera()->setPosition(
       Ogre::Vector3(position_backup_.x, position_backup_.y, position_backup_.z)
     );
     CameraManager::getSingleton().GetCurrentCamera()->setOrientation(Ogre::Quaternion(
       orientation_backup_.w, orientation_backup_.x, orientation_backup_.y, orientation_backup_.z
     ));
-    std::cout << "CAMERA BATTLE END FINISH: " << camera_->getPosition().x << ", " << camera_->getPosition().y << ", " << camera_->getPosition().z << ", "
-                << camera_->getOrientation().w << ", "<< camera_->getOrientation().x << ", " << camera_->getOrientation().y << ", "
-                << camera_->getOrientation().z << std::endl;
+    /*std::cout << "CAMERA BATTLE END FINISH: " << camera_->getPosition().x << ", "
+      << camera_->getPosition().y << ", " << camera_->getPosition().z << ", "
+      << camera_->getOrientation().w << ", "<< camera_->getOrientation().x << ", "
+      << camera_->getOrientation().y << ", " << camera_->getOrientation().z << std::endl;*/
 }
 
 void CameraManager::Set2DScroll(const Ogre::Vector2& position){

+ 4 - 1
src/core/EntityManager.cpp

@@ -394,7 +394,8 @@ void EntityManager::AddEntity(
 
 void EntityManager::AddBattleEntity(
   const Ogre::String& name, const Ogre::String& file_name, const Ogre::Vector3& position,
-  const Ogre::Degree& rotation, const Ogre::Vector3& scale, const int index, const int visible
+  const Ogre::Degree& rotation, const Ogre::Vector3& scale, const int index, const int visible,
+  const bool is_background
 ){
     if (module_ != Module::BATTLE){
         LOG_ERROR("Tried to add battle Entity but the EntityManager is not in battle mode.");
@@ -407,6 +408,8 @@ void EntityManager::AddBattleEntity(
     entity->setScale(scale);
     entity->SetIndex(index);
     entity->SetVisible(visible);
+    // Backgrounds must be reoriented.
+    if (is_background) node->setOrientation(1, 1, 0, 0);
     battle_entity_.push_back(entity);
     ScriptManager::getSingleton().AddEntity(ScriptManager::BATTLE, entity->GetName(), entity);
 }

+ 3 - 1
src/core/EntityManager.h

@@ -138,11 +138,13 @@ class EntityManager : public Manager, public Ogre::Singleton<EntityManager>{
          * @param[in] scale Entity scale.
          * @param[in] index Index of the entity.
          * @param[in] visible True to make the entity visible, false otherwise.
+         * @param[in] is_background Indicates if the entity is for the battle background.
          */
         void AddBattleEntity(
           const Ogre::String& name, const Ogre::String& file_name,
           const Ogre::Vector3& position, const Ogre::Degree& rotation,
-          const Ogre::Vector3& scale, const int index, const int visible
+          const Ogre::Vector3& scale, const int index, const int visible,
+          const bool is_background = false
         );
 
         /**

+ 0 - 1
src/core/XmlFormationFile.cpp

@@ -69,7 +69,6 @@ void XmlFormationFile::LoadFormation(){
             TiXmlNode* enemy_node = node->FirstChild();
             while (enemy_node != nullptr){
                 int id = GetInt(enemy_node, "id");
-                std::cout << "LOADING ENEMY " << id << std::endl;
                 Ogre::Vector3 pos = Ogre::Vector3(
                   GetInt(enemy_node, "x"), GetInt(enemy_node, "y"), GetInt(enemy_node, "z")
                 );

+ 65 - 38
src/installer/BattleDataInstaller.cpp

@@ -226,7 +226,6 @@ unsigned int BattleDataInstaller::ProcessModel(){
                     CharacterModel model;
                     model.name = info.name;
                     model.model = info.alphanumeric_id + "_" + info.name_normal + ".mesh";
-                    std::cout << "Character model update: " << std::to_string(data.id) << " " << model.name << " : " << model.model << std::endl;
                     data.models.push_back(model);
                     character_data_.push_back(data);
                     found = true;
@@ -239,7 +238,6 @@ unsigned int BattleDataInstaller::ProcessModel(){
                 CharacterModel model;
                 model.name = info.name;
                 model.model = info.alphanumeric_id + "_" + info.name_normal + ".mesh";
-                std::cout << "Character model new: " << std::to_string(character_data.id) << " " << model.name << " : " << model.model << std::endl;
                 character_data.models.push_back(model);
                 character_data_.push_back(character_data);
             }
@@ -305,23 +303,32 @@ unsigned int BattleDataInstaller::ConvertModel(){
         if (info.is_player) path += "characters/";
         else if (info.is_scene) path += "scenes/";
         else path += "enemies/";
-
-
-        DecompileHrc(
-          File(output_dir_ + "temp/battle_models/" + model.hrc + "bin"),
-          model,
-          output_dir_ + "temp/battle_models/" + model.id + "_" + info.name_normal + ".hrc",
-          model.id + "_" + info.name_normal
-        );
+        if (info.is_scene){
+            DecompileSceneHrc(
+              File(output_dir_ + "temp/battle_models/" + model.hrc + "bin"), model,
+              output_dir_ + "temp/battle_models/" + model.id + "_" + info.name_normal + ".hrc",
+              model.id + "_" + info.name_normal
+            );
+        }
+        else{
+            DecompileHrc(
+              File(output_dir_ + "temp/battle_models/" + model.hrc + "bin"), model,
+              output_dir_ + "temp/battle_models/" + model.id + "_" + info.name_normal + ".hrc",
+              model.id + "_" + info.name_normal
+            );
+        }
         GenerateRsdFiles(model, output_dir_ + "temp/battle_models/");
 
-        DaFile da(File(output_dir_ + "temp/battle_models/" + model.anim));
-        std::vector<std::string> a_files = da.GenerateAFiles(
-          model.id, output_dir_ + "temp/battle_models/"
-        );
-        for (std::string file_name : a_files) model.a.push_back(file_name);
+        if ("" != model.anim){ // Skip for non-animated, ie battle backgrounds
+            DaFile da(File(output_dir_ + "temp/battle_models/" + model.anim));
+            std::vector<std::string> a_files = da.GenerateAFiles(
+              model.id, output_dir_ + "temp/battle_models/"
+            );
+            for (std::string file_name : a_files) model.a.push_back(file_name);
+        }
 
         // Reload the resources for the newly created hrc and rsd.
+        // TODO: Could this be done with res_mgr_->declareResource() ? Probably faster
         res_mgr_->removeResourceLocation(output_dir_ + "temp/battle_models/", "FFVII");
         res_mgr_->addResourceLocation(
           output_dir_ + "temp/battle_models/", "FileSystem", "FFVII", true, true
@@ -700,16 +707,6 @@ std::string BattleDataInstaller::BuildEnemyFileName(Enemy enemy){
     std::string file_name = "gamedata/enemy/";
     std::string id = std::to_string(enemy.id);
     while (id.size() < 4) id = "0" + id;
-    /*file_name += (id + "_");
-    for (int n = 0; n < enemy.name.size(); n ++){
-        if (
-          (enemy.name[n] >= '0' && enemy.name[n] <= '9')
-          || (enemy.name[n] >= 'a' && enemy.name[n] <= 'z')
-          || (enemy.name[n] >= 'A' && enemy.name[n] <= 'Z')
-        ){
-            file_name += enemy.name[n];
-        }
-    }*/
     file_name += id + ".xml";
     return file_name;
 }
@@ -752,22 +749,26 @@ File* BattleDataInstaller::ExtractGZipScene(File file){
         switch (ret){
             case Z_MEM_ERROR:
                 inflateEnd(&strm);
-                std::cout << "Warning: inflateInit2 - Z_MEM_ERROR in file " << std::endl;
+                std::cout << "Warning: inflateInit2 - Z_MEM_ERROR in file "
+                  << file.GetFileName() << std::endl;
                 break;
             case Z_STREAM_ERROR:
                 inflateEnd(&strm);
-                std::cout << "Warning: inflateInit2 - Z_STREAM_ERROR in file " << std::endl;
+                std::cout << "Warning: inflateInit2 - Z_STREAM_ERROR in file "
+                  << file.GetFileName() << std::endl;
                 break;
             default:
                 inflateEnd(&strm);
-                std::cout << "Warning: inflateInit2 - unknown error in file " << std::endl;
+                std::cout << "Warning: inflateInit2 - unknown error in file "
+                  << file.GetFileName() << std::endl;
         }
         return NULL;
     }
     do{
         if (strm.next_out == NULL){
             inflateEnd(&strm);
-            std::cout << "Warning: strm.next_out == NULL in file " << std::endl;
+            std::cout << "Warning: strm.next_out == NULL in file "
+              << file.GetFileName() << std::endl;
             return NULL;
         }
         ret = inflate(&strm, Z_NO_FLUSH);
@@ -775,22 +776,26 @@ File* BattleDataInstaller::ExtractGZipScene(File file){
         switch (ret){
             case Z_NEED_DICT:
                 inflateEnd(&strm);
-                std::cout << "Warning: inflate - Z_NEED_DICT in file " << std::endl;
+                std::cout << "Warning: inflate - Z_NEED_DICT in file "
+                  << file.GetFileName() << std::endl;
                 return NULL;
             case Z_DATA_ERROR:
                 inflateEnd(&strm);
-                std::cout << "Warning: inflate - Z_DATA_ERROR in file " << std::endl;
+                std::cout << "Warning: inflate - Z_DATA_ERROR in file "
+                  << file.GetFileName() << std::endl;
                 return NULL;
             case Z_MEM_ERROR:
                 inflateEnd(&strm);
-                std::cout << "Warning: inflate - Z_MEM_ERROR in file " << std::endl;
+                std::cout << "Warning: inflate - Z_MEM_ERROR in file "
+                  << file.GetFileName() << std::endl;
                 return NULL;
         }
         if (ret != Z_STREAM_END){
             extract_buffer = static_cast<u8*>(realloc(extract_buffer, extract_size * 2));
             if (extract_buffer == NULL){
                 inflateEnd(&strm);
-                std::cout << "Warning: extract_buffer == NULL in file " << std::endl;
+                std::cout << "Warning: extract_buffer == NULL in file "
+                  << file.GetFileName() << std::endl;
                 return NULL;
             }
             strm.next_out = static_cast<u8*>(extract_buffer + extract_size);
@@ -801,7 +806,7 @@ File* BattleDataInstaller::ExtractGZipScene(File file){
     extract_size = extract_size - strm.avail_out;
     (void)inflateEnd(&strm);
     if (ret != Z_STREAM_END){
-        std::cout << "Warning: ret != Z_STREAM_END in file " << std::endl;
+        std::cout << "Warning: ret != Z_STREAM_END in file " << file.GetFileName() << std::endl;
         return NULL;
     }
     File* out_file = new File(extract_buffer, 0, extract_size);
@@ -869,7 +874,6 @@ void BattleDataInstaller::GenerateRsdFiles(Model model, std::string path){
     for (std::string p : model.p){
         std::string base_name = p.substr(0, 4);
         std::string content = "@RSD940102\n";
-
         content += "PLY=" + base_name + ".PLY\n";
         content += "MAT=" + base_name + ".MAT\n";
         content += "GRP=" + base_name + ".GRP\n";
@@ -915,9 +919,7 @@ void BattleDataInstaller::DecompileHrc(
         if (offset == 0) decompiled += "0\n\n";
         else {
             decompiled += std::to_string(offset) + " ";
-            if (p_file_index < model.p.size()){
-                decompiled += model.p[p_file_index].substr(0, 4);
-            }
+            if (p_file_index < model.p.size()) decompiled += model.p[p_file_index].substr(0, 4);
             p_file_index ++;
             decompiled += "\n\n";
         }
@@ -926,3 +928,28 @@ void BattleDataInstaller::DecompileHrc(
     out << decompiled;
     out.close();
 }
+
+void BattleDataInstaller::DecompileSceneHrc(
+  File compiled, Model model, std::string path, std::string skeleton_name
+){
+    compiled.SetOffset(0);
+    compiled.readU32LE(); // Skip 4 bytes
+    compiled.readU32LE(); // Skip 4 bytes
+    compiled.readU32LE(); // Skip 4 bytes
+    compiled.readU32LE(); // Supposed to be the number of bones, but for scenes is always 0.
+    std::sort(model.p.begin(), model.p.end());
+    std::string decompiled(":HEADER_BLOCK 2\n:SKELETON " + skeleton_name + "\n");
+    int bones = model.p.size();
+    decompiled += ":BONES " + std::to_string(bones) + "\n\n";
+    int p_file_index = 0;
+    for (int b = 0; b < bones; b ++){
+        decompiled += "bone" + std::to_string(b) + "\n";
+        if (b == 0) decompiled += "root\n";
+        else decompiled += ("bone" + std::to_string(b - 1) + "\n");
+        decompiled += "100.000000\n";
+        decompiled += "1 " + model.p[b].substr(0, 4) + "\n\n";
+    }
+    std::ofstream out(path);
+    out << decompiled;
+    out.close();
+}

+ 19 - 0
src/installer/BattleDataInstaller.h

@@ -244,6 +244,8 @@ class BattleDataInstaller{
         /**
          * Decompiles a compiled HRC file.
          *
+         * To be used for battle enemy and playable character models, since they have a
+         * well-defined bone hierarchy. For battle background models, use {@see DecompileSceneHrc}.
          * Note that this is not a general purpose HRC decompiler, it only works for files in
          * battle.lgp.
          *
@@ -254,6 +256,23 @@ class BattleDataInstaller{
          */
         void DecompileHrc(File compiled, Model model, std::string path, std::string skeleton_name);
 
+        /**
+         * Decompiles a compiled HRC file.
+         *
+         * To be used only for battle background HRC files, since they don't have a defined bone
+         * hierarchy, and every bone is assumed to be a child of the previous one. For enemy and
+         * playable character models, use {@see DecompileHrc}. Note that this is not a general
+         * purpose HRC decompiler, it only works for files in battle.lgp.
+         *
+         * @param[in] compiled The compiles HRC file.
+         * @param[in] model The model.
+         * @param[in] path Path to save the decompiled file to.
+         * @param[in] skeleton_name Name for the skeleton.
+         */
+        void DecompileSceneHrc(
+          File compiled, Model model, std::string path, std::string skeleton_name
+        );
+
         /**
          * The path to the directory from which to read the PC game data.
          */

+ 37 - 1
src/installer/MediaDataInstaller.cpp

@@ -458,7 +458,7 @@ bool MediaDataInstaller::InstallMusics(){
     if (!keep_originals_)
         std::remove((output_dir_ + "audio/musics/" + std::to_string(index) + ".mid").c_str());
 
-    musics_.push_back("audio/music/" + std::to_string(processed_musics_) + ".ogg");
+    musics_.push_back("audio/musics/" + std::to_string(processed_musics_) + ".ogg");
     processed_musics_ ++;
     if (processed_musics_ == midi_.list(true, true)->size()) return true;
     else return false;
@@ -493,6 +493,42 @@ void MediaDataInstaller::WriteMusicsIndex(){
         xml_music->SetAttribute("file_name", path);
         xml_music->SetAttribute("name", id);
         xml_music->SetAttribute("loop", "0");
+        switch (id){
+            case 1:
+                xml_music->SetAttribute("default", "initial");
+                break;
+            case 6:
+                xml_music->SetAttribute("default", "battle");
+                break;
+            case 9:
+                xml_music->SetAttribute("default", "boss");
+                break;
+            case 13:
+                xml_music->SetAttribute("default", "world_map");
+                break;
+            case 43:
+                xml_music->SetAttribute("default", "chocobo_battle");
+                break;
+            case 45:
+                xml_music->SetAttribute("default", "victory");
+                break;
+            case 46:
+                xml_music->SetAttribute("default", "airship");
+                break;
+            case 50:
+                xml_music->SetAttribute("default", "chocobo_ride");
+                break;
+            case 57:
+                xml_music->SetAttribute("default", "game_over");
+                break;
+            case 70:
+                xml_music->SetAttribute("default", "world_map_danger");
+                break;
+            case 84:
+                xml_music->SetAttribute("default", "submarine");
+                break;
+
+        }
         container->LinkEndChild(xml_music.release());
         // If there is a friendly name for this sound, add another entry
         if (musics_map_.count(id) != 0){

+ 94 - 101
src/installer/data/BattleSceneFile.cpp

@@ -52,7 +52,6 @@ void BattleSceneFile::Read(File file){
             // Camera positions are stored as 16 bit floats. Here, 16 bit are being read, then, the
             // sign is checked to fit it into -32766 and 32767 (0x7F9b). Then, the number is
             // divided by 255 (0xFF) to keep just the integer part.
-            //
             scene_.camera[c].camera[p].x = file.readU16LE();
             if (scene_.camera[c].camera[p].x > 0x7F9B) scene_.camera[c].camera[p].x -= 0xFFFF;
             scene_.camera[c].camera[p].x /= 0xFF;
@@ -82,21 +81,15 @@ void BattleSceneFile::Read(File file){
             // sign is checked to fit it into -32766 and 32767 (0x7F9b). Then, the number is
             // divided by 255 (0xFF) to keep just the integer part.
             scene_.formation[f][e].x = file.readU16LE();
-            if (scene_.formation[f][e].id == 347) std::cout << "TAILVAULT: x1 = " << std::to_string(scene_.formation[f][e].x) << std::endl;
             if (scene_.formation[f][e].x > 0x7F9B) scene_.formation[f][e].x -= 0xFFFF;
             scene_.formation[f][e].x /= 0xFF;
-            if (scene_.formation[f][e].id == 347) std::cout << "         : x2 = " << std::to_string(scene_.formation[f][e].x) << std::endl;
             // Y and Z are inverted in original data.
-            scene_.formation[f][e].y = file.readU16LE();
-            if (scene_.formation[f][e].id == 347) std::cout << "         : y1 = " << std::to_string(scene_.formation[f][e].y) << std::endl;
-            if (scene_.formation[f][e].y > 0x7F9B) scene_.formation[f][e].y -= 0xFFFF;
-            scene_.formation[f][e].y /= 0xFF;
-            if (scene_.formation[f][e].id == 347) std::cout << "         : y2 = " << std::to_string(scene_.formation[f][e].y) << std::endl;
             scene_.formation[f][e].z = file.readU16LE();
-            if (scene_.formation[f][e].id == 347) std::cout << "         : z1 = " << std::to_string(scene_.formation[f][e].z) << std::endl;
             if (scene_.formation[f][e].z > 0x7F9B) scene_.formation[f][e].z -= 0xFFFF;
             scene_.formation[f][e].z /= 0xFF;
-            if (scene_.formation[f][e].id == 347) std::cout << "         : z2 = " << std::to_string(scene_.formation[f][e].z) << std::endl;
+            scene_.formation[f][e].y = file.readU16LE();
+            if (scene_.formation[f][e].y > 0x7F9B) scene_.formation[f][e].y -= 0xFFFF;
+            scene_.formation[f][e].y /= 0xFF;
             scene_.formation[f][e].row = file.readU16LE();
             scene_.formation[f][e].cover_flags = file.readU16LE();
             scene_.formation[f][e].flags = file.readU32LE();
@@ -862,96 +855,96 @@ void BattleSceneFile::Read(File file){
 
 std::string BattleSceneFile::LocationToString(const int id){
     switch(id){
-        case 0x0000: return "Blank";
-        case 0x0001: return "Bizarro Battle - Center";
-        case 0x0002: return "Grassland";
-        case 0x0003: return "Mt Nibel";
-        case 0x0004: return "Forest";
-        case 0x0005: return "Beach";
-        case 0x0006: return "Desert";
-        case 0x0007: return "Snow";
-        case 0x0008: return "Swamp";
-        case 0x0009: return "Sector 1 Train Station";
-        case 0x000A: return "Reactor 1";
-        case 0x000B: return "Reactor 1 Core";
-        case 0x000C: return "Reactor 1 Entrance";
-        case 0x000D: return "Sector 4 Subway";
-        case 0x000E: return "Nibel Caves or AForest Caves";
-        case 0x000F: return "Shinra HQ";
-        case 0x0010: return "Midgar Raid Subway";
-        case 0x0011: return "Hojo's Lab";
-        case 0x0012: return "Shinra Elevators";
-        case 0x0013: return "Shinra Roof";
-        case 0x0014: return "Midgar Highway";
-        case 0x0015: return "Wutai Pagoda";
-        case 0x0016: return "Church";
-        case 0x0017: return "Coral Valley";
-        case 0x0018: return "Midgar Slums";
-        case 0x0019: return "Sector 4 Corridors or Junon Path";
-        case 0x001A: return "Sector 4 Gantries or Midgar Underground";
-        case 0x001B: return "Sector 7 Support Pillar Stairway";
-        case 0x001C: return "Sector 7 Support Pillar Top";
-        case 0x001D: return "Sector 8";
-        case 0x001E: return "Sewers";
-        case 0x001F: return "Mythril Mines";
-        case 0x0020: return "Northern Crater - Floating Platforms";
-        case 0x0021: return "Corel Mountain Path";
-        case 0x0022: return "Junon Beach";
-        case 0x0023: return "Junon Cargo Ship";
-        case 0x0024: return "Corel Prison";
-        case 0x0025: return "Battle Square";
-        case 0x0026: return "Da Chao - Rapps Battle";
-        case 0x0027: return "Cid's Backyard";
-        case 0x0028: return "Final Descent to Sephiroth";
-        case 0x0029: return "Reactor 5 Entrance";
-        case 0x002A: return "Temple of the Ancients - Escher Room";
-        case 0x002B: return "Shinra Mansion";
-        case 0x002C: return "Junon Airship Dock";
-        case 0x002D: return "Whirlwind Maze";
-        case 0x002E: return "Junon Underwater Reactor";
-        case 0x002F: return "Gongaga Reactor";
-        case 0x0030: return "Gelnika";
-        case 0x0031: return "Train Graveyard";
-        case 0x0032: return "Great Glacier Ice Caves & Gaea Cliffs - Inside";
-        case 0x0033: return "Sister Ray";
-        case 0x0034: return "Sister Ray Base";
-        case 0x0035: return "Forgotten City Altar";
-        case 0x0036: return "Northern Crater - Initial Descent";
-        case 0x0037: return "Northern Crater - Hatchery";
-        case 0x0038: return "Northern Crater - Water Area";
-        case 0x0039: return "Safer Battle";
-        case 0x003A: return "Kalm Flashback - Dragon Battle";
-        case 0x003B: return "Junon Underwater Pipe";
-        case 0x003C: return "Blank";
-        case 0x003D: return "Corel Railway - Canyon";
-        case 0x003E: return "Whirlwind Maze - Crater";
-        case 0x003F: return "Corel Railway - Rollercoaster";
-        case 0x0040: return "Wooden Bridge";
-        case 0x0041: return "Da Chao";
-        case 0x0042: return "Fort Condor";
-        case 0x0043: return "Dirt Wasteland";
-        case 0x0044: return "Bizarro Battle - Right Side";
-        case 0x0045: return "Bizarro Battle - Left Side";
-        case 0x0046: return "Jenova*SYNTHESIS Battle";
-        case 0x0047: return "Corel Train Battle";
-        case 0x0048: return "Cosmo Canyon";
-        case 0x0049: return "Caverns of the Gi";
-        case 0x004A: return "Nibelheim Mansion Basement";
-        case 0x004B: return "Temple of the Ancients - Demons Gate";
-        case 0x004C: return "Temple of the Ancients - Mural Room";
-        case 0x004D: return "Temple of the Ancients - Clock Passage";
-        case 0x004E: return "Final Battle - Sephiroth";
-        case 0x004F: return "Jungle";
-        case 0x0050: return "Ultimate Weapon - Battle on Highwind";
-        case 0x0051: return "Corel Reactor";
-        case 0x0052: return "Unused";
-        case 0x0053: return "Don Corneo's Mansion";
-        case 0x0054: return "Emerald Weapon Battle";
-        case 0x0055: return "Reactor 5";
-        case 0x0056: return "Shinra HQ - Escape";
-        case 0x0057: return "Ultimate Weapon - Gongaga Reactor";
-        case 0x0058: return "Corel Prison - Dyne Battle";
-        case 0x0059: return "Ultimate Weapon - Forest";
-        default: return "UNKNONW location";
+        case 0x0000: return "blank";
+        case 0x0001: return "bizarro_battle_center";
+        case 0x0002: return "grassland";
+        case 0x0003: return "mt_nibel";
+        case 0x0004: return "forest";
+        case 0x0005: return "beach";
+        case 0x0006: return "desert";
+        case 0x0007: return "snow";
+        case 0x0008: return "swamp";
+        case 0x0009: return "sector_1_train_station";
+        case 0x000a: return "reactor_1";
+        case 0x000b: return "reactor_1_core";
+        case 0x000c: return "reactor_1_entrance";
+        case 0x000d: return "sector_4_subway";
+        case 0x000e: return "nibel_caves";
+        case 0x000f: return "shinra_hq";
+        case 0x0010: return "midgar_raid_subway";
+        case 0x0011: return "hojo_lab";
+        case 0x0012: return "shinra_elevators";
+        case 0x0013: return "shinra_roof";
+        case 0x0014: return "midgar_highway";
+        case 0x0015: return "wutai_pagoda";
+        case 0x0016: return "church";
+        case 0x0017: return "coral_valley";
+        case 0x0018: return "midgar_slums";
+        case 0x0019: return "sector_4_corridors";
+        case 0x001a: return "sector_4_gantries";
+        case 0x001b: return "sector_7_pillar_stairway";
+        case 0x001c: return "sector_7pillar_top";
+        case 0x001d: return "sector_8";
+        case 0x001e: return "sewers";
+        case 0x001f: return "mythril_mines";
+        case 0x0020: return "crater_floating_platforms";
+        case 0x0021: return "corel_mountain_path";
+        case 0x0022: return "junon_beach";
+        case 0x0023: return "junon_cargo_ship";
+        case 0x0024: return "corel_prison";
+        case 0x0025: return "battle_square";
+        case 0x0026: return "da_chao_rapps_battle";
+        case 0x0027: return "cids_backyard";
+        case 0x0028: return "final_descent_to_sephiroth";
+        case 0x0029: return "reactor_5_entrance";
+        case 0x002a: return "ancients_escher_room";
+        case 0x002b: return "shinra_mansion";
+        case 0x002c: return "junon_airship_dock";
+        case 0x002d: return "whirlwind_maze";
+        case 0x002e: return "junon_underwater_reactor";
+        case 0x002f: return "gongaga_reactor";
+        case 0x0030: return "gelnika";
+        case 0x0031: return "train_graveyard";
+        case 0x0032: return "ice_caves";
+        case 0x0033: return "sister_ray";
+        case 0x0034: return "sister_ray_base";
+        case 0x0035: return "forgotten_city_altar";
+        case 0x0036: return "crater_descent";
+        case 0x0037: return "crater_hatchery";
+        case 0x0038: return "crater_water_area";
+        case 0x0039: return "safer_battle";
+        case 0x003a: return "kalm_flashback_dragon";
+        case 0x003b: return "junon_pipe";
+        case 0x003c: return "blank";
+        case 0x003d: return "railway_canyon";
+        case 0x003e: return "whirlwind_maze_crater";
+        case 0x003f: return "railway_rollercoaster";
+        case 0x0040: return "wooden_bridge";
+        case 0x0041: return "da_chao";
+        case 0x0042: return "fort_condor";
+        case 0x0043: return "dirt_wasteland";
+        case 0x0044: return "bizarro_battle_right";
+        case 0x0045: return "bizarro_battle_left";
+        case 0x0046: return "jenova_synthesis";
+        case 0x0047: return "corel_train_battle";
+        case 0x0048: return "cosmo_canyon";
+        case 0x0049: return "caverns_of_the_gi";
+        case 0x004a: return "nibelheim_mansion_basement";
+        case 0x004b: return "ancients_demons_gate";
+        case 0x004c: return "ancients_mural_room";
+        case 0x004d: return "ancients_clock_passage";
+        case 0x004e: return "final_battle";
+        case 0x004f: return "jungle";
+        case 0x0050: return "ultimate_weapon_highwind";
+        case 0x0051: return "corel_reactor";
+        case 0x0052: return "unused";
+        case 0x0053: return "don_corneos_mansion";
+        case 0x0054: return "emerald_weapon_battle";
+        case 0x0055: return "reactor_5";
+        case 0x0056: return "shinra_hq_-_escape";
+        case 0x0057: return "ultimate_weapon_gongaga";
+        case 0x0058: return "corel_prison_dyne";
+        case 0x0059: return "ultimate_weapon_forest";
+        default: return "unknonw_location";
     }
 }

+ 182 - 182
src/installer/data/FF7Data.h

@@ -2423,543 +2423,543 @@ class FF7Data{
                 info.is_enemy = true;
             }
             else if("og" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x00;
                 info.name = "Blank";
                 info.name_normal = "blank";
                 info.is_scene = true;
             }
             else if("oh" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x01;
                 info.name = "Bizarro Sephiroth Battle - Center";
-                info.name_normal = "bizarro sephiroth battle center";
+                info.name_normal = "bizarro_battle";
                 info.is_scene = true;
             }
             else if("oi" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x02;
                 info.name = "Grassland";
                 info.name_normal = "grassland";
                 info.is_scene = true;
             }
             else if("oj" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x03;
                 info.name = "Mt. Nibel";
-                info.name_normal = "mt nibel";
+                info.name_normal = "mt_nibel";
                 info.is_scene = true;
             }
             else if("ok" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x04;
                 info.name = "Forest";
                 info.name_normal = "forest";
                 info.is_scene = true;
             }
             else if("ol" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x05;
                 info.name = "Beach";
                 info.name_normal = "beach";
                 info.is_scene = true;
             }
             else if("om" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x06;
                 info.name = "Desert";
                 info.name_normal = "desert";
                 info.is_scene = true;
             }
             else if("on" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x07;
                 info.name = "Snow";
                 info.name_normal = "snow";
                 info.is_scene = true;
             }
             else if("oo" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x08;
                 info.name = "Swamp";
                 info.name_normal = "swamp";
                 info.is_scene = true;
             }
             else if("op" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x09;
                 info.name = "Sector 1 Train Station";
-                info.name_normal = "sector 1 train station";
+                info.name_normal = "sector_1_train_station";
                 info.is_scene = true;
             }
             else if("oq" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x0a;
                 info.name = "Reactor 1";
-                info.name_normal = "reactor 1";
+                info.name_normal = "reactor_1";
                 info.is_scene = true;
             }
             else if("or" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x0b;
                 info.name = "Reactor 1 Core";
-                info.name_normal = "reactor 1 core";
+                info.name_normal = "reactor_1_core";
                 info.is_scene = true;
             }
             else if("os" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x0c;
                 info.name = "Reactor 1 Entrance";
-                info.name_normal = "reactor 1 entrance";
+                info.name_normal = "reactor_1_entrance";
                 info.is_scene = true;
             }
             else if("ot" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x0d;
                 info.name = "Sector 4 Subway";
-                info.name_normal = "sector 4 subway";
+                info.name_normal = "sector_4_subway";
                 info.is_scene = true;
             }
             else if("ou" == alphanumeric_id){
-                info.numeric_id = 4;
-                info.name = "Mythril Caves or Nibel Caves or AForest Caves";
-                info.name_normal = "mythril caves or nibel caves or aforest caves";
+                info.numeric_id = 0x0e;
+                info.name = "Nibel Caves";
+                info.name_normal = "nibel_caves";
                 info.is_scene = true;
             }
             else if("ov" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x0f;
                 info.name = "Shinra HQ";
-                info.name_normal = "shinra hq";
+                info.name_normal = "shinra_hq";
                 info.is_scene = true;
             }
             else if("ow" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x10;
                 info.name = "Midgar Raid Subway";
-                info.name_normal = "midgar raid subway";
+                info.name_normal = "midgar_raid_subway";
                 info.is_scene = true;
             }
             else if("ox" == alphanumeric_id){
-                info.numeric_id = 4;
-                info.name = "Hojo's Lab Battle Field";
-                info.name_normal = "hojos lab battle field";
+                info.numeric_id = 0x11;
+                info.name = "Hojos Lab";
+                info.name_normal = "hojos_lab";
                 info.is_scene = true;
             }
             else if("oy" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x12;
                 info.name = "Shinra Elevators";
-                info.name_normal = "shinra elevators";
+                info.name_normal = "shinra_elevators";
                 info.is_scene = true;
             }
             else if("oz" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x13;
                 info.name = "Shinra Roof";
-                info.name_normal = "shinra roof";
+                info.name_normal = "shinra_roof";
                 info.is_scene = true;
             }
             else if("pa" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x14;
                 info.name = "Midgar Highway";
-                info.name_normal = "midgar highway";
+                info.name_normal = "midgar_highway";
                 info.is_scene = true;
             }
             else if("pb" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x15;
                 info.name = "Wutai Pagoda";
-                info.name_normal = "wutai pagoda";
+                info.name_normal = "wutai_pagoda";
                 info.is_scene = true;
             }
             else if("pc" == alphanumeric_id){
-                info.numeric_id = 4;
-                info.name = "Church Battle Field";
-                info.name_normal = "church battle field";
+                info.numeric_id = 0x16;
+                info.name = "Church";
+                info.name_normal = "church";
                 info.is_scene = true;
             }
             else if("pd" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x17;
                 info.name = "Coral Valley";
-                info.name_normal = "coral valley";
+                info.name_normal = "coral_valley";
                 info.is_scene = true;
             }
             else if("pe" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x18;
                 info.name = "Midgar Slums";
-                info.name_normal = "midgar slums";
+                info.name_normal = "midgar_slums";
                 info.is_scene = true;
             }
             else if("pf" == alphanumeric_id){
-                info.numeric_id = 4;
-                info.name = "Sector 4 Corridors or Junon Path";
-                info.name_normal = "sector 4 corridors or junon path";
+                info.numeric_id = 0x19;
+                info.name = "Sector 4 Corridors";
+                info.name_normal = "sector_4_corridors";
                 info.is_scene = true;
             }
             else if("pg" == alphanumeric_id){
-                info.numeric_id = 4;
-                info.name = "Sector 4 Gantries or Midgar Underground";
-                info.name_normal = "sector 4 gantries or midgar underground";
+                info.numeric_id = 0x1a;
+                info.name = "Sector 4 Gantries";
+                info.name_normal = "sector_4_gantries";
                 info.is_scene = true;
             }
             else if("ph" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x1b;
                 info.name = "Sector 7 Support Pillar Stairway";
-                info.name_normal = "sector 7 support pillar stairway";
+                info.name_normal = "sector_7_pillar_stairway";
                 info.is_scene = true;
             }
             else if("pi" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x1c;
                 info.name = "Sector 7 Support Pillar Top";
-                info.name_normal = "sector 7 support pillar top";
+                info.name_normal = "sector_7_pillar top";
                 info.is_scene = true;
             }
             else if("pj" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x1d;
                 info.name = "Sector 8";
-                info.name_normal = "sector 8";
+                info.name_normal = "sector_8";
                 info.is_scene = true;
             }
             else if("pk" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x1e;
                 info.name = "Sewers";
                 info.name_normal = "sewers";
                 info.is_scene = true;
             }
             else if("pl" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x1f;
                 info.name = "Mythril Mines";
-                info.name_normal = "mythril mines";
+                info.name_normal = "mythril_mines";
                 info.is_scene = true;
             }
             else if("pm" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x20;
                 info.name = "Northern Crater - Floating Platforms";
-                info.name_normal = "northern crater floating platforms";
+                info.name_normal = "crater_floating_platforms";
                 info.is_scene = true;
             }
             else if("pn" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x21;
                 info.name = "Corel Mountain Path";
-                info.name_normal = "corel mountain path";
+                info.name_normal = "corel_mountain_path";
                 info.is_scene = true;
             }
             else if("po" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x22;
                 info.name = "Junon Beach";
-                info.name_normal = "junon beach";
+                info.name_normal = "junon_beach";
                 info.is_scene = true;
             }
             else if("pp" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x23;
                 info.name = "Junon Cargo Ship";
-                info.name_normal = "junon cargo ship";
+                info.name_normal = "junon_cargo_ship";
                 info.is_scene = true;
             }
             else if("pq" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x24;
                 info.name = "Corel Prison";
-                info.name_normal = "corel prison";
+                info.name_normal = "corel_prison";
                 info.is_scene = true;
             }
             else if("pr" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x25;
                 info.name = "Battle Square";
-                info.name_normal = "battle square";
+                info.name_normal = "battle_square";
                 info.is_scene = true;
             }
             else if("ps" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x26;
                 info.name = "Da Chao - Rapps Battle";
-                info.name_normal = "da chao rapps battle";
+                info.name_normal = "da_chao_rapps_battle";
                 info.is_scene = true;
             }
             else if("pt" == alphanumeric_id){
-                info.numeric_id = 4;
-                info.name = "Cid's Backyard";
-                info.name_normal = "cids backyard";
+                info.numeric_id = 0x27;
+                info.name = "Cids Backyard";
+                info.name_normal = "cids_backyard";
                 info.is_scene = true;
             }
             else if("pu" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x28;
                 info.name = "Final Descent to Sephiroth";
-                info.name_normal = "final descent to sephiroth";
+                info.name_normal = "final_descent_to_sephiroth";
                 info.is_scene = true;
             }
             else if("pv" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x29;
                 info.name = "Reactor 5 Entrance";
-                info.name_normal = "reactor 5 entrance";
+                info.name_normal = "reactor_5_entrance";
                 info.is_scene = true;
             }
             else if("pw" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x2a;
                 info.name = "Temple of the Ancients - Escher Room";
-                info.name_normal = "temple of the ancients escher room";
+                info.name_normal = "ancients_escher_room";
                 info.is_scene = true;
             }
             else if("px" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x2b;
                 info.name = "Shinra Mansion";
-                info.name_normal = "shinra mansion";
+                info.name_normal = "shinra_mansion";
                 info.is_scene = true;
             }
             else if("py" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x2c;
                 info.name = "Junon Airship Dock";
-                info.name_normal = "junon airship dock";
+                info.name_normal = "junon_airship_dock";
                 info.is_scene = true;
             }
             else if("pz" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x2d;
                 info.name = "Whirlwind Maze";
-                info.name_normal = "whirlwind maze";
+                info.name_normal = "whirlwind_maze";
                 info.is_scene = true;
             }
             else if("qa" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x2e;
                 info.name = "Junon Underwater Reactor";
-                info.name_normal = "junon underwater reactor";
+                info.name_normal = "junon_underwater_reactor";
                 info.is_scene = true;
             }
             else if("qb" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x2f;
                 info.name = "Gongaga Reactor";
-                info.name_normal = "gongaga reactor";
+                info.name_normal = "gongaga_reactor";
                 info.is_scene = true;
             }
             else if("qc" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x30;
                 info.name = "Gelnika";
                 info.name_normal = "gelnika";
                 info.is_scene = true;
             }
             else if("qd" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x31;
                 info.name = "Train Graveyard";
-                info.name_normal = "train graveyard";
+                info.name_normal = "train_graveyard";
                 info.is_scene = true;
             }
             else if("qe" == alphanumeric_id){
-                info.numeric_id = 4;
-                info.name = "Great Glacier Ice Caves & Gaea Cliffs - Inside";
-                info.name_normal = "great glacier ice caves and gaea cliffs inside";
+                info.numeric_id = 0x32;
+                info.name = "Great Glacier Ice Caves Gaea Cliffs Inside";
+                info.name_normal = "ice_caves";
                 info.is_scene = true;
             }
             else if("qf" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x33;
                 info.name = "Sister Ray";
-                info.name_normal = "sister ray";
+                info.name_normal = "sister_ray";
                 info.is_scene = true;
             }
             else if("qg" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x34;
                 info.name = "Sister Ray Base";
-                info.name_normal = "sister ray base";
+                info.name_normal = "sister_ray_base";
                 info.is_scene = true;
             }
             else if("qh" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x35;
                 info.name = "Forgotten City Altar";
-                info.name_normal = "forgotten city altar";
+                info.name_normal = "forgotten_city_altar";
                 info.is_scene = true;
             }
             else if("qi" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x36;
                 info.name = "Northern Crater - Initial Descent";
-                info.name_normal = "northern crater initial descent";
+                info.name_normal = "crater_descent";
                 info.is_scene = true;
             }
             else if("qj" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x37;
                 info.name = "Northern Crater - Hatchery";
-                info.name_normal = "northern crater hatchery";
+                info.name_normal = "crater_hatchery";
                 info.is_scene = true;
             }
             else if("qk" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x38;
                 info.name = "Northern Crater - Water Area";
-                info.name_normal = "northern crater water area";
+                info.name_normal = "crater_water_area";
                 info.is_scene = true;
             }
             else if("ql" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x39;
                 info.name = "Safer Battle";
-                info.name_normal = "safer battle";
+                info.name_normal = "safer_battle";
                 info.is_scene = true;
             }
             else if("qm" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x3a;
                 info.name = "Kalm Flashback - Dragon Battle";
-                info.name_normal = "kalm flashback dragon battle";
+                info.name_normal = "kalm_flashback_dragon";
                 info.is_scene = true;
             }
             else if("qn" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x3b;
                 info.name = "Junon Underwater Pipe";
-                info.name_normal = "junon underwater pipe";
+                info.name_normal = "junon_pipe";
                 info.is_scene = true;
             }
             else if("qo" == alphanumeric_id){
-                info.numeric_id = 4;
-                info.name = "Blank";
-                info.name_normal = "blank";
+                info.numeric_id = 0x3c;
+                info.name = "Blank - 2";
+                info.name_normal = "blank_2";
                 info.is_scene = true;
             }
             else if("qp" == alphanumeric_id){
-                info.numeric_id = 4;
-                info.name = "qp";
-                info.name_normal = "qp";
+                info.numeric_id = 0x3d;
+                info.name = "unkonwon";
+                info.name_normal = "unknown_qp";
                 info.is_scene = true;
             }
             else if("qq" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x3d;
                 info.name = "Corel Railway - Canyon";
-                info.name_normal = "corel railway canyon";
+                info.name_normal = "railway_canyon";
                 info.is_scene = true;
             }
             else if("qr" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x3e;
                 info.name = "Whirlwind Maze - Crater";
-                info.name_normal = "whirlwind maze crater";
+                info.name_normal = "whirlwind_maze_crater";
                 info.is_scene = true;
             }
             else if("qs" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x3f;
                 info.name = "Corel Railway - Rollercoaster";
-                info.name_normal = "corel railway rollercoaster";
+                info.name_normal = "railway_rollercoaster";
                 info.is_scene = true;
             }
             else if("qt" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x40;
                 info.name = "Wooden Bridge";
-                info.name_normal = "wooden bridge";
+                info.name_normal = "wooden_bridge";
                 info.is_scene = true;
             }
             else if("qu" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x41;
                 info.name = "Da Chao";
-                info.name_normal = "da chao";
+                info.name_normal = "da_chao";
                 info.is_scene = true;
             }
             else if("qv" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x42;
                 info.name = "Fort Condor";
-                info.name_normal = "fort condor";
+                info.name_normal = "fort_condor";
                 info.is_scene = true;
             }
             else if("qw" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x44;
                 info.name = "Bizarro Battle - Right Side";
-                info.name_normal = "bizarro battle right side";
+                info.name_normal = "bizarro_battle_right";
                 info.is_scene = true;
             }
             else if("qx" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x45;
                 info.name = "Bizarro Battle - Left Side";
-                info.name_normal = "bizarro battle left side";
+                info.name_normal = "bizarro_battle_left";
                 info.is_scene = true;
             }
             else if("qy" == alphanumeric_id){
-                info.numeric_id = 4;
-                info.name = "Jenova*SYNTHESIS Battle";
-                info.name_normal = "jenova synthesis battle";
+                info.numeric_id = 0x46;
+                info.name = "Jenova SYNTHESIS Battle";
+                info.name_normal = "jenova_synthesis";
                 info.is_scene = true;
             }
             else if("qz" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x47;
                 info.name = "Corel Train Battle";
-                info.name_normal = "corel train battle";
+                info.name_normal = "corel_train_battle";
                 info.is_scene = true;
             }
             else if("ra" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x48;
                 info.name = "Cosmo Canyon";
-                info.name_normal = "cosmo canyon";
+                info.name_normal = "cosmo_canyon";
                 info.is_scene = true;
             }
             else if("rb" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x49;
                 info.name = "Caverns of the Gi";
-                info.name_normal = "caverns of the gi";
+                info.name_normal = "caverns_of_the_gi";
                 info.is_scene = true;
             }
             else if("rc" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x4a;
                 info.name = "Nibelheim Mansion Basement";
-                info.name_normal = "nibelheim mansion basement";
+                info.name_normal = "nibelheim_mansion_basement";
                 info.is_scene = true;
             }
             else if("rd" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x4b;
                 info.name = "Temple of the Ancients - Demons Gate";
-                info.name_normal = "temple of the ancients demons gate";
+                info.name_normal = "ancients_demons_gate";
                 info.is_scene = true;
             }
             else if("re" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x4c;
                 info.name = "Temple of the Ancients - Mural Room";
-                info.name_normal = "temple of the ancients mural room";
+                info.name_normal = "ancients_mural_room";
                 info.is_scene = true;
             }
             else if("rf" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x4d;
                 info.name = "Temple of the Ancients - Clock Passage";
-                info.name_normal = "temple of the ancients clock passage";
+                info.name_normal = "ancients_clock_passage";
                 info.is_scene = true;
             }
             else if("rg" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x4e;
                 info.name = "Final Battle - Sephiroth";
-                info.name_normal = "final battle sephiroth";
+                info.name_normal = "final_battle";
                 info.is_scene = true;
             }
             else if("rh" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x4f;
                 info.name = "Jungle";
                 info.name_normal = "jungle";
                 info.is_scene = true;
             }
             else if("ri" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x50;
                 info.name = "Ultimate Weapon - Battle on Highwind";
-                info.name_normal = "ultimate weapon highwind";
+                info.name_normal = "ultimate_weapon_highwind";
                 info.is_scene = true;
             }
             else if("rj" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x51;
                 info.name = "Corel Reactor";
-                info.name_normal = "corel reactor";
+                info.name_normal = "corel_reactor";
                 info.is_scene = true;
             }
             else if("rk" == alphanumeric_id){
-                info.numeric_id = 4;
-                info.name = "Blank";
-                info.name_normal = "blank";
+                info.numeric_id = 0x52;
+                info.name = "Unused";
+                info.name_normal = "unused";
                 info.is_scene = true;
             }
             else if("rl" == alphanumeric_id){
-                info.numeric_id = 4;
-                info.name = "Don Corneo's Mansion";
-                info.name_normal = "don corneos mansion";
+                info.numeric_id = 0x53;
+                info.name = "Don Corneos Mansion";
+                info.name_normal = "don_corneos_mansion";
                 info.is_scene = true;
             }
             else if("rm" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x54;
                 info.name = "Emerald Weapon Battle";
-                info.name_normal = "emerald weapon battle";
+                info.name_normal = "emerald_weapon_battle";
                 info.is_scene = true;
             }
             else if("rn" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x55;
                 info.name = "Reactor 5";
-                info.name_normal = "reactor 5";
+                info.name_normal = "reactor_5";
                 info.is_scene = true;
             }
             else if("ro" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x56;
                 info.name = "Shinra HQ - Escape";
-                info.name_normal = "shinra hq escape";
+                info.name_normal = "shinra_hq_escape";
                 info.is_scene = true;
             }
             else if("rp" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x57;
                 info.name = "Ultimate Weapon - Gongaga Reactor";
-                info.name_normal = "ultimate weapon gongaga reactor";
+                info.name_normal = "ultimate_weapon_gongaga";
                 info.is_scene = true;
             }
             else if("rq" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x58;
                 info.name = "Corel Prison - Dyne Battle";
-                info.name_normal = "corel prison dyne battle";
+                info.name_normal = "corel_prison_dyne";
                 info.is_scene = true;
             }
             else if("rr" == alphanumeric_id){
-                info.numeric_id = 4;
+                info.numeric_id = 0x59;
                 info.name = "Ultimate Weapon - Forest";
-                info.name_normal = "ultimate weapon forest";
+                info.name_normal = "ultimate_weapon_forest";
                 info.is_scene = true;
             }
             else if ("rs" == alphanumeric_id){