Selaa lähdekoodia

Installer: The kernel parser extracts command data.

Iñigo Valentin 3 vuotta sitten
vanhempi
sitoutus
24e7f02c53

+ 0 - 21
.gitmodules

@@ -1,21 +0,0 @@
-[submodule "dependencies/tinyxml"]
-	path = dependencies/tinyxml
-	url = git://github.com/paulsapps/TinyXML.git
-[submodule "dependencies/luabind"]
-	path = dependencies/luabind
-	url = https://github.com/paulsapps/luabind.git
-	branch = master
-[submodule "output/data"]
-	path = output/data
-	url = https://github.com/q-gears/data.git
-	branch = master
-[submodule "dependencies/luajit"]
-	path = dependencies/luajit
-	url = https://github.com/q-gears/luajit.git
-	branch = master
-[submodule "dependencies/SUDM"]
-	path = dependencies/SUDM
-	url = https://github.com/paulsapps/SUDM.git
-[submodule "dependencies/cotire"]
-	path = dependencies/cotire
-	url = https://github.com/sakra/cotire

+ 3 - 3
README.md

@@ -1,4 +1,4 @@
-# <img src="../v-gears.png" alt="V-Gears" width="50"/> V-Gears
+# <img src="doc/v-gears.png" alt="V-Gears" width="50"/> V-Gears
 
 
 ## What is V-Gears? 
 ## What is V-Gears? 
 
 
@@ -18,7 +18,7 @@ The field engine is almost completly functional. Once the little quircks in the
 
 
 ## In the meantime...
 ## In the meantime...
 
 
-If it picked your curiosity, you can check out the [history](HISTORY.md "V-Gears history") behind the project. Or, if you want to try it for yourself, maybe the [build](BUILD.md "Building guide") and [installaton](INSTALL.md "Installation guide") guides are a good place to start.
+If it picked your curiosity, you can check out the [history](doc/HISTORY.md "V-Gears history") behind the project. Or, if you want to try it for yourself, maybe the [build](doc/BUILD.md "Building guide") and [installaton](doc/INSTALL.md "Installation guide") guides are a good place to start.
 
 
-Or even better, if you want to see this done and want to contribute, clone the repo, read the [style guid](STYLE.md "V-Gears C++ Style Guide") and have a go at it!
+Or even better, if you want to see this done and want to contribute, clone the repo, read the [style guid](doc/STYLE.md "V-Gears C++ Style Guide") and have a go at it!
 
 

+ 103 - 9
V-Gears-Installer/include/KernelDataInstaller.h

