Преглед на файлове

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 години
родител
ревизия
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){