@@ -49,6 +49,20 @@ class KernelDataInstaller{
          */
          */
         void WriteItems(std::string file);
         void WriteItems(std::string file);
 
 
+        /**
+         * Reads the command from the kernel.
+         *
+         * @return The number of items read.
+         */
+        int ReadCommands();
+
+        /**
+         * Saves command data to an xml file
+         *
+         * @param file[in] Absolute path to the target XML file.
+         */
+        void WriteCommands(std::string file);
+
     private:
     private:
 
 
         enum KERNEL_SECTIONS{
         enum KERNEL_SECTIONS{
@@ -363,22 +377,27 @@ class KernelDataInstaller{
         /**
         /**
          * Determines what an item affects on when used from the menu.
          * Determines what an item affects on when used from the menu.
          */
          */
-        struct TargetCondition{
+        enum RESTORE_TYPE{
 
 
             /**
             /**
              * The item affects a party member or group HP.
              * The item affects a party member or group HP.
              */
              */
-            bool party_hp;
+            RESTORE_HP = 0,
 
 
             /**
             /**
              * The item affects a party member or group MP.
              * The item affects a party member or group MP.
              */
              */
-            bool party_mp;
+            RESTORE_MP = 1,
 
 
             /**
             /**
              * The item affects a party member or group status.
              * The item affects a party member or group status.
              */
              */
-            bool party_status;
+            RESTORE_STATUS = 2,
+
+            /**
+             * The item is not restorative.
+             */
+            RESTORE_NONE = 3
         };
         };
 
 
         /**
         /**
@@ -592,6 +611,76 @@ class KernelDataInstaller{
 
 
         };
         };
 
 
+        /**
+         * Data for each command.
+         *
+         * As found in KERNEL.BIN, file 0, in order, up to camera_multiple. Members after
+         * camera_multiple are not found literally in KERNEL.BIN, but are derived from other
+         * members or found in other files of the kernel (text files).
+         */
+        struct CommandData{
+
+            /**
+             * Cursor action when the command is selected.
+             */
+            u8 cursor_action;
+
+            /**
+             * Targeting mode. 1 byte.
+             *
+             * See {@see target} and {@TargetModes} for more information.
+             */
+            u8 target_raw;
+
+            /**
+             * Unknown data (Always 0XFFFF). 2 bytes.
+             */
+            u16 unknown;
+
+            /**
+             * Camera movement ID for single target. 2 bytes.
+             *
+             * Determines the camera movement when the command is executed over a single target.
+             */
+            u16 camera_single;
+
+            /**
+             * Camera movement ID for multiple target. 2 bytes.
+             *
+             * Determines the camera movement when the command is executed over multiple targets.
+             */
+            u16 camera_multiple;
+
+            /**
+             * Command ID.
+             *
+             * Not actually in the item file data, it's the order at which it appears.
+             */
+            int id;
+
+            /**
+             * Command name.
+             *
+             * Not found in the same file as the rest of the data, but on file 17.
+             */
+            std::string name;
+
+            /**
+             * Command description.
+             *
+             * Not found in the same file as the rest of the data, but on file 9.
+             */
+            std::string description;
+
+            /**
+             * Target selection mode.
+             *
+             * Derived from {@see target_raw}.
+             */
+            Target target;
+
+        };
+
         /**
         /**
          * Data for each items
          * Data for each items
          *
          *
@@ -659,9 +748,9 @@ class KernelDataInstaller{
             u8 power;
             u8 power;
 
 
             /**
             /**
-             * Item affected condition when used in menu. 1 byte.
+             * The restore type.
              *
              *
-             * See {@condition} and {@ItemCondition} for more information.
+             * See {@restore_typ} and {@RESTORE_TYPE} for more information.
              */
              */
             u8 condition_raw;
             u8 condition_raw;
 
 
@@ -772,11 +861,11 @@ class KernelDataInstaller{
             u8 damage_modifier;
             u8 damage_modifier;
 
 
             /**
             /**
-             * What the item affects when.
+             * What the item restores when used.
              *
              *
-             * Derived from {@see condition_raw}.
+             * Same as {@see condition_raw}, except for the wrong cases.
              */
              */
-            TargetCondition condition;
+            RESTORE_TYPE restore_type;
 
 
             /**
             /**
              * Status effects.
              * Status effects.
@@ -794,6 +883,11 @@ class KernelDataInstaller{
 
 
         };
         };
 
 
+        /**
+         * Items read from the kernel
+         */
+        std::vector<CommandData> commands_;
+
         /**
         /**
          * Items read from the kernel
          * Items read from the kernel
          */
          */

+ 4 - 0
V-Gears-Installer/src/DataInstaller.cpp

@@ -97,6 +97,10 @@ int DataInstaller::Progress(){
             kernel_installer_ = std::make_unique<KernelDataInstaller>(
             kernel_installer_ = std::make_unique<KernelDataInstaller>(
               input_dir_ += "kernel/KERNEL.BIN"
               input_dir_ += "kernel/KERNEL.BIN"
             );
             );
+            if (kernel_installer_->ReadCommands() > 0){
+                CreateDir("game");
+                kernel_installer_->WriteCommands(output_dir_ + "game/commands.xml");
+            }
             if (kernel_installer_->ReadItems() > 0){
             if (kernel_installer_->ReadItems() > 0){
                 CreateDir("game");
                 CreateDir("game");
                 kernel_installer_->WriteItems(output_dir_ + "game/items.xml");
                 kernel_installer_->WriteItems(output_dir_ + "game/items.xml");

+ 163 - 10
V-Gears-Installer/src/KernelDataInstaller.cpp

@@ -21,6 +21,127 @@ KernelDataInstaller::KernelDataInstaller(std::string path): kernel_(path){}
 
 
 KernelDataInstaller::~KernelDataInstaller(){}
 KernelDataInstaller::~KernelDataInstaller(){}
 
 
+int KernelDataInstaller::ReadCommands(){
+
+    // Empty the item list
+    commands_.clear();
+
+    File command_file = kernel_.ExtractGZip(KERNEL_COMMAND_DATA);
+    File command_name_file = kernel_.ExtractGZip(KERNEL_COMMAND_NAMES);
+    File command_desc_file = kernel_.ExtractGZip(KERNEL_COMMAND_DESCRIPTIONS);
+    int name_offset = 0;
+    int desc_offset = 0;
+    int command_count = 0;
+
+    std::cout << "|  ID | cur | c_s | c_m| tar |\n";
+
+    // There are exactly 32 commands. Some of them are blank, so there is not really a
+    // reliable exit condition.
+    for (int i = 0; i < 32; i ++){
+
+        CommandData data;
+
+        // From the current name file offset, read 16 bytes.
+        // This is the pointer to the offset for the item name.
+        // Start reading there until 0xFF is found.
+        data.name = "";
+        u8 ch = 1;
+        name_offset = command_name_file.readU16LE();
+        while (ch != 0xFF){
+            ch = command_name_file.GetU8(name_offset);
+            if (ch != 0xFF) data.name += ENGLISH_CHARS[ch];
+            name_offset ++;
+        }
+
+        // For descriptions, do the same as for names.
+        data.description = "";
+        ch = 1;
+        desc_offset = command_desc_file.readU16LE();
+        while (ch != 0xFF){
+            ch = command_desc_file.GetU8(desc_offset);
+            if (ch != 0xFF){
+                // Warning: If the char is 0xF9, special function!
+                // the next byte (in bits, aaoooooo) means to read aa data at offset oooooo.
+                // This is to compress information in the kernel.
+                if (ch == 0xF9){
+                    // Get how much to read, two upper bits of the next byte.
+                    // Multiply by 2 and add 4. That's just how it is.
+                    u8 comp_size = (command_desc_file.GetU8(desc_offset + 1) >> 6) * 2 + 4;
+                    // Get new offset, lower six bits of the next byte.
+                    // The offset goes backwards from the position of the 0xF9 byte.
+                    u8 comp_offset = command_desc_file.GetU8(desc_offset + 1) & 63;
+
+                    for (int i = 0; i < comp_size; i ++){
+                        data.description += ENGLISH_CHARS[
+                          command_desc_file.GetU8(desc_offset - 1 - comp_offset + i)
+                        ];
+                    }
+                    desc_offset ++;
+                }
+                else data.description += ENGLISH_CHARS[ch];
+            }
+            desc_offset ++;
+        }
+
+        // Read data from the item data section.
+        data.cursor_action = command_file.readU8();
+        data.target_raw = command_file.readU8();
+        data.camera_single = command_file.readU16LE();
+        data.camera_multiple = command_file.readU16LE();
+
+        // Derive data from the read data.
+        data.id = i;
+        if (data.target_raw == (data.target_raw | 0x01)) data.target.selection_enabled = true;
+        else data.target.selection_enabled = false;
+        if (data.target_raw == (data.target_raw | 0x02)) data.target.default_enemy = true;
+        else data.target.default_enemy = false;
+        if (data.target_raw == (data.target_raw | 0x04)) data.target.default_multiple = true;
+        else data.target.default_multiple = false;
+        if (data.target_raw == (data.target_raw | 0x08)) data.target.toggle_multiple = true;
+        else data.target.toggle_multiple = false;
+        if (data.target_raw == (data.target_raw | 0x10)) data.target.fixed_row = true;
+        else data.target.fixed_row = false;
+        if (data.target_raw == (data.target_raw | 0x20)) data.target.short_range = true;
+        else data.target.short_range = false;
+        if (data.target_raw == (data.target_raw | 0x40)) data.target.default_enemy = true;
+        else data.target.all_rows = false;
+        if (data.target_raw == (data.target_raw | 0x80)) data.target.random = true;
+        else data.target.random = false;
+
+        // Add to the list of items.
+        if (data.name != ""){
+            commands_.push_back(data);
+            command_count ++;
+        }
+
+        printf(
+          "| %3d | %3d | %3d | %3d | ",
+          i, data.camera_single, data.camera_multiple, data.target_raw
+        );
+        std::cout << data.name << ": " << data.description << std::endl;
+
+
+    }
+
+    return command_count;
+}
+
+void KernelDataInstaller::WriteCommands(std::string file){
+    TiXmlDocument xml;
+    std::unique_ptr<TiXmlElement> container(new TiXmlElement("commands"));
+    for (CommandData command : commands_){
+        std::unique_ptr<TiXmlElement> xml_command(new TiXmlElement("item"));
+        xml_command->SetAttribute("id", command.id);
+        xml_command->SetAttribute("name", command.name);
+        xml_command->SetAttribute("description", command.description);
+        xml_command->SetAttribute("camera_1", command.camera_single);
+        xml_command->SetAttribute("camera_x", command.camera_single);
+        container->LinkEndChild(xml_command.release());
+    }
+    xml.LinkEndChild(container.release());
+    xml.SaveFile(file);
+}
+
 int KernelDataInstaller::ReadItems(){
 int KernelDataInstaller::ReadItems(){
 
 
     // Empty the item list
     // Empty the item list
@@ -77,9 +198,7 @@ int KernelDataInstaller::ReadItems(){
                     }
                     }
                     desc_offset ++;
                     desc_offset ++;
                 }
                 }
-                else{
-                    data.description += ENGLISH_CHARS[ch];
-                }
+                else data.description += ENGLISH_CHARS[ch];
             }
             }
             desc_offset ++;
             desc_offset ++;
         }
         }
@@ -111,6 +230,7 @@ int KernelDataInstaller::ReadItems(){
         data.useable_battle = !(data.restrict_raw & (2 << 0));
         data.useable_battle = !(data.restrict_raw & (2 << 0));
         data.useable_menu = !(data.restrict_raw & (4 << 0));
         data.useable_menu = !(data.restrict_raw & (4 << 0));
         // TODO: XOR, not individual bits
         // TODO: XOR, not individual bits
+        /*
         data.target.selection_enabled = data.target_raw & (0 << 0); // First bit...
         data.target.selection_enabled = data.target_raw & (0 << 0); // First bit...
         data.target.default_enemy = data.target_raw & (1 << 0);
         data.target.default_enemy = data.target_raw & (1 << 0);
         data.target.default_multiple = data.target_raw & (2 << 0);
         data.target.default_multiple = data.target_raw & (2 << 0);
@@ -119,19 +239,45 @@ int KernelDataInstaller::ReadItems(){
         data.target.short_range = data.target_raw & (5 << 0);
         data.target.short_range = data.target_raw & (5 << 0);
         data.target.all_rows = data.target_raw & (6 << 0);
         data.target.all_rows = data.target_raw & (6 << 0);
         data.target.random = data.target_raw & (7 << 0); // ... last bit.
         data.target.random = data.target_raw & (7 << 0); // ... last bit.
+        */
+        if (data.target_raw == (data.target_raw | 0x01)) data.target.selection_enabled = true;
+        else data.target.selection_enabled = false;
+        if (data.target_raw == (data.target_raw | 0x02)) data.target.default_enemy = true;
+        else data.target.default_enemy = false;
+        if (data.target_raw == (data.target_raw | 0x04)) data.target.default_multiple = true;
+        else data.target.default_multiple = false;
+        if (data.target_raw == (data.target_raw | 0x08)) data.target.toggle_multiple = true;
+        else data.target.toggle_multiple = false;
+        if (data.target_raw == (data.target_raw | 0x10)) data.target.fixed_row = true;
+        else data.target.fixed_row = false;
+        if (data.target_raw == (data.target_raw | 0x20)) data.target.short_range = true;
+        else data.target.short_range = false;
+        if (data.target_raw == (data.target_raw | 0x40)) data.target.default_enemy = true;
+        else data.target.all_rows = false;
+        if (data.target_raw == (data.target_raw | 0x80)) data.target.random = true;
+        else data.target.random = false;
+
+
         data.damage_formula = data.damage_raw >> 4; // Upper nybble.
         data.damage_formula = data.damage_raw >> 4; // Upper nybble.
         data.damage_modifier = data.damage_raw & 15; // Lower nybble.
         data.damage_modifier = data.damage_raw & 15; // Lower nybble.
-        data.condition.party_hp = data.condition_raw & (0 << 0); //First bit...
-        data.condition.party_mp = data.condition_raw & (1 << 0);
-        data.condition.party_status = data.condition_raw & (2 << 0); // ... last bit.
+        /*data.condition.party_hp = data.condition_raw & (0 << 0); //First bit...
+        data.condition.mp = data.condition_raw & (1 << 0);
+        data.condition.party_status = data.condition_raw & (2 << 0); // ... last bit.*/
 
 
-        data.status.chance = 64 - (data.status_change_raw ^ 63); // Out of 63;
+        data.status.chance = 63 - (data.status_change_raw ^ 63); // Out of 63;
         if (data.status_change_raw == (data.status_change_raw | 0x00000080))
         if (data.status_change_raw == (data.status_change_raw | 0x00000080))
             data.status.mode = TOGGLE;
             data.status.mode = TOGGLE;
         else if (data.status_change_raw == (data.status_change_raw | 0x00000040))
         else if (data.status_change_raw == (data.status_change_raw | 0x00000040))
             data.status.mode = CURE;
             data.status.mode = CURE;
         else data.status.mode = INFLICT;
         else data.status.mode = INFLICT;
 
 
+        switch (data.condition_raw){
+            case 0: data.restore_type = RESTORE_HP; break;
+            case 1: data.restore_type = RESTORE_MP; break;
+            case 2: data.restore_type = RESTORE_STATUS; break;
+            default: data.restore_type = RESTORE_NONE;
+        }
+
 
 
         // In KERNEL.BIN, items that don't induce statuses actually have all statuses marked, and
         // In KERNEL.BIN, items that don't induce statuses actually have all statuses marked, and
         // a chance of 255. If it's the case, skip statuses altogether.
         // a chance of 255. If it's the case, skip statuses altogether.
@@ -260,7 +406,16 @@ void KernelDataInstaller::WriteItems(std::string file){
         xml_item->SetAttribute("dmg_formula", item.damage_formula);
         xml_item->SetAttribute("dmg_formula", item.damage_formula);
         xml_item->SetAttribute("dmg_modifier", item.damage_modifier);
         xml_item->SetAttribute("dmg_modifier", item.damage_modifier);
         xml_item->SetAttribute("power", item.power);
         xml_item->SetAttribute("power", item.power);
-        //if (item.status.status.size() > 0 && item.status.chance <= 64){
+        xml_item->SetAttribute("restore", item.restore_type);
+        xml_item->SetAttribute("target_select", item.target.selection_enabled);
+        xml_item->SetAttribute("target_default_enemy", item.target.default_enemy);
+        xml_item->SetAttribute("target_default_multiple", item.target.default_multiple);
+        xml_item->SetAttribute("target_toggle_multiple", item.target.toggle_multiple);
+        xml_item->SetAttribute("target_fixed", item.target.fixed_row);
+        xml_item->SetAttribute("target_short_range", item.target.short_range);
+        xml_item->SetAttribute("target_all", item.target.all_rows);
+        xml_item->SetAttribute("target_random", item.target.random);
+        // Statuses.
         if (item.status.status.size() > 0){
         if (item.status.status.size() > 0){
             std::unique_ptr<TiXmlElement> xml_status(new TiXmlElement("statuses"));
             std::unique_ptr<TiXmlElement> xml_status(new TiXmlElement("statuses"));
             xml_status->SetAttribute("mode", item.status.mode);
             xml_status->SetAttribute("mode", item.status.mode);
@@ -273,8 +428,6 @@ void KernelDataInstaller::WriteItems(std::string file){
             xml_item->LinkEndChild(xml_status.release());
             xml_item->LinkEndChild(xml_status.release());
         }
         }
         // Add elements.
         // Add elements.
-        // In KERNEL.BIN, Non elemental item actually have all elements marked. Don't print them.
-        //if (item.elements.size() > 0 && item.elements.size() < 16){
         if (item.elements.size() > 0){
         if (item.elements.size() > 0){
             std::unique_ptr<TiXmlElement> xml_elements(new TiXmlElement("elements"));
             std::unique_ptr<TiXmlElement> xml_elements(new TiXmlElement("elements"));
             for (int s : item.elements){
             for (int s : item.elements){

+ 6 - 20
V-Gears/src/common/File.cpp

@@ -13,7 +13,6 @@
  * GNU General Public License for more details.
  * GNU General Public License for more details.
  */
  */
 
 
-#include <iostream>
 #include <cassert>
 #include <cassert>
 #include <string.h>
 #include <string.h>
 #include "common/File.h"
 #include "common/File.h"
@@ -29,34 +28,25 @@ File::File(const Ogre::String& file):
     LOG_TRIVIAL("Loading file: " + file_name_ + "\n");
     LOG_TRIVIAL("Loading file: " + file_name_ + "\n");
     buffer_size_ = FileSystem::GetFileSize(file_name_);
     buffer_size_ = FileSystem::GetFileSize(file_name_);
     buffer_ = (u8*) malloc(sizeof(u8) * buffer_size_);
     buffer_ = (u8*) malloc(sizeof(u8) * buffer_size_);
-    if (!FileSystem::ReadFile(file_name_, buffer_, 0, buffer_size_)){
+    if (!FileSystem::ReadFile(file_name_, buffer_, 0, buffer_size_))
         LOG_TRIVIAL("Warning: " + file_name_ + " not found!\n");
         LOG_TRIVIAL("Warning: " + file_name_ + " not found!\n");
-    }
 }
 }
 
 
 File::File(const File* file, u32 offset, u32 length):
 File::File(const File* file, u32 offset, u32 length):
-  buffer_(nullptr),
-  buffer_size_(length),
-  offset_(offset)
+  buffer_(nullptr), buffer_size_(length), offset_(offset)
 {
 {
     assert(file != nullptr);
     assert(file != nullptr);
-
     file_name_ = file->GetFileName();
     file_name_ = file->GetFileName();
-
     buffer_ = (u8 *) malloc(sizeof(u8) * buffer_size_);
     buffer_ = (u8 *) malloc(sizeof(u8) * buffer_size_);
     file->GetFileBuffer(buffer_, offset_, buffer_size_);
     file->GetFileBuffer(buffer_, offset_, buffer_size_);
 }
 }
 
 
 File::File(const u8* buffer, u32 offset, u32 length):
 File::File(const u8* buffer, u32 offset, u32 length):
-  file_name_("BUFFER"),
-  buffer_(nullptr),
-  buffer_size_(length),
-  offset_(offset)
+  file_name_("BUFFER"), buffer_(nullptr), buffer_size_(length), offset_(offset)
 {
 {
     assert(buffer != nullptr);
     assert(buffer != nullptr);
     buffer_ = (u8*) malloc(sizeof(u8) * buffer_size_);
     buffer_ = (u8*) malloc(sizeof(u8) * buffer_size_);
     memcpy(buffer_, buffer + offset, buffer_size_);
     memcpy(buffer_, buffer + offset, buffer_size_);
-    std::cout << "New file from buffer. Size " << length << " Offset: " << offset << "/" << offset_ << "\n";
 }
 }
 
 
 File::File(const File* file){
 File::File(const File* file){
@@ -67,21 +57,17 @@ File::File(const File* file){
     file->GetFileBuffer(buffer_, 0, buffer_size_);
     file->GetFileBuffer(buffer_, 0, buffer_size_);
 }
 }
 
 
-File::~File(){
-    free(buffer_);
-}
+File::~File(){free(buffer_);}
 
 
 void File::WriteFile(const Ogre::String& file) const{
 void File::WriteFile(const Ogre::String& file) const{
-  FileSystem::WriteNewFile(file, buffer_, buffer_size_);
+    FileSystem::WriteNewFile(file, buffer_, buffer_size_);
 }
 }
 
 
 const Ogre::String& File::GetFileName() const{return file_name_;}
 const Ogre::String& File::GetFileName() const{return file_name_;}
 
 
 u32 File::GetFileSize() const{return buffer_size_;}
 u32 File::GetFileSize() const{return buffer_size_;}
 
 
-void File::GetFileBuffer(
-  u8* buffer, const u32 &start, const u32 &length
-) const{
+void File::GetFileBuffer(u8* buffer, const u32 &start, const u32 &length) const{
     memcpy(buffer, buffer_ + start, length);
     memcpy(buffer, buffer_ + start, length);
 }
 }