ソースを参照

More old SUDM code reformatted and documented. Field instructions separated in files by instruction type.

Iñigo Valentin 3 年 前
コミット
15c8111a7f
59 ファイル変更4654 行追加3973 行削除
  1. 1 1
      CMakeLists.txt
  2. 30 2
      V-Gears-Installer/CMakeLists.txt
  3. 1 1
      V-Gears-Installer/include/decompiler/decompiler_codegen.h
  4. 5 5
      V-Gears-Installer/include/decompiler/decompiler_engine.h
  5. 4 4
      V-Gears-Installer/include/decompiler/field/FieldDisassembler.h
  6. 400 0
      V-Gears-Installer/include/decompiler/field/FieldEngine.h
  7. 0 1554
      V-Gears-Installer/include/decompiler/field/ff7_field_engine.h
  8. 54 0
      V-Gears-Installer/include/decompiler/field/instruction/FieldBackgroundInstruction.h
  9. 48 0
      V-Gears-Installer/include/decompiler/field/instruction/FieldCameraInstruction.h
  10. 61 0
      V-Gears-Installer/include/decompiler/field/instruction/FieldCondJumpInstruction.h
  11. 186 0
      V-Gears-Installer/include/decompiler/field/instruction/FieldControlFlowInstruction.h
  12. 109 0
      V-Gears-Installer/include/decompiler/field/instruction/FieldMathInstruction.h
  13. 52 0
      V-Gears-Installer/include/decompiler/field/instruction/FieldMediaInstruction.h
  14. 374 0
      V-Gears-Installer/include/decompiler/field/instruction/FieldModelInstruction.h
  15. 117 0
      V-Gears-Installer/include/decompiler/field/instruction/FieldModuleInstruction.h
  16. 50 0
      V-Gears-Installer/include/decompiler/field/instruction/FieldNoOperationInstruction.h
  17. 46 0
      V-Gears-Installer/include/decompiler/field/instruction/FieldPartyInstruction.h
  18. 41 0
      V-Gears-Installer/include/decompiler/field/instruction/FieldUncategorizedInstruction.h
  19. 84 0
      V-Gears-Installer/include/decompiler/field/instruction/FieldUncondJumpInstruction.h
  20. 82 0
      V-Gears-Installer/include/decompiler/field/instruction/FieldWalkmeshInstruction.h
  21. 49 0
      V-Gears-Installer/include/decompiler/field/instruction/FieldWindowInstruction.h
  22. 26 16
      V-Gears-Installer/include/decompiler/instruction.h
  23. 26 26
      V-Gears-Installer/include/decompiler/test/cfg_test.cpp
  24. 10 10
      V-Gears-Installer/include/decompiler/test/codegen.cpp
  25. 1 1
      V-Gears-Installer/include/decompiler/test/disassembler/pasc.h
  26. 1 1
      V-Gears-Installer/include/decompiler/test/disassembler/subopcode.h
  27. 2 2
      V-Gears-Installer/include/decompiler/test/ff7_field_all_opcodes_disassembler_test.cpp
  28. 4 4
      V-Gears-Installer/include/decompiler/test/ff7_field_control_flow_test.cpp
  29. 2 2
      V-Gears-Installer/include/decompiler/test/ff7_field_disasm_all_opcodes_by_category_test.cpp
  30. 5 5
      V-Gears-Installer/include/decompiler/test/main.cpp
  31. 19 19
      V-Gears-Installer/include/decompiler/world/ff7_world_engine.h
  32. 8 8
      V-Gears-Installer/src/decompiler/control_flow.cpp
  33. 3 3
      V-Gears-Installer/src/decompiler/decompiler.cpp
  34. 6 6
      V-Gears-Installer/src/decompiler/decompiler_codegen.cpp
  35. 12 11
      V-Gears-Installer/src/decompiler/field/FieldCodeGenerator.cpp
  36. 303 280
      V-Gears-Installer/src/decompiler/field/FieldDisassembler.cpp
  37. 309 0
      V-Gears-Installer/src/decompiler/field/FieldEngine.cpp
  38. 0 1969
      V-Gears-Installer/src/decompiler/field/ff7_field_engine.cpp
  39. 207 0
      V-Gears-Installer/src/decompiler/field/instruction/FieldBackgroundInstruction.cpp
  40. 141 0
      V-Gears-Installer/src/decompiler/field/instruction/FieldCameraInstruction.cpp
  41. 124 0
      V-Gears-Installer/src/decompiler/field/instruction/FieldCondJumpInstruction.cpp
  42. 123 0
      V-Gears-Installer/src/decompiler/field/instruction/FieldControlFlowInstruction.cpp
  43. 266 0
      V-Gears-Installer/src/decompiler/field/instruction/FieldMathInstruction.cpp
  44. 145 0
      V-Gears-Installer/src/decompiler/field/instruction/FieldMediaInstruction.cpp
  45. 516 0
      V-Gears-Installer/src/decompiler/field/instruction/FieldModelInstruction.cpp
  46. 135 0
      V-Gears-Installer/src/decompiler/field/instruction/FieldModuleInstruction.cpp
  47. 26 0
      V-Gears-Installer/src/decompiler/field/instruction/FieldNoOperationInstruction.cpp
  48. 84 0
      V-Gears-Installer/src/decompiler/field/instruction/FieldPartyInstruction.cpp
  49. 38 0
      V-Gears-Installer/src/decompiler/field/instruction/FieldUncategorizedInstruction.cpp
  50. 58 0
      V-Gears-Installer/src/decompiler/field/instruction/FieldUncondJumpInstruction.cpp
  51. 74 0
      V-Gears-Installer/src/decompiler/field/instruction/FieldWalkmeshInstruction.cpp
  52. 103 0
      V-Gears-Installer/src/decompiler/field/instruction/FieldWindowInstruction.cpp
  53. 19 15
      V-Gears-Installer/src/decompiler/instruction.cpp
  54. 7 7
      V-Gears-Installer/src/decompiler/sudm.cpp
  55. 2 2
      V-Gears-Installer/src/decompiler/world/ff7_world_codegen.cpp
  56. 18 18
      V-Gears-Installer/src/decompiler/world/ff7_world_engine.cpp
  57. 14 0
      V-Gears-Installer/src/ff7DataInstaller.cpp
  58. 19 0
      V-Gears/src/data/VGearsFLevelFileSerializer.cpp
  59. 4 1
      V-Gears/src/data/VGearsLZSFLevelFile.cpp

+ 1 - 1
CMakeLists.txt

@@ -227,7 +227,7 @@ if (UNIX AND $ENV{COVERAGE}==1)
 endif()
 
 #DEBUG, no optimizations
-#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -rdynamic -O0")
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -rdynamic -O0")
 
 add_definitions(-DTIXML_USE_STL)
 add_subdirectory(lib)

+ 30 - 2
V-Gears-Installer/CMakeLists.txt

@@ -35,8 +35,22 @@ set(HEADER_FILES
     include/decompiler/unknown_opcode_exception.h
     include/decompiler/value.h
     include/decompiler/wrongtype.h
+    include/decompiler/field/instruction/FieldBackgroundInstruction.h
+    include/decompiler/field/instruction/FieldCameraInstruction.h
+    include/decompiler/field/instruction/FieldCondJumpInstruction.h
+    include/decompiler/field/instruction/FieldControlFlowInstruction.h
+    include/decompiler/field/instruction/FieldMathInstruction.h
+    include/decompiler/field/instruction/FieldMediaInstruction.h
+    include/decompiler/field/instruction/FieldModelInstruction.h
+    include/decompiler/field/instruction/FieldModuleInstruction.h
+    include/decompiler/field/instruction/FieldNoOperationInstruction.h
+    include/decompiler/field/instruction/FieldPartyInstruction.h
+    include/decompiler/field/instruction/FieldUncategorizedInstruction.h
+    include/decompiler/field/instruction/FieldUncondJumpInstruction.h
+    include/decompiler/field/instruction/FieldWalkmeshInstruction.h
+    include/decompiler/field/instruction/FieldWindowInstruction.h
     include/decompiler/field/FieldDisassembler.h
-    include/decompiler/field/ff7_field_engine.h
+    include/decompiler/field/FieldEngine.h
     include/decompiler/field/FieldCodeGenerator.h
     include/common/scummsys.h
     include/common/BinaryReader.h
@@ -64,8 +78,22 @@ set(SOURCE_FILES
     src/decompiler/simple_disassembler.cpp
     src/decompiler/unknown_opcode_exception.cpp
     src/decompiler/value.cpp
+    src/decompiler/field/instruction/FieldBackgroundInstruction.cpp
+    src/decompiler/field/instruction/FieldCameraInstruction.cpp
+    src/decompiler/field/instruction/FieldCondJumpInstruction.cpp
+    src/decompiler/field/instruction/FieldControlFlowInstruction.cpp
+    src/decompiler/field/instruction/FieldMathInstruction.cpp
+    src/decompiler/field/instruction/FieldMediaInstruction.cpp
+    src/decompiler/field/instruction/FieldModelInstruction.cpp
+    src/decompiler/field/instruction/FieldModuleInstruction.cpp
+    src/decompiler/field/instruction/FieldNoOperationInstruction.cpp
+    src/decompiler/field/instruction/FieldPartyInstruction.cpp
+    src/decompiler/field/instruction/FieldUncategorizedInstruction.cpp
+    src/decompiler/field/instruction/FieldUncondJumpInstruction.cpp
+    src/decompiler/field/instruction/FieldWalkmeshInstruction.cpp
+    src/decompiler/field/instruction/FieldWindowInstruction.cpp
     src/decompiler/field/FieldDisassembler.cpp
-    src/decompiler/field/ff7_field_engine.cpp
+    src/decompiler/field/FieldEngine.cpp
     src/decompiler/field/FieldCodeGenerator.cpp
 )
 

+ 1 - 1
V-Gears-Installer/include/decompiler/decompiler_codegen.h

@@ -305,7 +305,7 @@ protected:
      *
      * @param inst The instruction to process.
      */
-    void processInst(Function& func, InstVec& insts, const InstPtr inst);
+    void ProcessInst(Function& func, InstVec& insts, const InstPtr inst);
     void processUncondJumpInst(Function& func, InstVec& insts, const InstPtr inst);
     void processCondJumpInst(const InstPtr inst);
 

+ 5 - 5
V-Gears-Installer/include/decompiler/decompiler_engine.h

@@ -76,7 +76,7 @@ class Engine
 public:
     virtual ~Engine() = default;
 
-    virtual std::unique_ptr<Disassembler> getDisassembler(InstVec &, const std::vector<unsigned char>& )
+    virtual std::unique_ptr<Disassembler> GetDisassembler(InstVec &, const std::vector<unsigned char>& )
     {
         throw NotImplementedException();
     }
@@ -87,7 +87,7 @@ public:
 	 * @param insts Reference to the std::vector to place the Instructions in.
 	 * @return Pointer to a Disassembler for the engine.
 	 */
-	virtual std::unique_ptr<Disassembler> getDisassembler(InstVec &insts) = 0;
+	virtual std::unique_ptr<Disassembler> GetDisassembler(InstVec &insts) = 0;
 
 	/**
 	 * Retrieve the code generator for the engine.
@@ -95,14 +95,14 @@ public:
 	 * @param output The std::ostream to output the code to.
 	 * @return Pointer to a CodeGenerator for the engine.
 	 */
-    virtual std::unique_ptr<CodeGenerator> getCodeGenerator(const InstVec& insts, std::ostream &output) = 0;
+    virtual std::unique_ptr<CodeGenerator> GetCodeGenerator(const InstVec& insts, std::ostream &output) = 0;
 
 	/**
 	 * Post-processing step after CFG analysis.
 	 * @param insts Reference to the std::vector to place the Instructions in.
 	 * @param g Graph generated from the CFG analysis.
 	 */
-	virtual void postCFG(InstVec&, Graph) { }
+	virtual void PostCFG(InstVec&, Graph) { }
 
 	/**
 	 * Whether or not code flow analysis is supported for this engine.
@@ -137,7 +137,7 @@ public:
 	 *
 	 * @return True if pure grouping should be used, false if not.
 	 */
-	virtual bool usePureGrouping() const { return false; }
+	virtual bool UsePureGrouping() const { return false; }
 };
 
 #endif

+ 4 - 4
V-Gears-Installer/include/decompiler/field/FieldDisassembler.h

@@ -351,7 +351,7 @@ struct InstructionRecord{
 
 std::map<std::string, const InstructionRecord*> FieldInstructions();
 
-class FF7FieldEngine;
+class FieldEngine;
 
 class FieldDisassembler : public SimpleDisassembler{
 
@@ -364,7 +364,7 @@ class FieldDisassembler : public SimpleDisassembler{
          * @param engine[in] The engine to use to disassemble.
          * @param insts[in] The list of instructions.
          */
-        FieldDisassembler(SUDM::IScriptFormatter& formatter, FF7FieldEngine* engine, InstVec& insts);
+        FieldDisassembler(SUDM::IScriptFormatter& formatter, FieldEngine* engine, InstVec& insts);
 
         /**
          * Constructor.
@@ -375,7 +375,7 @@ class FieldDisassembler : public SimpleDisassembler{
          * @param raw_script_data[in] @todo Understand and document.
          */
         FieldDisassembler(
-          SUDM::IScriptFormatter& formatter, FF7FieldEngine* engine,
+          SUDM::IScriptFormatter& formatter, FieldEngine* engine,
           InstVec& insts, const std::vector<unsigned char>& raw_script_data
         );
 
@@ -490,7 +490,7 @@ class FieldDisassembler : public SimpleDisassembler{
         /**
          * The engine.
          */
-        FF7FieldEngine* engine_;
+        FieldEngine* engine_;
 
         /**
          * Last address of the header.

+ 400 - 0
V-Gears-Installer/include/decompiler/field/FieldEngine.h

@@ -0,0 +1,400 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+#include "decompiler/sudm.h"
+#include "decompiler/decompiler_engine.h"
+
+/**
+ * Represents the FF7 Field engine.
+ */
+class FieldEngine : public Engine{
+
+    public:
+
+        /**
+         * FieldEngine constructor.
+         *
+         * Generates a FieldEngine.
+         *
+         * @param formatter[in] The formatter to be used by the engine.
+         * @param script_name The script name.
+         */
+        FieldEngine(SUDM::IScriptFormatter& formatter, std::string script_name);
+
+        /**
+         * Copy constructor, deleted.
+         *
+         * @param engine[in] The engine to copy.
+         */
+        FieldEngine(const FieldEngine& engine) = delete;
+
+        /**
+         * Copy constructor, deleted.
+         *
+         * @param engine[in] The engine to copy.
+         */
+        FieldEngine& operator = (const FieldEngine& engine) = delete;
+
+        /**
+         * Represents an entity.
+         *
+         * An entity can be almost anything in a field map: the playable
+         * character, an NPC, an item, a line...
+         */
+        class Entity{
+
+            public:
+
+                /**
+                 * Entity constructor.
+                 *
+                 * It doesn't initialize any of the fields.
+                 */
+                Entity() = default;
+
+                /**
+                 * Entity constructor.
+                 *
+                 * Instantiates an entity with a name.
+                 *
+                 * @param name[in] Entity name.
+                 */
+                Entity(const std::string& name, size_t index);
+
+                /**
+                 * Retrieves the entity name.
+                 *
+                 * @return The entity name.
+                 */
+                std::string GetName() const;
+
+                /**
+                 * Retrieves the entity index.
+                 *
+                 * The index is the one at which appears in the original game
+                 * script.
+                 *
+                 * @return The entity index.
+                 */
+                size_t GetIndex() const;
+
+                /**
+                 * Retrieves a function.
+                 *
+                 * Retrieves the name of a function from it's index.
+                 *
+                 * @param index[in] Function index.
+                 * @return Function name.
+                 * @throws InternalDecompilerError if there is no function
+                 * with the specified index.
+                 */
+                std::string FunctionByIndex(size_t index) const;
+
+                /**
+                 * Adds a function to the engine.
+                 *
+                 * Must be added by name and index.
+                 *
+                 * @param name[in] Function name. If the entity is a line, the
+                 * name will be overridden.
+                 * @param index[in] Function index.
+                 * @todo What is a function here? An Opcode?
+                 */
+                void AddFunction(const std::string& name, size_t index);
+
+                /**
+                 * Marks the entity as a line.
+                 *
+                 * @param line[in] True to mark the entity as a line,
+                 * false to unmark it.
+                 * @param point_a[in] First point of the line. Can be null if
+                 * line is false.
+                 * @param point_b[in] Second point of the line. Can be null if
+                 * line is false.
+                 */
+                void MarkAsLine(bool line, std::vector<float> point_a, std::vector<float> point_b);
+
+                /**
+                 * Checks if the entity is a line.
+                 *
+                 * Note that an entity is not considered to be a line until a
+                 * function has been found containing the opcode LINE and
+                 * {@see MarkAsLine} has been called.
+                 *
+                 * @return true if the entity is a line.
+                 */
+                bool IsLine();
+
+                /**
+                 * Retrieves the first point of the line entity.
+                 *
+                 * If the entity is not a line, the behavior is undefined.
+                 *
+                 * @return The first point of the line entity.
+                 */
+                std::vector<float> GetLinePointA();
+
+                /**
+                 * Retrieves the second point of the line entity.
+                 *
+                 * If the entity is not a line, the behavior is undefined.
+                 *
+                 * @return The second point of the line entity.
+                 */
+                std::vector<float> GetLinePointB();
+
+
+
+            private:
+
+                /**
+                 * Entity name.
+                 */
+                std::string name_;
+
+                /**
+                 * Entity index.
+                 */
+                size_t index_;
+
+                /**
+                 * Function list.
+                 */
+                std::map<size_t, std::string> functions_;
+
+                /**
+                 * Indicates if the entity is a line.
+                 */
+                bool is_line_;
+
+                /**
+                 * The first point of a line entity.
+                 *
+                 * If the entity is not a line, it may not be initializer.
+                 */
+                std::vector<float> point_a_;
+
+                /**
+                 * The second point of a line entity.
+                 *
+                 * If the entity is not a line, it may not be initializer.
+                 */
+                std::vector<float> point_b_;
+        };
+
+        /**
+         * Retrieves the disassembler.
+         *
+         * @param insts[in] List of instructions.
+         * @param raw_script_data[in] Script data, raw format.
+         * @return Pointer to the disassembler.
+         */
+        virtual std::unique_ptr<Disassembler> GetDisassembler(
+          InstVec &insts, const std::vector<unsigned char>& raw_script_data
+        ) override;
+
+        /**
+         * Retrieves the dissasembler.
+         *
+         * @param insts[in] List of instructions.
+         * @return Pointer to the dissasembler.
+         * @todo Understand and document properly.
+         */
+        virtual std::unique_ptr<Disassembler> GetDisassembler(InstVec &insts) override;
+
+        /**
+         * Retrieves the code generator.
+         *
+         * @param insts[in] List of instructions.
+         * @param output[in] Pointer to the output (file, stream...).
+         * @return Pointer to the generator.
+         */
+        virtual std::unique_ptr<CodeGenerator> GetCodeGenerator(
+          const InstVec& insts, std::ostream &output
+        ) override;
+
+        /**
+         * Post-processing actions to apply to the scripts.
+         *
+         * It actually does nothing. CFG stands for control flow group
+         *
+         * @param insts[in] Instruction list.
+         * @param grapho[in] Code graph.
+         */
+        virtual void PostCFG(InstVec &insts, Graph g) override;
+
+        /**
+         * Indicates if instructions are purely grouped.
+         *
+         * @return True if instructions are purely grouped.
+         * @todo What is pure grouping?
+         */
+        virtual bool UsePureGrouping() const override;
+
+        /**
+         * Retrieves all entities in the map.
+         *
+         * @return A map of entities, with the name and index.
+         */
+        std::map<std::string, int> GetEntities() const;
+
+        /**
+         * Retrieves all non-line entities in the map.
+         *
+         * @return A list of non-line entities.
+         */
+        std::vector<SUDM::Field::FieldEntity> GetEntityList() const;
+
+        /**
+         * Retrieves all line entities in the map.
+         *
+         * @param A list of line entities.
+         */
+        std::vector<SUDM::Field::Line> GetLineList() const;
+
+        /**
+         * Retrieves all entities in the map.
+         *
+         * @return A map of entities, with the name and index.
+         */
+        std::map<size_t, Entity> GetEntityIndexMap() const{return entity_index_map_;}
+
+        /**
+         * Adds a function to an entity.
+         *
+         * @param entity_name Name of the entity.
+         * @param entity_index Index of the entity.
+         * @param func_name Name of the function.
+         * @param func_index Index of the function.
+         */
+        void AddEntityFunction(
+          const std::string& entity_name, size_t entity_index,
+          const std::string& func_name, size_t func_index
+        );
+
+        /**
+         * Marks an entity as a line.
+         *
+         * @param entity_index Index of the entity.
+         * @param line[in] True to mark the entity as a line, false to unmark
+         * it.
+         * @param point_a[in] First point of the line. Can be null if line is
+         * false.
+         * @param point_b[in] Second point of the line. Can be null if line is
+         * false.
+         */
+        void MarkEntityAsLine(
+            size_t entity_index, bool line, std::vector<float> point_a, std::vector<float> point_b
+        );
+
+        /**
+         * Checks if an entity has been marked as a line.
+         *
+         * @param entity_index[in] Index of the entity to check.
+         * @return True if the entity is a line. False if it isn't, or if
+         * there is no such entity.
+         */
+        bool EntityIsLine(size_t entity_index);
+
+        /**
+         * Retrieves an entity.
+         *
+         * @param index[in] Index of the entity to retrieve.
+         * @throws InternalDecompilerError if there is no entity at the
+         * specified index.
+         */
+        const Entity& EntityByIndex(size_t index) const;
+
+        /**
+         * Retrieves the scale factor for the map.
+         *
+         * @return Map scale factor.
+         */
+        float GetScaleFactor() const;
+
+        /**
+         * Retrieves the script name.
+         *
+         * @return The script name.
+         */
+        const std::string& ScriptName() const;
+
+    private:
+
+        /**
+         * Removes extraneous return statements.
+         *
+         * Usefull for scripts that only contain one one return
+         * statement.
+         *
+         * @param insts[in|out] List of instructions to proccess.
+         * Extraneous return statements will be deleted from the
+         * instructions.
+         * @param g[in] Code graph. Unused.
+         */
+        void RemoveExtraneousReturnStatements(InstVec& insts, Graph g);
+
+        /**
+         * Removes trailing infinite loops.
+         *
+         * In FF7 some scripts ends with an infinite loop to keep it
+         * alive. in VGears this isn't required, and can cause infinite
+         * loops, so they can be removed.
+         *
+         * @param insts[in|out] List of instructions to proccess. Trailing
+         * infinite loops will be deleted from the instructions.
+         * @param g[in] Code graph.
+         * @todo What is the graph used to?
+         */
+        void RemoveTrailingInfiniteLoops(InstVec& insts, Graph g);
+
+        /**
+         * Tries to detect scripts with trailing infinite loops.
+         *
+         * In FF7 some scripts ends with an infinite loop to keep it
+         * alive. in VGears this isn't required, and can cause infinite
+         * loops, so they can be removed. This function marks them, so
+         * they can be deleted with
+         * @{see FieldEngine::RemoveTrailingInfiniteLoops}.
+         */
+        void MarkInfiniteLoopGroups(InstVec& insts, Graph g);
+
+        /**
+         * The script formatter.
+         */
+        SUDM::IScriptFormatter& mFormatter;
+
+        /**
+         * The entity index map for the field.
+         */
+        std::map<size_t, Entity> entity_index_map_;
+
+        /**
+         * The map scale factor.
+         */
+        float scale_factor_ = 1.0f;
+
+        /**
+         * The script name.
+         */
+        std::string script_name_;
+};

+ 0 - 1554
V-Gears-Installer/include/decompiler/field/ff7_field_engine.h

@@ -1,1554 +0,0 @@
-/*
- * V-Gears
- * Copyright (C) 2022 V-Gears Team
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#include "decompiler/decompiler_engine.h"
-#include <string>
-#include <vector>
-#include "decompiler/sudm.h"
-
-//namespace FF7{
-
-    /**
-     * Represents the FF7 Field engine.
-     */
-    class FF7FieldEngine : public Engine{
-
-        public:
-
-            /**
-             * FF7FieldEngine constructor.
-             *
-             * Generates a FF7FieldEngine.
-             *
-             * @param formatter[in] The formatter to be used by the engine.
-             * @param scriptName The script name.
-             */
-            FF7FieldEngine(SUDM::IScriptFormatter& formatter, std::string scriptName) :
-              mFormatter(formatter), mScriptName(scriptName)
-            {setOutputStackEffect(false);}
-
-            /**
-             * Destructor.
-             */
-            FF7FieldEngine(const FF7FieldEngine&) = delete;
-
-            /**
-             * Destructor.
-             */
-            FF7FieldEngine& operator = (const FF7FieldEngine&) = delete;
-
-            /**
-             * Represents an entity.
-             *
-             * An entity can be almost anything in a field map: the playable
-             * character, an NPC, an item, a line...
-             */
-            class Entity{
-                public:
-
-                    /**
-                     * Entity constructor.
-                     *
-                     * It doesn't initialize any of the fields.
-                     */
-                    Entity() = default;
-
-                    /**
-                     * Entity constructor.
-                     *
-                     * Instantiates an entity with a name.
-                     *
-                     * @param name[in] Entity name.
-                     */
-                    Entity(const std::string& name, size_t index):
-                      mName(name), index_(index), is_line_(false)
-                    {}
-
-                    /**
-                     * Retrieves the entity name.
-                     *
-                     * @return The entity name.
-                     */
-                    std::string Name() const{return mName;}
-
-                    /**
-                     * Retrieves the entity index.
-                     *
-                     * The index is the one at which appears in the original
-                     * game script.
-                     *
-                     * @return The entity index.
-                     */
-                    size_t GetIndex() const{return index_;}
-
-                    /**
-                     * Retrieves a function.
-                     *
-                     * Retrieves the name of a function from it's index.
-                     *
-                     * @param index[in] Function index.
-                     * @return Function name.
-                     * @throws InternalDecompilerError if there is no function
-                     * with the specified index.
-                     * @todo What is a function here? An Opcode?
-                     */
-                    std::string FunctionByIndex(size_t index) const{
-                        auto it = mFunctions.find(index);
-                        if (it == std::end(mFunctions)) throw InternalDecompilerError();
-                        return it->second;
-                    }
-
-                    /**
-                     * Adds a function to the engine.
-                     *
-                     * Must be added by name and index.
-                     *
-                     * @param name[in] Function name. If the entity is a line,
-                     * the name will be overridden.
-                     * @param index[in] Function index.
-                     * @todo What is a function here? An Opcode?
-                     */
-                    void AddFunction(const std::string& name, size_t index){
-                        mFunctions[index] = name;
-                    }
-
-                    /**
-                     * Marks the entity as a line.
-                     *
-                     * @param line[in] True to mark the entity as a line,
-                     * false to unmark it.
-                     * @param point_a[in] First point of the line. Can be null
-                     * if line is false.
-                     * @param point_b[in] Second point of the line. Can be
-                     * null if line is false.
-                     */
-                    void MarkAsLine(
-                      bool line, std::vector<float> point_a, std::vector<float> point_b
-                    ){
-                        is_line_ = line;
-                        point_a_.clear();
-                        point_b_.clear();
-                        if (line){
-                            if (point_a.size() >= 3 && point_b.size() >= 3){
-                                point_a_.push_back(point_a[0]);
-                                point_a_.push_back(point_a[1]);
-                                point_a_.push_back(point_a[2]);
-                                point_b_.push_back(point_b[0]);
-                                point_b_.push_back(point_b[1]);
-                                point_b_.push_back(point_b[2]);
-                            }
-                            // TODO: Notify on else.
-                        }
-                        // TODO: These are not getting to the final script.
-                        // Maybe this can be removed?
-                        AddFunction("on_enter_line", 1);
-                        AddFunction("on_move_to_line", 2);
-                        AddFunction("on_cross_line", 3);
-                        AddFunction("on_leave_line", 4);
-                    }
-
-                    /**
-                     * Checks if the entity is a line.
-                     *
-                     * Note that an entity is not considered to be a line
-                     * until a function has been found containing the opcode
-                     * LINE and {@see MarkAsLine} has been called.
-                     *
-                     * @return true if the entity is a line.
-                     */
-                    bool IsLine(){return is_line_;}
-
-                    /**
-                     * Retrieves the first point of the line entity.
-                     *
-                     * If the entity is not a line, the behavior is undefined.
-                     *
-                     * @return The first point of the line entity.
-                     */
-                    std::vector<float> GetLinePointA(){return point_a_;}
-
-                    /**
-                     * Retrieves the second point of the line entity.
-                     *
-                     * If the entity is not a line, the behavior is undefined.
-                     *
-                     * @return The second point of the line entity.
-                     */
-                    std::vector<float> GetLinePointB(){return point_b_;}
-
-
-
-                private:
-
-                    /**
-                     * Entity name.
-                     */
-                    std::string mName;
-
-                    /**
-                     * Entity index.
-                     */
-                    size_t index_;
-
-                    /**
-                     * Function list.
-                     * @todo What is a function here? An Opcode?
-                     */
-                    std::map< size_t, std::string > mFunctions;
-
-                    /**
-                     * Indicates if the entity is a line.
-                     */
-                    bool is_line_;
-
-                    /**
-                     * The first point of a line entity.
-                     *
-                     * If the entity is not a line, it may not be initializer.
-                     */
-                    std::vector<float> point_a_;
-
-                    /**
-                     * The second point of a line entity.
-                     *
-                     * If the entity is not a line, it may not be initializer.
-                     */
-                    std::vector<float> point_b_;
-            };
-
-            /**
-             * Retrieves the dissasembler.
-             *
-             * @param insts[in] List of instructions.
-             * @param raw_script_data[in] Script data, raw format.
-             * @return Pointer to the dissasembler.
-             * @todo Understand and document properly.
-             */
-            virtual std::unique_ptr<Disassembler> getDisassembler(
-              InstVec &insts, const std::vector<unsigned char>& raw_script_data
-            ) override;
-
-            /**
-             * Retrieves the dissasembler.
-             *
-             * @param insts[in] List of instructions.
-             * @return Pointer to the dissasembler.
-             * @todo Understand and document properly.
-             */
-            virtual std::unique_ptr<Disassembler> getDisassembler(InstVec &insts) override;
-
-            /**
-             * Retrieves the code generator.
-             *
-             * @param insts[in] List of instructions.
-             * @param output[in] Pointer to the output (file, stream...).
-             * @return Pointer to the generator.
-             * @todo Understand and document properly.
-             */
-            virtual std::unique_ptr<CodeGenerator> getCodeGenerator(
-              const InstVec& insts, std::ostream &output
-            ) override;
-
-            /**
-             * Postprocessing actions to apply to the scripts.
-             *
-             * @param insts[in] Instruction list.
-             * @param g[in] Code graph.
-             * @todo Understand and document properly.
-             * @todo What is the graph used to?
-             */
-            virtual void postCFG(InstVec &insts, Graph g) override;
-
-            /**
-             * Indicates if instructions are purely grouped.
-             *
-             * @return True if instructions are purely grouped.
-             * @todo What is pure grouping?
-             */
-            virtual bool usePureGrouping() const override{return false;}
-
-            /**
-             * Retrieves all entities in the map.
-             *
-             * @return A map of entities, with the name and index.
-             */
-            std::map<std::string, int> GetEntities() const;
-
-            /**
-             * Retrieves all non-line entities in the map.
-             *
-             * @return A list of non-line entities.
-             */
-            std::vector<SUDM::Field::FieldEntity> GetEntityList() const;
-
-            /**
-             * Retrieves all line entities in the map.
-             *
-             * @param A list of line entities.
-             */
-            std::vector<SUDM::Field::Line> GetLineList() const;
-
-            /**
-             * Retrieves all entities in the map.
-             *
-             * @return A map of entities, with the name and index.
-             */
-            std::map<size_t, Entity> GetEntityIndexMap() const{return mEntityIndexMap;}
-
-            /**
-             * Adds a function to an entity.
-             *
-             * @param entity_name Name of the entity.
-             * @param entity_index Index of the entity.
-             * @param func_name Name of the function.
-             * @param func_index Index of the function.
-             */
-            void AddEntityFunction(
-              const std::string& entity_name, size_t entity_index,
-              const std::string& func_name, size_t func_index
-            );
-
-            /**
-             * Marks an entity as a line.
-             *
-             * @param entity_index Index of the entity.
-             * @param line[in] True to mark the entity as a line, false to
-             * unmark it.
-             * @param point_a[in] First point of the line. Can be null if line
-             * is false.
-             * @param point_b[in] Second point of the line. Can be null if
-             * line is false.
-             */
-            void MarkEntityAsLine(
-                size_t entity_index, bool line,
-                std::vector<float> point_a, std::vector<float> point_b
-            );
-
-            /**
-             * Checks if an entity has been marked as a line.
-             *
-             * @param entity_index[in] Index of the entity to check.
-             * @return True if the entity is a line. False if it isn't, or if
-             * there is no such entity.
-             */
-            bool EntityIsLine(size_t entity_index);
-
-            /**
-             * Retrieves an entity.
-             *
-             * @param index[in] Index of the entity to retrieve.
-             * @throws InternalDecompilerError if there is no entity at the
-             * specified index.
-             */
-            const Entity& EntityByIndex(size_t index) const{
-                auto it = mEntityIndexMap.find(index);
-                if (it == std::end(mEntityIndexMap)) throw InternalDecompilerError();
-                return it->second;
-            }
-
-            /**
-             * Retrieves the scale factor for the map.
-             *
-             * @return Map scale factor.
-             */
-            float GetScaleFactor() const {return scale_factor_;}
-
-            /**
-             * Retrieves the script name.
-             *
-             * @return The script name.
-             */
-            const std::string& ScriptName() const {return mScriptName;}
-
-        private:
-
-            /**
-             * Removes extraneous return statements.
-             *
-             * Usefull for scripts that only contain one one return
-             * statement.
-             *
-             * @param insts[in|out] List of instructions to proccess.
-             * Extraneous return statements will be deleted from the
-             * instructions.
-             * @param g[in] Code graph. Unused.
-             */
-            void RemoveExtraneousReturnStatements(InstVec& insts, Graph g);
-
-            /**
-             * Removes trailing infinite loops.
-             *
-             * In FF7 some scripts ends with an infinite loop to keep it
-             * alive. in VGears this isn't required, and can cause infinite
-             * loops, so they can be removed.
-             *
-             * @param insts[in|out] List of instructions to proccess. Trailing
-             * infinite loops will be deleted from the instructions.
-             * @param g[in] Code graph.
-             * @todo What is the graph used to?
-             */
-            void RemoveTrailingInfiniteLoops(InstVec& insts, Graph g);
-
-            /**
-             * Tries to detect scripts with trailing infinite loops.
-             *
-             * In FF7 some scripts ends with an infinite loop to keep it
-             * alive. in VGears this isn't required, and can cause infinite
-             * loops, so they can be removed. This function marks them, so
-             * they can be deleted with
-             * @{see FF7FieldEngine::RemoveTrailingInfiniteLoops}.
-             */
-            void MarkInfiniteLoopGroups(InstVec& insts, Graph g);
-
-            /**
-             * The script formatter.
-             */
-            SUDM::IScriptFormatter& mFormatter;
-
-            /**
-             * The entity index map for the field.
-             */
-            std::map<size_t, Entity> mEntityIndexMap;
-
-            /**
-             * The map scale factor.
-             */
-            float scale_factor_ = 1.0f;
-
-            /**
-             * The script name.
-             */
-            std::string mScriptName;
-    };
-
-    /**
-     * An unconditional map jump instruction.
-     */
-    class FF7UncondJumpInstruction : public UncondJumpInstruction{
-
-        public:
-
-            // TODO: Make private and add accessors.
-            /**
-             * Whether or not this is really a call to a script function.
-             */
-            bool _isCall;
-
-            /**
-             * Constructor.
-             */
-            FF7UncondJumpInstruction() : _isCall(false) {}
-
-            /**
-             * Indicates if the instruction is a function call.
-             *
-             * @return true if the instruction is a function call, false if not.
-             */
-            virtual bool isFuncCall() const;
-
-            /**
-             * Indicates if the instruction is an unconditional jump.
-             *
-             * @return true if the instruction is an unconditional jump, false
-             * if it's not.
-             */
-            virtual bool isUncondJump() const;
-
-            /**
-             * Retrieves the destination address of the jump.
-             *
-             * @return The offset (number of bytes) to jump from the beginning
-             * of the instruction.
-             */
-            virtual uint32 getDestAddress() const;
-
-            /**
-             * Processes the instruction.
-             *
-             * @param func[in] Function to process.
-             * @param stack[out] Function stack.
-             * @param engine[in] Engine.
-             * @param code_gen[in] Code generator.
-             * @todo Func and engine are unused?
-             * @todo Understand and document properly.
-             */
-            virtual void processInst(
-              Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
-            ) override;
-
-            /**
-             * Prints the instruction
-             *
-             * @param output The stram to print the instruction to.
-             * @todo Understand and document properly.
-             */
-            virtual std::ostream& print(std::ostream &output) const override;
-    };
-
-    /**
-     * A conditional map jump instruction.
-     */
-    class FF7CondJumpInstruction : public CondJumpInstruction{
-
-        public:
-
-            /**
-             * Processes a conditional jump instruction.
-             *
-             * Checks if the condition is a function or a comparison, and
-             * adds the function to the stack.
-             *
-             * @param function[in] Function to process. Unused.
-             * @param stack[out] Function stack. The Instruction will be added
-             * here.
-             * @param engine[in] Engine. Unused.
-             * @param code_gen[in] Code generator.
-             */
-            virtual void processInst(
-              Function& function, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
-            ) override;
-
-            /**
-             * Retrieves the destination address of the jump.
-             *
-             * @return The offset (number of bytes) to jump from the beginning
-             * of the instruction.
-             */
-            virtual uint32 getDestAddress() const override;
-
-            /**
-             * Prints the instruction
-             *
-             * @param output The stram to print the instruction to.
-             * @todo Understand and document properly.
-             */
-            virtual std::ostream& print(std::ostream &output) const override;
-        };
-
-    /**
-     * A script flow control instruction.
-     */
-    class FF7ControlFlowInstruction : public KernelCallInstruction{
-
-        public:
-
-            /**
-             * Create a FF7ControlFlowInstruction.
-             *
-             * @return Pointer to the newly created instruction.
-             */
-            static InstPtr Create(){return new FF7ControlFlowInstruction();}
-
-            /**
-             * Processes the instruction.
-             *
-             * @param func[in] Function to process.
-             * @param stack[out] Function stack.
-             * @param engine[in] Engine.
-             * @param code_gen[in] Code generator.
-             */
-            virtual void processInst(
-              Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
-            ) override;
-
-        private:
-
-            /**
-             * Processes a REQ command.
-             *
-             * Opcode: 0x01
-             * Short name: REQ
-             * Long name: Request remote execution (asynchronous,
-             *            non-guaranteed)
-             *
-             * Memory layout
-             *   0x01
-             *   E
-             *   P/F
-             *
-             * Arguments
-             *
-             * const UByte E: The ID of the target entity.
-             * const Bit[3] P: The priority at which we want to execute the
-             *                 remote script (high 3 bits of byte).
-             * const Bit[5] F: The ID of the specific member function of E to
-             *                 be executed (low 5 bits of byte).
-             *
-             * Requests that a remote entity executes one of its member
-             * functions at a specified priority. The request is asynchronous
-             * and returns immediately without waiting for the remote
-             * execution to start or finish. If the specified priority is
-             * already busy executing, the request will fail silently.
-             *
-             * @param codegen[in|out] Code generator. Output lines are
-             * appended to it.
-             * @param engine[in] The engine instance to fetch entities.
-             */
-            void processREQ(CodeGenerator* code_gen, const FF7FieldEngine& engine);
-
-            /**
-             * Processes a REQSW command.
-             *
-             * Opcode: 0x02
-             * Short name: REQSW
-             * Long name: Request remote execution (asynchronous execution,
-             *            guaranteed)
-             *
-             * Memory layout
-             *   0x02
-             *   E
-             *   P/F
-             *
-             * Arguments
-             *
-             * const UByte E: The ID of the target entity.
-             * const Bit[3] P: The priority at which we want to execute the
-             *                 remote script (high 3 bits of byte).
-             * const Bit[5] F: The ID of the specific member function of E to
-             *                 be executed (low 5 bits of byte).
-             *
-             * Requests that a remote entity executes one of its member
-             * functions at a specified priority. If the specified priority is
-             * already busy executing, the request will block until it becomes
-             * available and only then return. The remote execution is still
-             * carried out asynchronously, with no notification of completion.
-             *
-             * @param codegen[in|out] Code generator. Output lines are
-             * appended to it.
-             * @param engine[in] The engine instance to fetch entities.
-             */
-            void processREQSW(CodeGenerator* code_gen, const FF7FieldEngine& engine);
-
-            /**
-             * Processes a REQEW command.
-             *
-             * Opcode: 0x03
-             * Short name: REQEW
-             * Long name: Request remote execution (synchronous, guaranteed)
-             *
-             * Memory layout
-             *   0x03
-             *   E
-             *   P/F
-             *
-             * Arguments
-             *
-             * const UByte E: The ID of the target entity.
-             * const Bit[3] P: The priority at which we want to execute the
-             *                 remote script (high 3 bits of byte).
-             * const Bit[5] F: The ID of the specific member function of E to
-             *                 be executed (low 5 bits of byte).
-             *
-             * Requests that a remote entity executes one of its member
-             * functions at a specified priority. The request will block until
-             * remote execution has finished before returning.
-             *
-             * @param codegen[in|out] Code generator. Output lines are
-             * appended to it.
-             * @param engine[in] The engine instance to fetch entities.
-             */
-            void processREQEW(CodeGenerator* code_gen, const FF7FieldEngine& engine);
-
-            /**
-             * Processes a RETTO command.
-             *
-             * Opcode: 0x07
-             * Short name: RETTO
-             * Long name: Return To
-             *
-             * Memory layout
-             *   0x07
-             *   P/F
-             *
-             * Arguments
-             *   const Bit[3] P: The priority at which we want to execute the
-             *                   remote script (high 3 bits of byte).
-             *   const Bit[5] F: The ID of the specific member function of the
-             *                   current entity to be executed to (low 5 bits
-             *                   of byte).
-             *
-             * Stops the active script loop for this entity and also any
-             * script loops (except the main) that are queuing to be executed
-             * after the current script. This is essentially the same as
-             * adding a RET onto each of the active / queued scripts next
-             * execution position and returning the current op index to index
-             * for each script. Then the script control is passed to the
-             * script F within the current entity with the priority P.
-             *
-             * @param codegen[in|out] Code generator. Output lines are
-             * appended to it.
-             */
-            void processRETTO(CodeGenerator* code_gen);
-
-            /**
-             * Processes a WAIT command.
-             *
-             * Opcode: 0x24
-             * Short name: WAIT
-             * Long name: Wait
-             *
-             * Memory layout
-             *   0x24
-             *   A
-             *
-             * Arguments
-             *   const UShort A: Amount (number of frames) to wait.
-             *
-             * Pauses current script execution for a specific amount of time.
-             * Rather than a specific time value in milliseconds/seconds,
-             * the amount specifies the number of frames that must be drawn
-             * before execution resumes. Since the game runs at 30fps,
-             * WAIT(0x1E) (or WAIT(30) in decimal) will pause script execution
-             * for 1 second, WAIT(0x96) will pause for 5 seconds, and so on.
-             *
-             * @param codegen[in|out] Code generator. Output lines are
-             * appended to it.
-             */
-            void processWAIT(CodeGenerator* code_gen);
-    };
-
-    /**
-     * A module instruction.
-     */
-    class FF7ModuleInstruction : public KernelCallInstruction{
-
-        public:
-
-            /**
-             * Processes the instruction.
-             *
-             * @param func[in] Function to process.
-             * @param stack[out] Function stack.
-             * @param engine[in] Engine. Unused.
-             * @param code_gen[in] Code generator.
-             */
-            virtual void processInst(
-              Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
-            ) override;
-
-        private:
-
-            /**
-             * Processes a BATTLE opcode.
-             *
-             * Opcode: 0x70
-             * Short name: BATTLE
-             * Long name: Start battle
-             *
-             * Memory layout
-             *   0x70
-             *   B
-             *   N
-             *   N
-             *
-             * Arguments
-             *   const UByte B: Bank (16-bit) to retrieve the address of the
-             *                  battle ID, or zero if it is given as a literal
-             *                  value.
-             *   const UWord N: Battle ID, or address to find ID if B is
-             *                  non-zero.
-             *
-             * This launches the battle module with whatever battle number is
-             * used in the argument, or the value retrieved from memory location
-             * N if B is non-zero. Battle 1, 2, and 999 (0x03E7) are debug
-             * battles.
-             *
-             * @param codegen[in|out] Code generator. Output lines are appended
-             * to it.
-             */
-            void processBATTLE(CodeGenerator* code_gen);
-
-            /**
-             * Processes a BTLON opcode.
-             *
-             * Opcode: 0x71
-             * Short name: BTLON
-             * Long name: Battle switch
-             *
-             * Memory layout
-             *   0x71
-             *   S
-             *
-             * Arguments
-             *   const UByte S: Switch battles on/off (0/1, respectively).
-             *
-             * Turns random encounters on or off for this field. Note that if
-             * a field does not have any Encounter Data set in its field file,
-             * battles will not occur regardless of the argument passed with
-             * this opcode.
-             *
-             * @param codegen[in|out] Code generator. Output lines are
-             * appended to it.
-             */
-            void processBTLON(CodeGenerator* code_gen);
-
-            /**
-             * Processes a MAPJUMP opcode.
-             *
-             * Opcode: 0x60
-             * Short name: BTLON
-             * Long name: Change Field
-             *
-             * Memory layout
-             *   0x60
-             *   I
-             *   I
-             *   X
-             *   X
-             *   Y
-             *   Y
-             *   Z
-             *   Z
-             *   D
-             *
-             * Arguments
-             *   const UShort I: Field ID of the map to jump to.
-             *   const Short X: X-coordinate of the player on the next field.
-             *   const Short Y: Y-coordinate of the player on the next field.
-             *   const Short Z: Z-coordinate of the player on the next field.
-             *   const UByte D: Direction the character will be facing on the
-             *                  next field, in the standard game format.
-             *
-             * Switches fields to the one indicated by I, and places the
-             * character at the coordinates and direction specified. This is
-             * an alternative to using a gateway, and can complement their
-             * usage as it allows for more than 12 gateways by simulating
-             * their behavior through a LINE which, when crossed, executes a
-             * MAPJUMP.
-             *
-             * @param codegen[in|out] Code generator. Output lines are
-             * appended to it.
-             * @param func[in] Function
-             * @todo What is func for?
-             */
-            void processMAPJUMP(CodeGenerator* code_gen, Function& func);
-    };
-
-    /**
-     * A math instruction.
-     */
-    class FF7MathInstruction : public StoreInstruction{
-
-        public:
-
-            /**
-             * Processes the instruction.
-             *
-             * @param func[in] Function to process.
-             * @param stack[out] Function stack.
-             * @param engine[in] Engine. Unused.
-             * @param code_gen[in] Code generator.
-             */
-            virtual void processInst(
-              Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
-            ) override;
-
-        private:
-
-            void processSaturatedPLUS(CodeGenerator* code_gen);
-            void processSaturatedPLUS2(CodeGenerator* code_gen);
-            void processSaturatedMINUS(CodeGenerator* code_gen);
-            void processSaturatedMINUS2(CodeGenerator* code_gen);
-            void processSaturatedINC(CodeGenerator* code_gen);
-            void processSaturatedINC2(CodeGenerator* code_gen);
-            void processSaturatedDEC(CodeGenerator* code_gen);
-            void processSaturatedDEC2(CodeGenerator* code_gen);
-            void processRDMSD(CodeGenerator* code_gen);
-            void processSETBYTE_SETWORD(CodeGenerator* code_gen);
-
-            /**
-             * Processes a BITON opcode.
-             *
-             * Opcode: 0x82
-             * Short name: BITON
-             * Long name: Set Bit
-             *
-             * Memory layout (4 bytes)
-             * |0x82|D/S|A|B|
-             *
-             * Arguments
-             * - const Bit[4] D: Destination bank.
-             * - const Bit[4] S: Source bank.
-             * - const UByte A: Destination address.
-             * - const UByte Bit: The number of the bit to turn on.
-             *
-             * Sets the nth bit in the "A" location, where n is a number
-             * between 0-7 supplied in B. A value of zero in B will set the
-             * least significant bit. If the Source Bank is 0 then the bit to
-             * be set is taken from "Bit". If the Source Bank is an 8 bit
-             * bank, then the bit is the address in that bank where the
-             * operand is.
-             *
-             * @param code_gen[in|out] Code generator. Output lines are
-             * appended to it.
-             */
-            void processBITON(CodeGenerator* code_gen);
-
-            /**
-             * Processes a BITON opcode.
-             *
-             * Opcode: 0x83
-             * Short name: BITOFF
-             * Long name: Reset Bit
-             *
-             * Memory layout (4 bytes)
-             * |0x83|D/S|A|B|
-             *
-             * Arguments
-             * - const Bit[4] D: Destination bank.
-             * - const Bit[4] S: Source bank.
-             * - const UByte A: Destination address.
-             * - const UByte Bit: The number of the bit to turn off.
-             *
-             * Sets the nth bit in the "A" location, where n is a number
-             * between 0-7 supplied in B. A value of zero in B will reset the
-             * least significant bit. If the Source Bank is 0 then the bit to
-             * be set is taken from "Bit". If the Source Bank is an 8 bit
-             * bank, then the bit is the address in that bank where the
-             * operand is.
-             *
-             * @param code_gen[in|out] Code generator. Output lines are
-             * appended to it.
-             */
-            void processBITOFF(CodeGenerator* code_gen);
-            void processPLUSx_MINUSx(CodeGenerator* code_gen, const std::string& op);
-            void processINCx_DECx(CodeGenerator* code_gen, const std::string& op);
-            void processRANDOM(CodeGenerator* code_gen);
-    };
-
-    /**
-     * A window instruction.
-     */
-    class FF7WindowInstruction : public KernelCallInstruction{
-
-        public:
-
-            /**
-             * Processes the instruction.
-             *
-             * @param func[in] Function to process.
-             * @param stack[out] Function stack.
-             * @param engine[in] Engine.
-             * @param code_gen[in] Code generator.
-             */
-            virtual void processInst(
-              Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
-            ) override;
-
-        private:
-
-            void processMESSAGE(CodeGenerator* code_gen, const std::string& script_name);
-            void processMPNAM(CodeGenerator* code_gen);
-            void processMENU2(CodeGenerator* code_gen);
-            void processWINDOW(CodeGenerator* code_gen);
-            void processWCLSE(CodeGenerator* code_gen);
-    };
-
-    /**
-     * A party instruction
-     */
-    class FF7PartyInstruction : public KernelCallInstruction{
-
-        public:
-
-            /**
-             * Processes the instruction.
-             *
-             * @param func[in] Function to process.
-             * @param stack[out] Function stack.
-             * @param engine[in] Engine. Unused
-             * @param code_gen[in] Code generator.
-             */
-            virtual void processInst(
-              Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
-            ) override;
-
-        private:
-
-            void processSTITM(CodeGenerator* code_gen);
-            void processPRTYE(CodeGenerator* code_gen);
-    };
-
-    /**
-     * A model instruction.
-     */
-    class FF7ModelInstruction : public KernelCallInstruction{
-
-        public:
-
-            /**
-             * Processes the instruction.
-             *
-             * @param func[in] Function to process.
-             * @param stack[out] Function stack.
-             * @param engine[in] Engine.
-             * @param code_gen[in] Code generator.
-             */
-            virtual void processInst(
-              Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
-            ) override;
-
-        private:
-
-            /**
-             * Processes a JOIN opcode.
-             *
-             * Opcode: 0x08
-             * Short name: JOIN
-             * Long name: Party Field Join
-             * Memory layout (2 bytes)
-             * |0x08|S|
-             *
-             * Arguments
-             * - const UByte S: Speed that the characters join back together.
-             *
-             * Causes seperated party characters that have previously been
-             * SPLIT onto the field, to be joined back together again; that
-             * is, only the party leader becomes visible on the field. This
-             * should be called if a previous SPLIT has completed (the party
-             * members have finished speaking, or performing their actions,
-             * for example). As with SPLIT, the speed of the join is
-             * specified, from a scale of 1 (almost instant) to FF (very slow
-             * walk), and must be non-zero. In contrast to most MOVE related
-             * op codes, the speed is this setting is actually the total
-             * number of frames required. Depending on the distance from the
-             * player character and the number of frames required, the entity
-             * plays a run or walk animation. Also, all characters take the
-             * same time irrespective of distance. Calling JOIN without having
-             * previously SPLIT the characters will cause the party members to
-             * appear at the walkmesh origin and attempt to JOIN from there.
-             * This is not normally the required behaviour and should be
-             * avoided.
-             *
-             * @param code_gen The code generator.
-             */
-            void processJOIN(CodeGenerator* code_gen);
-
-            /**
-             * Processes a SPLIT opcode.
-             *
-             * Opcode: 0x09
-             * Short name: SPLIT
-             * Long name: Party Field Split
-             *
-             * Memory layout (15 bytes)
-             * |0x20|B1/B2|B3/B4|B5/B6|XA|XA|YA|YA|DA|XB|XB|YB|YB|DB|S|
-             *
-             * Arguments
-             * - const Bit[4] B1: Bank for XA, or zero if XA is specified as a
-             * literal value.
-             * - const Bit[4] B2: Bank for YA, or zero if YA is specified as a
-             * literal value.
-             * - const Bit[4] B3: Bank for DA, or zero if DA is specified as a
-             * literal value.
-             * - const Bit[4] B4: Bank for XB, or zero if XB is specified as a
-             * literal value.
-             * - const Bit[4] B5: Bank for YB, or zero if YB is specified as a
-             * literal value.
-             * - const Bit[4] B6: Bank for DB, or zero if DB is specified as a
-             * literal value.
-             * - const Short XA: X-coordinate of the second character in the
-             * party after the split, or address for the value if B1 is
-             * non-zero.
-             * - const Short YA: Y-coordinate of the second character in the
-             * party after the split, or address for the value if B2 is
-             * non-zero.
-             * - const UByte DA: Direction the second character faces after the
-             * split, or address for the value if B3 is non-zero.
-             * - const Short XB: X-coordinate of the third character in the
-             * party after the split, or address for the value if B4 is
-             * non-zero.
-             * - const Short YB: Y-coordinate of the third character in the
-             * party after the split, or address for the value if B5 is
-             * non-zero.
-             * - const UByte DB: Direction the third character faces after the
-             * split, or address for the value if B6 is non-zero.
-             * - const UByte S: Speed that the characters split.
-             *
-             * Causes the common 'split effect' whereby the second and third
-             * characters in the current party 'come out' from the party
-             * leader. That is, they become visible in the field, starting
-             * from the center of the party leader, and move out to the
-             * coordinates specified in the argument list. This is commonly
-             * used when the other characters in the current party have an
-             * action or dialog to perform and must be individually visible in
-             * the field. As well as specifying final coordinates for the two
-             * other party characters, the directions each character faces
-             * after the split are specified as a byte, using the common
-             * direction values found throughout the game. Speed is also given
-             * and is used to specify the rate at which the characters leave
-             * the party leader, using a scale from 1 (almost instant) to FF
-             * (extremely slow walk); this must be non-zero. In contrast to
-             * most MOVE related op codes, the speed is this setting is
-             * actually the total number of frames required. Depending on the
-             * distance from the player character and the number of frames
-             * required, the entity plays a run or walk animation. Also, all
-             * characters take the same time irrespective of distance.
-             *
-             * @param code_gen The code generator.
-             */
-            void processSPLIT(CodeGenerator* code_gen);
-            void processTLKON(CodeGenerator* code_gen, const std::string& entity);
-            void processPC(CodeGenerator* code_gen, const std::string& entity);
-            void processCHAR(CodeGenerator* code_gen, const std::string& entity);
-            void processDFANM(CodeGenerator* code_gen, const std::string& entity, int char_id);
-            void processANIME1(CodeGenerator* code_gen, const std::string& entity, int char_id);
-            void processVISI(CodeGenerator* code_gen, const std::string& entity);
-            void processXYZI(CodeGenerator* code_gen, const std::string& entity);
-            void processMOVE(CodeGenerator* code_gen, const std::string& entity);
-            void processMSPED(CodeGenerator* code_gen, const std::string& entity);
-            void processDIR(CodeGenerator* code_gen, const std::string& entity);
-            void processTURNGEN(CodeGenerator* code_gen, const std::string& entity);
-            void processGETAI(CodeGenerator* code_gen, const FF7FieldEngine& engine);
-            void processANIM_2(CodeGenerator* code_gen, const std::string& entity, int char_id);
-            void processCANIM2(CodeGenerator* code_gen, const std::string& entity, int char_id);
-            void processCANM_2(CodeGenerator* code_gen, const std::string& entity, int char_id);
-            void processCC(CodeGenerator* code_gen, const FF7FieldEngine& engine);
-
-            /**
-             * Processes a JUMP opcode.
-             *
-             * Opcode: 0xC0
-             * Short name: JUMP
-             * Long name: Jump
-             *
-             * Memory layout (7 bytes)
-             * |0xC2|B1/B2|B3/B4|X|Y|I|Steps|
-             *
-             * Arguments
-             * - const Bit[4] B1: Bank to retrieve X-coordinate, or zero if
-             * specifying X as a literal value.
-             * - const Bit[4] B2: Bank to retrieve Y-coordinate, or zero if
-             * specifying Y as a literal value.
-             * - const Bit[4] B3: Bank to retrieve triangle ID, or zero if
-             * specifying Z as a literal value.
-             * - const Bit[4] B4: Bank to retrieve jump height, or zero if
-             * specifying H as a literal value.
-             * - const Short X: X-coordinate of the target to jump to, or
-             * lower byte specifying address if B1 is non-zero.
-             * - const Short Y: Y-coordinate of the target to jump to, or
-             * lower byte specifying address if B2 is non-zero.
-             * - const Short I: Triangle ID of the target to jump to, or
-             * lower byte specifying address if B3 is non-zero.
-             * - const UShort Steps: Steps in jump. Must be non-zero if a
-             * literal value. Alternatively, lower byte specifies address if
-             * B4 is non-zero.
-             *
-             * Causes the character to jump to the specified point and
-             * triangle ID, with the jump curve peaking at a height which is
-             * increased by using a larger value for the H argument. In
-             * addition, the larger the number, the longer the jump will take
-             * to complete. A "normal" value is around 0x15, 0x01 is fast and
-             * instantaneous; the argument must not be zero or the game will
-             * crash. Whilst this is an unsigned two-byte number, a large
-             * value (beyond around 0x60) will not only cause a vast jump
-             * height, but also cause the screen to scroll erratically (the
-             * larger the number, the more erratic).
-             * Main update function go through all entity with JUMP state and
-             * if stage is 0 it calculates final Z point according to triangle
-             * id. It sets current coords as start coords. The main thing this
-             * function does is set B coefficient for later calculation. It
-             * defines as follows:
-             *   B = (Z_final - Z_start) / steps - steps * 1.45;
-             * Then it set current step to 0 and stage to 1. On next update
-             * other part of function works. It's calculate real position.
-             * First it increment current step number. Then it calculate X and
-             * Y. They change linear so nothing interesting here. The Z
-             * calculation is as follows:
-             *   Z_current = - step^2 * 1.45 + step * B + Z_start;
-             * If current substep equal number of steps then we set current
-             * triangle to final triangle and set stage to 2. Which finalizes
-             * the routine on next opcode call. Neither animation nor sound is
-             * specified in this opcode. An animation is played by using an
-             * animation opcode such as DFANM, and a SOUND played, before the
-             * jump.
-             *
-             * @param code_gen[in] The code generator.
-             * @param entity[in] The name of the entity.
-             */
-            void processJUMP(CodeGenerator* code_gen, const std::string& entity);
-
-            /**
-             * Processes a AXYZI opcode
-             *
-             * Opcode: 0xC1
-             * Short name: AXYZI
-             * Long name: Entity Get Position
-             *
-             * Memory layout (8 bytes)
-             * |0xC1|B1/B2|B3/B4|A|X|Y|Z|I|
-             *
-             * Arguments
-             * - const Bit[4] B1: Bank to store X.
-             * - const Bit[4] B2: Bank to store Y.
-             * - const Bit[4] B3: Bank to store Z.
-             * - const Bit[4] B4: Bank to store I.
-             * - const UByte A: Entity ID whose field object will have its
-             * position retrieved from.
-             * - const UByte X: Address to store the X-coordinate.
-             * - const UByte Y: Address to store the Y-coordinate.
-             * - const UByte Z: Address to store the Z-coordinate.
-             * - const UByte I: Address to store the ID of the walkmesh
-             * triangle the object is standing on.
-             *
-             * Retrieves the coordinates of the field object that the entity,
-             * whose ID specified in A, is associated with. This opcode uses
-             * an entity ID, not a field object offset; as such, if an entity
-             * ID is given that does not have a field object, this opcode will
-             * store zero in each of the four address specified.
-             */
-            void processAXYZI(CodeGenerator* code_gen);
-
-            /**
-             * Processes a LADER opcode.
-             *
-             * Opcode: 0xC2
-             * Short name: LADER
-             * Long name: Ladder
-             *
-             * Memory layout (15 bytes)
-             * |0xC2|B1/B2|B3/B4|X|X|Y|Y|Z|Z|I|I|K|A|D|S|
-             *
-             * Arguments
-             * - const Bit[4] B1: Bank to retrieve X-coordinate, or zero if X
-             * is specified as a literal value.
-             * - const Bit[4] B2: Bank to retrieve Y-coordinate, or zero if Y
-             * is specified as a literal value.
-             * - const Bit[4] B3: Bank to retrieve Z-coordinate, or zero if Z
-             * is specified as a literal value.
-             * - const Bit[4] B4: Bank to retrieve ID, or zero if I is
-             * specified as a literal value.
-             * - const Short X: X-coordinate of the end of the ladder, or
-             * address to find X-coordinate if B1 is non-zero.
-             * - const Short Y: Y-coordinate of the end of the ladder, or
-             * address to find Y-coordinate if B2 is non-zero.
-             * - const Short Z: Z-coordinate of the end of the ladder, or
-             * address to find Z-coordinate if B3 is non-zero.
-             * - const UShort I: ID of the walkmesh triangle found at the end
-             * of the ladder, or address to find ID if B4 is non-zero.
-             * - const UByte K: The keys used to move the character on the
-             * ladder.
-             * - const UByte A: Animation ID for the field object's movement
-             * animation.
-             * - const UByte D: Direction the character faces when climbing
-             * the ladder.
-             * - const UByte S: Speed of the animation whilst climbing the
-             * ladder.
-             *
-             * Causes the character to climb a ladder; that is, switching from
-             * standard walkmesh movement, to climbing along a line connecting
-             * two points on the walkmesh. If B1, B2, B3 or B4 is non-zero,
-             * then the value for that particular component is taken from
-             * memory using the corresponding bank and address specified,
-             * rather than as a literal value. Both retrieved values and
-             * literals can be used for different components. If using X, Y, Z
-             * or I as addresses, the lower byte should hold the address
-             * whilst the higher byte should be zero. The coordinates specify
-             * the end-point of the ladder; the current position of the
-             * character is used as the start point. The ID of the walkmesh
-             * triangle must be specified; this is the triangle the character
-             * will step onto after reaching the end point of the ladder. The
-             * K value specifies the keys used to move the character across
-             * the ladder; keys outside the range found in the table will
-             * cause unpredictable behaviour. The animation ID specifies an
-             * offset into the field object's animation list; this animation
-             * is played at the speed specified by S whilst the character
-             * climbs. Finally, the D argument is a direction value in the
-             * game's standard direction format, which orients the character
-             * on the ladder. This opcode is used as part of the character's
-             * entity, rather than in a seperate entity, as with a LINE. A
-             * LINE is used to set the start point of the ladder on the
-             * walkmesh. When this LINE is crossed by the player, a script in
-             * the LINE then uses a PREQ (or one of its variants), calling the
-             * script in the party leader that defines the LADER, causing the
-             * character to switch to 'climbing mode'. To set up a two-way
-             * ladder, two LINEs are used at either end, with different values
-             * for the LADER arguments, such as differing end points. If this
-             * opcode is used as part of a non-playable character entity, the
-             * NPC object will automatically climb from the start to the end
-             * point without need for player interaction.
-             *
-             * @param code_gen[in] The code generator.
-             * @param entity[in] The name of the entity.
-             */
-            void processLADER(CodeGenerator* code_gen, const std::string& entity);
-
-            void processSOLID(CodeGenerator* code_gen, const std::string& entity);
-
-            /**
-             * Processes an OFST opcode.
-             *
-             * Opcode: 0xC3
-             * Short name: OFST
-             * Long name: Offset Object
-             *
-             * Memory layout (8 bytes)
-             * |0xC3|B1/B2|B3/B4|T|X|Y|Z|S|
-             *
-             * Arguments:
-             * - const Bit[4] B1: Bank to retrieve X offset, or zero if X is
-             * specified as a literal.
-             * - const Bit[4] B2: Bank to retrieve Y offset, or zero if Y is
-             * specified as a literal.
-             * - const Bit[4] B3: Bank to retrieve Z offset, or zero if Z is
-             * specified as a literal.
-             * - const Bit[4] B4: Bank to retrieve speed, or zero if S is
-             * specified as a literal.
-             * - const UByte T: Type of movement.
-             * - const Short X: X offset amount, relative to current position,
-             * or address to find X offset, if B1 is non-zero.
-             * - const Short Y: Y offset amount, relative to current position,
-             * or address to find Y offset, if B2 is non-zero.
-             * - const Short Z: Z offset amount, relative to current position,
-             * or address to find Z offset, if B3 is non-zero.
-             * - const UShort S: Speed of the offset movement, if type is
-             * non-zero, or address to find speed, if B4 is non-zero.
-             *
-             * Offsets the field object, belonging to the entity whose script
-             * this opcode resides in, by a certain amount. After being
-             * offset, the character continues to be constrained in movement
-             * as defined by the walkmesh's shape, but at a certain distance
-             * away from the normal walkmesh position. Other field objects are
-             * unaffected, and their position or movements are maintained on
-             * the walkmesh's original position. If B1, B2, B3 or B4 is
-             * non-zero, then the value for that particular component is taken
-             * from memory using the corresponding bank and address specified,
-             * rather than as a literal value. Both retrieved values and
-             * literals can be used for different components. If using T, X, Y
-             * or S as addresses, the lower byte should hold the address
-             * whilst the higher byte should be zero. The amount to offset is
-             * specified relative to the current position. If Type is
-             * specified, the object moves gradually from its current point to
-             * the offset position; this can be used to simulate movements
-             * such as elevators. Any type outside the range in the table will
-             * cause the offset not to occur. If the object is set to move
-             * gradually, then the speed of offset can be set; the greater the
-             * number, the slower the object moves to its target offset.
-             * Script execution may also be halted until the gradual offset
-             * has been completed. For this, see OFSTW.
-             *
-             * @param codegen[in] The code generator.
-             * @param entity[in] The entity name.
-             */
-            void processOFST(CodeGenerator* codegen, const std::string& entity);
-    };
-
-    /**
-     * A walkmesh instruction.
-     */
-    class FF7WalkmeshInstruction : public KernelCallInstruction{
-
-        public:
-
-            /**
-             * Processes the instruction.
-             *
-             * @param func[in] Function to process.
-             * @param stack[out] Function stack.
-             * @param engine[in] Engine. Unused.
-             * @param code_gen[in] Code generator.
-             */
-            virtual void processInst(
-              Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
-            ) override;
-
-        private:
-
-            void processUC(CodeGenerator* code_gen);
-
-            /**
-             * Processes a LINE opcode.
-             *
-             * Opcode: 0xD0
-             * Short name: LINE
-             * Long name: Line definition
-             *
-             * Memory layout (7 bytes)
-             * |0xD0|XA|YA|ZA|XB|YB|ZB|
-             *
-             * Arguments:
-             * - const Short XA: X-coordinate of the first point of the line.
-             * - const Short YA: Y-coordinate of the first point of the line.
-             * - const Short ZA: Z-coordinate of the first point of the line.
-             * - const Short XB: X-coordinate of the second point of the line.
-             * - const Short YB: Y-coordinate of the second point of the line.
-             * - const Short ZB: Z-coordinate of the second point of the line.
-             *
-             * Defines a line on the walkmesh that, when crossed by a playable
-             * character, causes one of the entity's scripts to be executed.
-             * These are similar to the triggers in Section 8. All the lines
-             * in the current field can be turned on or off by using the LINON
-             * opcode.
-             *
-             * There are generally 6 scripts (other than the init and main) if
-             * the entity is a LINE.
-             * - script index 2 -> S1 - [OK].
-             * - script index 3 -> S2 - Move.
-             * - script index 4 -> S3 - Move.
-             * - script index 5 -> S4 - Go.
-             * - script index 6 -> S5 - Go 1x.
-             * - script index 7 -> S6 - Go away.
-             *
-             * @param code_gen The code generator.
-             * @param entity[in] The entity name.
-             */
-            void processLINE(CodeGenerator* code_gen, const std::string& entity);
-    };
-
-    /**
-     * A background instruction.
-     */
-    class FF7BackgroundInstruction : public KernelCallInstruction{
-
-        public:
-
-            /**
-             * Processes the instruction.
-             *
-             * @param func[in] Function to process.
-             * @param stack[out] Function stack.
-             * @param engine[in] Engine. Unused
-             * @param code_gen[in] Code generator.
-             */
-            virtual void processInst(
-              Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
-            ) override;
-
-        private:
-
-            void processBGON(CodeGenerator* code_gen);
-            void processBGOFF(CodeGenerator* code_gen);
-            void processBGCLR(CodeGenerator* code_gen);
-            void processSTPAL(CodeGenerator* code_gen);
-            void processLDPAL(CodeGenerator* code_gen);
-            void processCPPAL(CodeGenerator* code_gen);
-            void processADPAL(CodeGenerator* code_gen);
-            void processMPPAL2(CodeGenerator* code_gen);
-            void processSTPLS(CodeGenerator* code_gen);
-            void processLDPLS(CodeGenerator* code_gen);
-    };
-
-    /**
-     * A camera instruction.
-     */
-    class FF7CameraInstruction : public KernelCallInstruction{
-
-        public:
-
-            /**
-             * Processes the instruction.
-             *
-             * @param func[in] Function to process.
-             * @param stack[out] Function stack.
-             * @param engine[in] Engine. Unused
-             * @param code_gen[in] Code generator.
-             */
-            virtual void processInst(
-              Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
-            ) override;
-
-        private:
-
-            void processNFADE(CodeGenerator* code_gen);
-            void processSCR2D(CodeGenerator* code_gen);
-            void processSCR2DC(CodeGenerator* code_gen);
-            void processFADE(CodeGenerator* code_gen);
-    };
-
-    /**
-     * An audio or video (or both) instruction.
-     */
-    class FF7AudioVideoInstruction : public KernelCallInstruction{
-
-        public:
-
-            /**
-             * Processes the instruction.
-             *
-             * @param func[in] Function to process.
-             * @param stack[out] Function stack.
-             * @param engine[in] Engine. Unused
-             * @param code_gen[in] Code generator.
-             */
-            virtual void processInst(
-              Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
-            ) override;
-
-        private:
-
-            void processAKAO2(CodeGenerator* code_gen);
-            void processMUSIC(CodeGenerator* code_gen);
-            void processSOUND(CodeGenerator* code_gen);
-            void processAKAO(CodeGenerator* code_gen);
-            void processMULCK(CodeGenerator* code_gen);
-            void processPMVIE(CodeGenerator* code_gen);
-            void processMOVIE(CodeGenerator* code_gen);
-            void processMVIEF(CodeGenerator* code_gen);
-    };
-
-    /**
-     * An instructions that doesn't fall in any other category.
-     */
-    class FF7UncategorizedInstruction : public KernelCallInstruction{
-
-        public:
-
-            /**
-             * Processes the instruction.
-             *
-             * @param func[in] Function to process.
-             * @param stack[out] Function stack.
-             * @param engine[in] Engine. Unused.
-             * @param code_gen[in] Code generator.
-             */
-            virtual void processInst(
-              Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
-            ) override;
-    };
-
-    /**
-     * An instruction that does nothing.
-     */
-    class FF7NoOperationInstruction : public Instruction{
-
-        public:
-
-            /**
-             * Generates a instruction that does nothing.
-             *
-             * @return The generated instruction.
-             */
-            static InstPtr Create(){return new FF7NoOperationInstruction();}
-
-            /**
-             * Processes the instruction.
-             *
-             * It doesn't do anything.
-             *
-             * @param func[in] Function to process. Unused.
-             * @param stack[out] Function stack. Unused.
-             * @param engine[in] Engine. Unused.
-             * @param code_gen[in] Code generator. Unused.
-             */
-            virtual void processInst(
-              Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
-            ) override;
-    };
-//}

+ 54 - 0
V-Gears-Installer/include/decompiler/field/instruction/FieldBackgroundInstruction.h

@@ -0,0 +1,54 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "decompiler/decompiler_engine.h"
+
+/**
+ * A background instruction.
+ */
+class FieldBackgroundInstruction : public KernelCallInstruction{
+
+    public:
+
+        /**
+         * Processes the instruction.
+         *
+         * @param func[in] Function to process.
+         * @param stack[out] Function stack.
+         * @param engine[in] Engine. Unused
+         * @param code_gen[in|out] Code generator.
+         */
+        virtual void ProcessInst(
+          Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
+        ) override;
+
+    private:
+
+        void ProcessBGON(CodeGenerator* code_gen);
+        void ProcessBGOFF(CodeGenerator* code_gen);
+        void ProcessBGCLR(CodeGenerator* code_gen);
+        void ProcessSTPAL(CodeGenerator* code_gen);
+        void ProcessLDPAL(CodeGenerator* code_gen);
+        void ProcessCPPAL(CodeGenerator* code_gen);
+        void ProcessADPAL(CodeGenerator* code_gen);
+        void ProcessMPPAL2(CodeGenerator* code_gen);
+        void ProcessSTPLS(CodeGenerator* code_gen);
+        void ProcessLDPLS(CodeGenerator* code_gen);
+};

+ 48 - 0
V-Gears-Installer/include/decompiler/field/instruction/FieldCameraInstruction.h

@@ -0,0 +1,48 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "decompiler/decompiler_engine.h"
+
+/**
+ * A camera instruction.
+ */
+class FieldCameraInstruction : public KernelCallInstruction{
+
+    public:
+
+        /**
+         * Processes the instruction.
+         *
+         * @param func[in] Function to process.
+         * @param stack[out] Function stack.
+         * @param engine[in] Engine. Unused
+         * @param code_gen[in|out] Code generator.
+         */
+        virtual void ProcessInst(
+          Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
+        ) override;
+
+    private:
+
+        void ProcessNFADE(CodeGenerator* code_gen);
+        void ProcessSCR2D(CodeGenerator* code_gen);
+        void ProcessSCR2DC(CodeGenerator* code_gen);
+        void ProcessFADE(CodeGenerator* code_gen);
+};

+ 61 - 0
V-Gears-Installer/include/decompiler/field/instruction/FieldCondJumpInstruction.h

@@ -0,0 +1,61 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "decompiler/decompiler_engine.h"
+
+/**
+ * A conditional map jump instruction.
+ */
+class FieldCondJumpInstruction : public CondJumpInstruction{
+
+    public:
+
+        /**
+         * Processes a conditional jump instruction.
+         *
+         * Checks if the condition is a function or a comparison, and
+         * adds the function to the stack.
+         *
+         * @param function[in] Function to process. Unused.
+         * @param stack[out] Function stack. The instruction will be added
+         * here.
+         * @param engine[in] Engine. Unused.
+         * @param code_gen[in|out] Code generator.
+         */
+        virtual void ProcessInst(
+          Function& function, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
+        ) override;
+
+        /**
+         * Retrieves the destination address of the jump.
+         *
+         * @return The offset (number of bytes) to jump from the beginning
+         * of the instruction.
+         */
+        virtual uint32 GetDestAddress() const override;
+
+        /**
+         * Prints the instruction
+         *
+         * @param output The stram to print the instruction to.
+         * @todo Understand and document properly.
+         */
+        virtual std::ostream& Print(std::ostream &output) const override;
+};

+ 186 - 0
V-Gears-Installer/include/decompiler/field/instruction/FieldControlFlowInstruction.h

@@ -0,0 +1,186 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "decompiler/decompiler_engine.h"
+#include "decompiler/field/FieldEngine.h"
+
+/**
+ * A script flow control instruction.
+ */
+class FieldControlFlowInstruction : public KernelCallInstruction{
+
+    public:
+
+        /**
+         * Create a FieldControlFlowInstruction.
+         *
+         * @return Pointer to the newly created instruction.
+         */
+        static InstPtr Create(){return new FieldControlFlowInstruction();}
+
+        /**
+         * Processes the instruction.
+         *
+         * @param func[in] Function to process.
+         * @param stack[out] Function stack.
+         * @param engine[in] Engine.
+         * @param code_gen[in|out] Code generator.
+         */
+        virtual void ProcessInst(
+          Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
+        ) override;
+
+    private:
+
+        /**
+         * Processes a REQ command.
+         *
+         * Opcode: 0x01
+         * Short name: REQ
+         * Long name: Request remote execution (asynchronous, non-guaranteed)
+         *
+         * Memory layout (3 bytes)
+         * |0x01|E|P/F|
+         *
+         * Arguments
+         * - const UByte E: The ID of the target entity.
+         * - const Bit[3] P: The priority at which we want to execute the
+         * remote script (high 3 bits of byte).
+         * - const Bit[5] F: The ID of the specific member function of E to be
+         * executed (low 5 bits of byte).
+         *
+         * Requests that a remote entity executes one of its member functions
+         * at a specified priority. The request is asynchronous and returns
+         * immediately without waiting for the remote execution to start or
+         * finish. If the specified priority is already busy executing, the
+         * request will fail silently.
+         *
+         * @param codegen[in|out] Code generator. Output lines are appended.
+         * @param engine[in] The engine.
+         */
+        void ProcessREQ(CodeGenerator* code_gen, const FieldEngine& engine);
+
+        /**
+         * Processes a REQSW command.
+         *
+         * Opcode: 0x02
+         * Short name: REQSW
+         * Long name: Request remote execution (asynchronous execution,
+         * guaranteed)
+         *
+         * Memory layout (3 bytes)
+         * |0x02|E|P/F|
+         *
+         * Arguments
+         * - const UByte E: The ID of the target entity.
+         * - const Bit[3] P: The priority at which we want to execute the
+         * remote script (high 3 bits of byte).
+         * - const Bit[5] F: The ID of the specific member function of E to be
+         * executed (low 5 bits of byte).
+         *
+         * Requests that a remote entity executes one of its member functions
+         * at a specified priority. If the specified priority is already busy
+         * executing, the request will block until it becomes available and
+         * only then return. The remote execution is still carried out
+         * asynchronously, with no notification of completion.
+         *
+         * @param codegen[in|out] Code generator. Output lines are appended.
+         * @param engine[in] The engine.
+         */
+        void ProcessREQSW(CodeGenerator* code_gen, const FieldEngine& engine);
+
+        /**
+         * Processes a REQEW command.
+         *
+         * Opcode: 0x03
+         * Short name: REQEW
+         * Long name: Request remote execution (synchronous, guaranteed)
+         *
+         * Memory layout (3 bytes)
+         * |0x03|E|P/F|
+         *
+         * Arguments
+         * - const UByte E: The ID of the target entity.
+         * - const Bit[3] P: The priority at which we want to execute the
+         * remote script (high 3 bits of byte).
+         * - const Bit[5] F: The ID of the specific member function of E to be
+         * be executed (low 5 bits of byte).
+         *
+         * Requests that a remote entity executes one of its member functions
+         * at a specified priority. The request will block until remote
+         * execution has finished before returning.
+         *
+         * @param codegen[in|out] Code generator. Output lines are appended.
+         * @param engine[in] The engine.
+         */
+        void ProcessREQEW(CodeGenerator* code_gen, const FieldEngine& engine);
+
+        /**
+         * Processes a RETTO command.
+         *
+         * Opcode: 0x07
+         * Short name: RETTO
+         * Long name: Return To
+         *
+         * Memory layout (2 bytes)
+         * |0x07|P/F|
+         *
+         * Arguments
+         * - const Bit[3] P: The priority at which we want to execute the
+         * remote script (high 3 bits of byte).
+         * - const Bit[5] F: The ID of the specific member function of the
+         * current entity to be executed to (low 5 bits of byte).
+         *
+         * Stops the active script loop for this entity and also any script
+         * loops (except the main) that are queuing to be executed after the
+         * current script. This is essentially the same as adding a RET onto
+         * each of the active / queued scripts next execution position and
+         * returning the current op index to index for each script. Then the
+         * script control is passed to the script F within the current entity
+         * with the priority P.
+         *
+         * @param codegen[in|out] Code generator. Output lines are appended.
+         */
+        void ProcessRETTO(CodeGenerator* code_gen);
+
+        /**
+         * Processes a WAIT command.
+         *
+         * Opcode: 0x24
+         * Short name: WAIT
+         * Long name: Wait
+         *
+         * Memory layout (2 bytes)
+         * |0x24|A|
+         *
+         * Arguments
+         * - const UShort A: Amount (number of frames) to wait.
+         *
+         * Pauses current script execution for a specific amount of time.
+         * Rather than a specific time value in milliseconds/seconds, the
+         * amount specifies the number of frames that must be drawn before
+         * execution resumes. Since the game runs at 30fps, WAIT(0x1E) (or
+         * WAIT(30) in decimal) will pause script execution for 1 second,
+         * WAIT(0x96) will pause for 5 seconds, and so on.
+         *
+         * @param codegen[in|out] Code generator. Output lines are appended.
+         */
+        void ProcessWAIT(CodeGenerator* code_gen);
+};

+ 109 - 0
V-Gears-Installer/include/decompiler/field/instruction/FieldMathInstruction.h

@@ -0,0 +1,109 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "decompiler/decompiler_engine.h"
+
+/**
+ * A math instruction.
+ */
+class FieldMathInstruction : public StoreInstruction{
+
+    public:
+
+        /**
+         * Processes the instruction.
+         *
+         * @param func[in] Function to process.
+         * @param stack[out] Function stack.
+         * @param engine[in] Engine. Unused.
+         * @param code_gen[in|out] Code generator.
+         */
+        virtual void ProcessInst(
+          Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
+        ) override;
+
+    private:
+
+        void ProcessSaturatedPLUS(CodeGenerator* code_gen);
+        void ProcessSaturatedPLUS2(CodeGenerator* code_gen);
+        void ProcessSaturatedMINUS(CodeGenerator* code_gen);
+        void ProcessSaturatedMINUS2(CodeGenerator* code_gen);
+        void ProcessSaturatedINC(CodeGenerator* code_gen);
+        void ProcessSaturatedINC2(CodeGenerator* code_gen);
+        void ProcessSaturatedDEC(CodeGenerator* code_gen);
+        void ProcessSaturatedDEC2(CodeGenerator* code_gen);
+        void ProcessRDMSD(CodeGenerator* code_gen);
+        void ProcessSETBYTE_SETWORD(CodeGenerator* code_gen);
+
+        /**
+         * Processes a BITON opcode.
+         *
+         * Opcode: 0x82
+         * Short name: BITON
+         * Long name: Set Bit
+         *
+         * Memory layout (4 bytes)
+         * |0x82|D/S|A|B|
+         *
+         * Arguments
+         * - const Bit[4] D: Destination bank.
+         * - const Bit[4] S: Source bank.
+         * - const UByte A: Destination address.
+         * - const UByte Bit: The number of the bit to turn on.
+         *
+         * Sets the nth bit in the "A" location, where n is a number between
+         * 0-7 supplied in B. A value of zero in B will set the least
+         * significant bit. If the Source Bank is 0 then the bit to be set is
+         * taken from "Bit". If the Source Bank is an 8 bit bank, then the bit
+         * is the address in that bank where the operand is.
+         *
+         * @param codegen[in|out] Code generator. Output lines are appended.
+         */
+        void ProcessBITON(CodeGenerator* code_gen);
+
+        /**
+         * Processes a BITON opcode.
+         *
+         * Opcode: 0x83
+         * Short name: BITOFF
+         * Long name: Reset Bit
+         *
+         * Memory layout (4 bytes)
+         * |0x83|D/S|A|B|
+         *
+         * Arguments
+         * - const Bit[4] D: Destination bank.
+         * - const Bit[4] S: Source bank.
+         * - const UByte A: Destination address.
+         * - const UByte Bit: The number of the bit to turn off.
+         *
+         * Sets the nth bit in the "A" location, where n is a number between
+         * 0-7 supplied in B. A value of zero in B will reset the least
+         * significant bit. If the Source Bank is 0 then the bit to be set is
+         * taken from "Bit". If the Source Bank is an 8 bit bank, then the bit
+         * is the address in that bank where the operand is.
+         *
+         * @param codegen[in|out] Code generator. Output lines are appended.
+         */
+        void ProcessBITOFF(CodeGenerator* code_gen);
+        void ProcessPLUSx_MINUSx(CodeGenerator* code_gen, const std::string& op);
+        void ProcessINCx_DECx(CodeGenerator* code_gen, const std::string& op);
+        void ProcessRANDOM(CodeGenerator* code_gen);
+};

+ 52 - 0
V-Gears-Installer/include/decompiler/field/instruction/FieldMediaInstruction.h

@@ -0,0 +1,52 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "decompiler/decompiler_engine.h"
+
+/**
+ * An audio or video (or both) instruction.
+ */
+class FieldMediaInstruction : public KernelCallInstruction{
+
+    public:
+
+        /**
+         * Processes the instruction.
+         *
+         * @param func[in] Function to process.
+         * @param stack[out] Function stack.
+         * @param engine[in] Engine. Unused
+         * @param code_gen[in|out] Code generator.
+         */
+        virtual void ProcessInst(
+          Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
+        ) override;
+
+    private:
+
+        void ProcessAKAO2(CodeGenerator* code_gen);
+        void ProcessMUSIC(CodeGenerator* code_gen);
+        void ProcessSOUND(CodeGenerator* code_gen);
+        void ProcessAKAO(CodeGenerator* code_gen);
+        void ProcessMULCK(CodeGenerator* code_gen);
+        void ProcessPMVIE(CodeGenerator* code_gen);
+        void ProcessMOVIE(CodeGenerator* code_gen);
+        void ProcessMVIEF(CodeGenerator* code_gen);
+};

+ 374 - 0
V-Gears-Installer/include/decompiler/field/instruction/FieldModelInstruction.h

@@ -0,0 +1,374 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "decompiler/decompiler_engine.h"
+#include "decompiler/field/FieldEngine.h"
+
+/**
+ * A model instruction.
+ */
+class FieldModelInstruction : public KernelCallInstruction{
+
+    public:
+
+        /**
+         * Processes the instruction.
+         *
+         * @param func[in] Function to process.
+         * @param stack[out] Function stack.
+         * @param engine[in] Engine.
+         * @param code_gen[in|out] Code generator.
+         */
+        virtual void ProcessInst(
+          Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
+        ) override;
+
+    private:
+
+        /**
+         * Processes a JOIN opcode.
+         *
+         * Opcode: 0x08
+         * Short name: JOIN
+         * Long name: Party Field Join
+         * Memory layout (2 bytes)
+         * |0x08|S|
+         *
+         * Arguments
+         * - const UByte S: Speed that the characters join back together.
+         *
+         * Causes seperated party characters that have previously been SPLIT
+         * onto the field, to be joined back together again; that is, only the
+         * party leader becomes visible on the field. This should be called if
+         * a previous SPLIT has completed (the party members have finished
+         * speaking, or performing their actions, for example). As with SPLIT,
+         * the speed of the join is specified, from a scale of 1 (almost
+         * instant) to FF (very slow walk), and must be non-zero. In contrast
+         * to most MOVE related opcodes, the speed is this setting is actually
+         * the total number of frames required. Depending on the distance from
+         * the player character and the number of frames required, the entity
+         * plays a run or walk animation. Also, all characters take the same
+         * time irrespective of distance. Calling JOIN without having
+         * previously SPLIT the characters will cause the party members to
+         * appear at the walkmesh origin and attempt to JOIN from there. This
+         * is not normally the required behaviour and should be avoided.
+         *
+         * @param codegen[in|out] Code generator. Output lines are appended.
+         */
+        void ProcessJOIN(CodeGenerator* code_gen);
+
+        /**
+         * Processes a SPLIT opcode.
+         *
+         * Opcode: 0x09
+         * Short name: SPLIT
+         * Long name: Party Field Split
+         *
+         * Memory layout (15 bytes)
+         * |0x20|B1/B2|B3/B4|B5/B6|XA|XA|YA|YA|DA|XB|XB|YB|YB|DB|S|
+         *
+         * Arguments
+         * - const Bit[4] B1: Bank for XA, or zero if XA is specified as a
+         * literal value.
+         * - const Bit[4] B2: Bank for YA, or zero if YA is specified as a
+         * literal value.
+         * - const Bit[4] B3: Bank for DA, or zero if DA is specified as a
+         * literal value.
+         * - const Bit[4] B4: Bank for XB, or zero if XB is specified as a
+         * literal value.
+         * - const Bit[4] B5: Bank for YB, or zero if YB is specified as a
+         * literal value.
+         * - const Bit[4] B6: Bank for DB, or zero if DB is specified as a
+         * literal value.
+         * - const Short XA: X-coordinate of the second character in the party
+         * after the split, or address for the value if B1 is non-zero.
+         * - const Short YA: Y-coordinate of the second character in the party
+         * after the split, or address for the value if B2 is non-zero.
+         * - const UByte DA: Direction the second character faces after the
+         * split, or address for the value if B3 is non-zero.
+         * - const Short XB: X-coordinate of the third character in the party
+         * after the split, or address for the value if B4 is non-zero.
+         * - const Short YB: Y-coordinate of the third character in the party
+         * after the split, or address for the value if B5 is non-zero.
+         * - const UByte DB: Direction the third character faces after the
+         * split, or address for the value if B6 is non-zero.
+         * - const UByte S: Speed that the characters split.
+         *
+         * Causes the common 'split effect' whereby the second and third
+         * characters in the current party 'come out' from the party leader.
+         * That is, they become visible in the field, starting from the center
+         * of the party leader, and move out to the coordinates specified in
+         * the argument list. This is commonly used when the other characters
+         * in the current party have an action or dialog to perform and must
+         * be individually visible in the field. As well as specifying final
+         * coordinates for the two other party characters, the directions each
+         * character faces after the split are specified as a byte, using the
+         * common direction values found throughout the game. Speed is also
+         * given and is used to specify the rate at which the characters leave
+         * the party leader, using a scale from 1 (almost instant) to FF
+         * (extremely slow walk); this must be non-zero. In contrast to most
+         * MOVE related op codes, the speed is this setting is actually the
+         * total number of frames required. Depending on the distance from the
+         * player character and the number of frames required, the entity
+         * plays a run or walk animation. Also, all * characters take the same
+         * time irrespective of distance.
+         *
+         * @param codegen[in|out] Code generator. Output lines are appended.
+         */
+        void ProcessSPLIT(CodeGenerator* code_gen);
+        void ProcessTLKON(CodeGenerator* code_gen, const std::string& entity);
+        void ProcessPC(CodeGenerator* code_gen, const std::string& entity);
+        void ProcessCHAR(CodeGenerator* code_gen, const std::string& entity);
+        void ProcessDFANM(CodeGenerator* code_gen, const std::string& entity, int char_id);
+        void ProcessANIME1(CodeGenerator* code_gen, const std::string& entity, int char_id);
+        void ProcessVISI(CodeGenerator* code_gen, const std::string& entity);
+        void ProcessXYZI(CodeGenerator* code_gen, const std::string& entity);
+        void ProcessMOVE(CodeGenerator* code_gen, const std::string& entity);
+        void ProcessMSPED(CodeGenerator* code_gen, const std::string& entity);
+        void ProcessDIR(CodeGenerator* code_gen, const std::string& entity);
+        void ProcessTURNGEN(CodeGenerator* code_gen, const std::string& entity);
+        void ProcessGETAI(CodeGenerator* code_gen, const FieldEngine& engine);
+        void ProcessANIM_2(CodeGenerator* code_gen, const std::string& entity, int char_id);
+        void ProcessCANIM2(CodeGenerator* code_gen, const std::string& entity, int char_id);
+        void ProcessCANM_2(CodeGenerator* code_gen, const std::string& entity, int char_id);
+        void ProcessCC(CodeGenerator* code_gen, const FieldEngine& engine);
+
+        /**
+         * Processes a JUMP opcode.
+         *
+         * Opcode: 0xC0
+         * Short name: JUMP
+         * Long name: Jump
+         *
+         * Memory layout (7 bytes)
+         * |0xC2|B1/B2|B3/B4|X|Y|I|Steps|
+         *
+         * Arguments
+         * - const Bit[4] B1: Bank to retrieve X-coordinate, or zero if
+         * specifying X as a literal value.
+         * - const Bit[4] B2: Bank to retrieve Y-coordinate, or zero if
+         * specifying Y as a literal value.
+         * - const Bit[4] B3: Bank to retrieve triangle ID, or zero if
+         * specifying Z as a literal value.
+         * - const Bit[4] B4: Bank to retrieve jump height, or zero if
+         * specifying H as a literal value.
+         * - const Short X: X-coordinate of the target to jump to, or lower
+         * byte specifying address if B1 is non-zero.
+         * - const Short Y: Y-coordinate of the target to jump to, or lower
+         * byte specifying address if B2 is non-zero.
+         * - const Short I: Triangle ID of the target to jump to, or lower
+         * byte specifying address if B3 is non-zero.
+         * - const UShort Steps: Steps in jump. Must be non-zero if a literal
+         * value. Alternatively, lower byte specifies address if B4 is
+         * non-zero.
+         *
+         * Causes the character to jump to the specified point and triangle
+         * ID, with the jump curve peaking at a height which is increased by
+         * using a larger value for the H argument. In addition, the larger
+         * the number, the longer the jump will take to complete. A "normal"
+         * value is around 0x15, 0x01 is fast and instantaneous; the argument
+         * must not be zero or the game will crash. Whilst this is an unsigned
+         * two-byte number, a large value (beyond around 0x60) will not only
+         * cause a vast jump height, but also cause the screen to scroll
+         * erratically (the larger the number, the more erratic). Main update
+         * function go through all entity with JUMP state and if stage is 0 it
+         * calculates final Z point according to triangle id. It sets current
+         * coords as start coords. The main thing this function does is set B
+         * coefficient for later calculation. It defines as follows:
+         *   B = (Z_final - Z_start) / steps - steps * 1.45;
+         * Then it set current step to 0 and stage to 1. On next update other
+         * part of function works. It's calculate real position. First it
+         * increment current step number. Then it calculate X and Y. They
+         * change linear so nothing interesting here. The Z calculation is as
+         * follows:
+         *   Z_current = - step^2 * 1.45 + step * B + Z_start;
+         * If current substep equal number of steps then we set current
+         * triangle to final triangle and set stage to 2. Which finalizes the
+         * routine on next opcode call. Neither animation nor sound is
+         * specified in this opcode. An animation is played by using an
+         * animation opcode such as DFANM, and a SOUND played, before the
+         * jump.
+         *
+         * @param codegen[in|out] Code generator. Output lines are appended.
+         * @param entity[in] The name of the entity.
+         */
+        void ProcessJUMP(CodeGenerator* code_gen, const std::string& entity);
+
+        /**
+         * Processes a AXYZI opcode
+         *
+         * Opcode: 0xC1
+         * Short name: AXYZI
+         * Long name: Entity Get Position
+         *
+         * Memory layout (8 bytes)
+         * |0xC1|B1/B2|B3/B4|A|X|Y|Z|I|
+         *
+         * Arguments
+         * - const Bit[4] B1: Bank to store X.
+         * - const Bit[4] B2: Bank to store Y.
+         * - const Bit[4] B3: Bank to store Z.
+         * - const Bit[4] B4: Bank to store I.
+         * - const UByte A: Entity ID whose field object will have its
+         * position retrieved from.
+         * - const UByte X: Address to store the X-coordinate.
+         * - const UByte Y: Address to store the Y-coordinate.
+         * - const UByte Z: Address to store the Z-coordinate.
+         * - const UByte I: Address to store the ID of the walkmesh triangle
+         * the object is standing on.
+         *
+         * Retrieves the coordinates of the field object that the entity,
+         * whose ID specified in A, is associated with. This opcode uses an
+         * entity ID, not a field object offset; as such, if an entity ID is
+         * given that does not have a field object, this opcode will store
+         * zero in each of the four address specified.
+         *
+         * @param codegen[in|out] Code generator. Output lines are appended.
+         */
+        void ProcessAXYZI(CodeGenerator* code_gen);
+
+        /**
+         * Processes a LADER opcode.
+         *
+         * Opcode: 0xC2
+         * Short name: LADER
+         * Long name: Ladder
+         *
+         * Memory layout (15 bytes)
+         * |0xC2|B1/B2|B3/B4|X|X|Y|Y|Z|Z|I|I|K|A|D|S|
+         *
+         * Arguments
+         * - const Bit[4] B1: Bank to retrieve X-coordinate, or zero if X is
+         * specified as a literal value.
+         * - const Bit[4] B2: Bank to retrieve Y-coordinate, or zero if Y is
+         * specified as a literal value.
+         * - const Bit[4] B3: Bank to retrieve Z-coordinate, or zero if Z is
+         * specified as a literal value.
+         * - const Bit[4] B4: Bank to retrieve ID, or zero if I is specified
+         * as a literal value.
+         * - const Short X: X-coordinate of the end of the ladder, or address
+         * to find X-coordinate if B1 is non-zero.
+         * - const Short Y: Y-coordinate of the end of the ladder, or address
+         * to find Y-coordinate if B2 is non-zero.
+         * - const Short Z: Z-coordinate of the end of the ladder, or address
+         * to find Z-coordinate if B3 is non-zero.
+         * - const UShort I: ID of the walkmesh triangle found at the end of
+         * the ladder, or address to find ID if B4 is non-zero.
+         * - const UByte K: The keys used to move the character on the ladder.
+         * - const UByte A: Animation ID for the field object's movement
+         * animation.
+         * - const UByte D: Direction the character faces when climbing the
+         * ladder.
+         * - const UByte S: Speed of the animation whilst climbing the ladder.
+         *
+         * Causes the character to climb a ladder; that is, switching from
+         * standard walkmesh movement, to climbing along a line connecting two
+         * points on the walkmesh. If B1, B2, B3 or B4 is non-zero, then the
+         * value for that particular component is taken from memory using the
+         * corresponding bank and address specified, rather than as a literal
+         * value. Both retrieved values and literals can be used for different
+         * components. If using X, Y, Z or I as addresses, the lower byte
+         * should hold the address whilst the higher byte should be zero. The
+         * coordinates specify the end-point of the ladder; the current
+         * position of the character is used as the start point. The ID of the
+         * walkmesh triangle must be specified; this is the triangle the
+         * character will step onto after reaching the end point of the
+         * ladder. The K value specifies the keys used to move the character
+         * across the ladder; keys outside the range found in the table will
+         * cause unpredictable behavior. The animation ID specifies an offset
+         * into the field object's animation list; this animation is played at
+         * the speed specified by S whilst the character climbs. Finally, the
+         * D argument is a direction value in the game's standard direction
+         * format, which orients the character on the ladder. This opcode is
+         * used as part of the character's entity, rather than in a separate
+         * entity, as with a LINE. A LINE is used to set the start point of
+         * the ladder on the walkmesh. When this LINE is crossed by the
+         * player, a script in the LINE then uses a PREQ (or one of its
+         * variants), calling the script in the party leader that defines the
+         * LADER, causing the character to switch to 'climbing mode'. To set
+         * up a two-way ladder, two LINEs are used at either end, with
+         * different values for the LADER arguments, such as differing end
+         * points. If this opcode is used as part of a non-playable character
+         * entity, the NPC object will automatically climb from the start to
+         * the end point without need for player interaction.
+         *
+         * @param codegen[in|out] Code generator. Output lines are appended.
+         * @param entity[in] The name of the entity.
+         */
+        void ProcessLADER(CodeGenerator* code_gen, const std::string& entity);
+
+        void ProcessSOLID(CodeGenerator* code_gen, const std::string& entity);
+
+        /**
+         * Processes an OFST opcode.
+         *
+         * Opcode: 0xC3
+         * Short name: OFST
+         * Long name: Offset Object
+         *
+         * Memory layout (8 bytes)
+         * |0xC3|B1/B2|B3/B4|T|X|Y|Z|S|
+         *
+         * Arguments:
+         * - const Bit[4] B1: Bank to retrieve X offset, or zero if X is
+         * specified as a literal.
+         * - const Bit[4] B2: Bank to retrieve Y offset, or zero if Y is
+         * specified as a literal.
+         * - const Bit[4] B3: Bank to retrieve Z offset, or zero if Z is
+         * specified as a literal.
+         * - const Bit[4] B4: Bank to retrieve speed, or zero if S is
+         * specified as a literal.
+         * - const UByte T: Type of movement.
+         * - const Short X: X offset amount, relative to current position, or
+         * address to find X offset, if B1 is non-zero.
+         * - const Short Y: Y offset amount, relative to current position, or
+         * address to find Y offset, if B2 is non-zero.
+         * - const Short Z: Z offset amount, relative to current position, or
+         * address to find Z offset, if B3 is non-zero.
+         * - const UShort S: Speed of the offset movement, if type is
+         * non-zero, or address to find speed, if B4 is non-zero.
+         *
+         * Offsets the field object, belonging to the entity whose script this
+         * opcode resides in, by a certain amount. After being offset, the
+         * character continues to be constrained in movement as defined by the
+         * walkmesh's shape, but at a certain distance away from the normal
+         * walkmesh position. Other field objects are unaffected, and their
+         * position or movements are maintained on the walkmesh's original
+         * position. If B1, B2, B3 or B4 is non-zero, then the value for that
+         * particular component is taken from memory using the corresponding
+         * bank and address specified, rather than as a literal value. Both
+         * retrieved values and literals can be used for different components.
+         * If using T, X, Y or S as addresses, the lower byte should hold the
+         * address whilst the higher byte should be zero. The amount to offset
+         * is specified relative to the current position. If Type is
+         * specified, the object moves gradually from its current point to the
+         * offset position; this can be used to simulate movements such as
+         * elevators. Any type outside the range in the table will cause the
+         * offset not to occur. If the object is set to move gradually, then
+         * the speed of offset can be set; the greater the number, the slower
+         * the object moves to its target offset. Script execution may also be
+         * halted until the gradual offset has been completed. For this, see
+         * OFSTW.
+         *
+         * @param codegen[in|out] Code generator. Output lines are appended.
+         * @param entity[in] The entity name.
+         */
+        void ProcessOFST(CodeGenerator* codegen, const std::string& entity);
+};

+ 117 - 0
V-Gears-Installer/include/decompiler/field/instruction/FieldModuleInstruction.h

@@ -0,0 +1,117 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "decompiler/decompiler_engine.h"
+
+/**
+ * A module instruction.
+ */
+class FieldModuleInstruction : public KernelCallInstruction{
+
+    public:
+
+        /**
+         * Processes the instruction.
+         *
+         * @param func[in] Function to process.
+         * @param stack[out] Function stack.
+         * @param engine[in] Engine. Unused.
+         * @param code_gen[in|out] Code generator.
+         */
+        virtual void ProcessInst(
+          Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
+        ) override;
+
+    private:
+
+        /**
+         * Processes a BATTLE opcode.
+         *
+         * Opcode: 0x70
+         * Short name: BATTLE
+         * Long name: Start battle
+         *
+         * Memory layout (4 bytes)
+         * |0x70|B|N|N|
+         *
+         * Arguments
+         * - const UByte B: Bank (16-bit) to retrieve the address of the
+         * battle ID, or zero if it is given as a literal value.
+         * - const UWord N: Battle ID, or address to find ID if B is non-zero.
+         *
+         * This launches the battle module with whatever battle number is used
+         * in the argument, or the value retrieved from memory location N if B
+         * is non-zero. Battle 1, 2, and 999 (0x03E7) are debug battles.
+         *
+         * @param codegen[in|out] Code generator. Output lines are appended.
+         */
+        void ProcessBATTLE(CodeGenerator* code_gen);
+
+        /**
+         * Processes a BTLON opcode.
+         *
+         * Opcode: 0x71
+         * Short name: BTLON
+         * Long name: Battle switch
+         *
+         * Memory layout (2 bytes)
+         * |0x71|S|
+         *
+         * Arguments
+         * - const UByte S: Switch battles on/off (0/1, respectively).
+         *
+         * Turns random encounters on or off for this field. Note that if a
+         * field does not have any Encounter Data set in its field file,
+         * battles will not occur regardless of the argument passed with this
+         * opcode.
+         *
+         * @param codegen[in|out] Code generator. Output lines are appended.
+         */
+        void ProcessBTLON(CodeGenerator* code_gen);
+
+        /**
+         * Processes a MAPJUMP opcode.
+         *
+         * Opcode: 0x60
+         * Short name: BTLON
+         * Long name: Change Field
+         *
+         * Memory layout (10 bytes)
+         * |0x60|I|I|X|X|Y|Y|Z|Z|D|
+         *
+         * Arguments
+         * - const UShort I: Field ID of the map to jump to.
+         * - const Short X: X-coordinate of the player on the next field.
+         * - const Short Y: Y-coordinate of the player on the next field.
+         * - const Short Z: Z-coordinate of the player on the next field.
+         * - const UByte D: Direction the character will be facing on the next
+         * field, in the standard game format.
+         *
+         * Switches fields to the one indicated by I, and places the character
+         * at the coordinates and direction specified. This is an alternative
+         * to using a gateway, and can complement their usage as it allows for
+         * more than 12 gateways by simulating their behavior through a LINE
+         * which, when crossed, executes a MAPJUMP.
+         *
+         * @param codegen[in|out] Code generator. Output lines are appended.
+         * @param func[in] Function. @todo What for?
+         */
+        void ProcessMAPJUMP(CodeGenerator* code_gen, Function& func);
+};

+ 50 - 0
V-Gears-Installer/include/decompiler/field/instruction/FieldNoOperationInstruction.h

@@ -0,0 +1,50 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "decompiler/decompiler_engine.h"
+
+/**
+ * An instruction that does nothing.
+ */
+class FieldNoOperationInstruction : public Instruction{
+
+    public:
+
+        /**
+         * Generates a instruction that does nothing.
+         *
+         * @return The generated instruction.
+         */
+        static InstPtr Create(){return new FieldNoOperationInstruction();}
+
+        /**
+         * Processes the instruction.
+         *
+         * It doesn't do anything.
+         *
+         * @param func[in] Function to process. Unused.
+         * @param stack[out] Function stack. Unused.
+         * @param engine[in] Engine. Unused.
+         * @param code_gen[in|out] Code generator. Unused.
+         */
+        virtual void ProcessInst(
+          Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
+        ) override;
+};

+ 46 - 0
V-Gears-Installer/include/decompiler/field/instruction/FieldPartyInstruction.h

@@ -0,0 +1,46 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "decompiler/decompiler_engine.h"
+
+/**
+ * A party instruction.
+ */
+class FieldPartyInstruction : public KernelCallInstruction{
+
+    public:
+
+        /**
+         * Processes the instruction.
+         *
+         * @param func[in] Function to process.
+         * @param stack[out] Function stack.
+         * @param engine[in] Engine. Unused
+         * @param code_gen[in|out] Code generator.
+         */
+        virtual void ProcessInst(
+          Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
+        ) override;
+
+    private:
+
+        void ProcessSTITM(CodeGenerator* code_gen);
+        void ProcessPRTYE(CodeGenerator* code_gen);
+};

+ 41 - 0
V-Gears-Installer/include/decompiler/field/instruction/FieldUncategorizedInstruction.h

@@ -0,0 +1,41 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "decompiler/decompiler_engine.h"
+
+/**
+ * An instructions that doesn't fall in any other category.
+ */
+class FieldUncategorizedInstruction : public KernelCallInstruction{
+
+    public:
+
+        /**
+         * Processes the instruction.
+         *
+         * @param func[in] Function to process.
+         * @param stack[out] Function stack.
+         * @param engine[in] Engine.
+         * @param code_gen[in|out] Code generator.
+         */
+        virtual void ProcessInst(
+          Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
+        ) override;
+};

+ 84 - 0
V-Gears-Installer/include/decompiler/field/instruction/FieldUncondJumpInstruction.h

@@ -0,0 +1,84 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "decompiler/decompiler_engine.h"
+
+/**
+ * An unconditional map jump instruction.
+ */
+class FieldUncondJumpInstruction : public UncondJumpInstruction{
+
+    public:
+
+        /**
+         * Constructor.
+         */
+        FieldUncondJumpInstruction();
+
+        /**
+         * Indicates if the instruction is a function call.
+         *
+         * @return true if the instruction is a function call, false if not.
+         */
+        virtual bool IsFuncCall() const;
+
+        /**
+         * Indicates if the instruction is an unconditional jump.
+         *
+         * @return true if the instruction is an unconditional jump, false if
+         * it's not.
+         */
+        virtual bool IsUncondJump() const;
+
+        /**
+         * Retrieves the destination address of the jump.
+         *
+         * @return The offset (number of bytes) to jump from the beginning of
+         * the instruction.
+         */
+        virtual uint32 GetDestAddress() const;
+
+        /**
+         * Processes the instruction.
+         *
+         * @param func[in] Function to process. Unused.
+         * @param stack[out] Function stack.
+         * @param engine[in] Engine. Unused.
+         * @param code_gen[in|out] Code generator.
+         */
+        virtual void ProcessInst(
+          Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
+        ) override;
+
+        /**
+         * Prints the instruction
+         *
+         * @param output The stream to print the instruction to.
+         * @todo Understand and document properly.
+         */
+        virtual std::ostream& Print(std::ostream &output) const override;
+
+    private:
+
+        /**
+         * Whether or not this is really a call to a script function.
+         */
+        bool call_;
+};

+ 82 - 0
V-Gears-Installer/include/decompiler/field/instruction/FieldWalkmeshInstruction.h

@@ -0,0 +1,82 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "decompiler/decompiler_engine.h"
+
+/**
+ * A walkmesh instruction.
+ */
+class FieldWalkmeshInstruction : public KernelCallInstruction{
+
+    public:
+
+        /**
+         * Processes the instruction.
+         *
+         * @param func[in] Function to process.
+         * @param stack[out] Function stack.
+         * @param engine[in] Engine. Unused.
+         * @param code_gen[in|out] Code generator.
+         */
+        virtual void ProcessInst(
+          Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
+        ) override;
+
+    private:
+
+        void ProcessUC(CodeGenerator* code_gen);
+
+        /**
+         * Processes a LINE opcode.
+         *
+         * Opcode: 0xD0
+         * Short name: LINE
+         * Long name: Line definition
+         *
+         * Memory layout (7 bytes)
+         * |0xD0|XA|YA|ZA|XB|YB|ZB|
+         *
+         * Arguments:
+         * - const Short XA: X-coordinate of the first point of the line.
+         * - const Short YA: Y-coordinate of the first point of the line.
+         * - const Short ZA: Z-coordinate of the first point of the line.
+         * - const Short XB: X-coordinate of the second point of the line.
+         * - const Short YB: Y-coordinate of the second point of the line.
+         * - const Short ZB: Z-coordinate of the second point of the line.
+         *
+         * Defines a line on the walkmesh that, when crossed by a playable
+         * character, causes one of the entity's scripts to be executed. These
+         * are similar to the triggers in Section 8. All the lines in the
+         * current field can be turned on or off by using the LINON opcode.
+         *
+         * There are generally 6 scripts (other than the init and main) if the
+         * entity is a LINE.
+         * - script index 2 -> S1 - [OK].
+         * - script index 3 -> S2 - Move.
+         * - script index 4 -> S3 - Move.
+         * - script index 5 -> S4 - Go.
+         * - script index 6 -> S5 - Go 1x.
+         * - script index 7 -> S6 - Go away.
+         *
+         * @param codegen[in|out] Code generator. Output lines are appended.
+         * @param entity[in] The entity name.
+         */
+        void ProcessLINE(CodeGenerator* code_gen, const std::string& entity);
+};

+ 49 - 0
V-Gears-Installer/include/decompiler/field/instruction/FieldWindowInstruction.h

@@ -0,0 +1,49 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "decompiler/decompiler_engine.h"
+
+/**
+ * A window instruction.
+ */
+class FieldWindowInstruction : public KernelCallInstruction{
+
+    public:
+
+        /**
+         * Processes the instruction.
+         *
+         * @param func[in] Function to process.
+         * @param stack[out] Function stack.
+         * @param engine[in] Engine.
+         * @param code_gen[in|out] Code generator.
+         */
+        virtual void ProcessInst(
+          Function& func, ValueStack &stack, Engine *engine, CodeGenerator *code_gen
+        ) override;
+
+    private:
+
+        void ProcessMESSAGE(CodeGenerator* code_gen, const std::string& script_name);
+        void ProcessMPNAM(CodeGenerator* code_gen);
+        void ProcessMENU2(CodeGenerator* code_gen);
+        void ProcessWINDOW(CodeGenerator* code_gen);
+        void ProcessWCLSE(CodeGenerator* code_gen);
+};

+ 26 - 16
V-Gears-Installer/include/decompiler/instruction.h

@@ -81,6 +81,15 @@ public:
 	std::string _codeGenData;       ///< String containing metadata for code generation. See the extended documentation for details.
     bool mLabelRequired = false;
 
+    /**
+     * Writes a comment to the script indicating an unimplemented opcode.
+     *
+     * @param code_gen[in|out] Code generator. The line will be added to it
+     * @param owner[in] The name of the class. Unused.
+     * @param instructions[in] The name of the instruction.
+     */
+    static void WriteTodo(CodeGenerator *code_gen, std::string owner, std::string opcode);
+
 	/**
 	 * Operator overload to output an Instruction to a std::ostream.
 	 *
@@ -89,7 +98,7 @@ public:
 	 * @return The std::ostream used for output.
 	 */
 	friend std::ostream &operator<<(std::ostream &output, const Instruction *inst) {
-		return inst->print(output);
+		return inst->Print(output);
 	}
 
 	/**
@@ -98,7 +107,7 @@ public:
 	 * @param output The std::ostream to write to.
 	 * @return The std::ostream used for output.
 	 */
-	virtual std::ostream &print(std::ostream &output) const;
+	virtual std::ostream &Print(std::ostream &output) const;
 
 	/**
 	 * Returns whether or not the instruction is a jump of some sort.
@@ -119,7 +128,7 @@ public:
 	 *
 	 * @return True if the instruction is an unconditional jump, otherwise false.
 	 */
-	virtual bool isUncondJump() const;
+	virtual bool IsUncondJump() const;
 
 	/**
 	 * Returns whether or not the instruction is a stack operation.
@@ -133,7 +142,7 @@ public:
 	 *
 	 * @return True if the instruction is a script function call, otherwise false.
 	 */
-	virtual bool isFuncCall() const;
+	virtual bool IsFuncCall() const;
 
 	/**
 	 * Returns whether or not the instruction is a return statement.
@@ -169,7 +178,7 @@ public:
 	 * @return Destination address of a jump instruction.
 	 * @throws WrongTypeException if instruction is not a jump.
 	 */
-	virtual uint32 getDestAddress() const;
+	virtual uint32 GetDestAddress() const;
 
 	/**
 	 * Process an instruction for code generation.
@@ -178,7 +187,8 @@ public:
 	 * @param engine Pointer to the Engine used for code generation.
 	 * @param codeGen Pointer to the CodeGenerator used for code generation.
 	 */
-	virtual void processInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) = 0;
+	virtual void ProcessInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) = 0;
+
 };
 
 /**
@@ -200,8 +210,8 @@ public:
  */
 struct UncondJumpInstruction : public JumpInstruction {
 public:
-	virtual bool isUncondJump() const override;
-	virtual void processInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
+	virtual bool IsUncondJump() const override;
+	virtual void ProcessInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
 };
 
 /**
@@ -217,7 +227,7 @@ public:
  */
 struct CallInstruction : public Instruction {
 public:
-	virtual bool isFuncCall() const;
+	virtual bool IsFuncCall() const;
 };
 
 /**
@@ -273,7 +283,7 @@ public:
  */
 struct DupStackInstruction : public DupInstruction {
 public:
-	virtual void processInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
+	virtual void ProcessInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
 };
 
 /**
@@ -281,7 +291,7 @@ public:
  */
 struct BoolNegateStackInstruction : public BoolNegateInstruction {
 public:
-	virtual void processInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
+	virtual void ProcessInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
 };
 
 /**
@@ -289,7 +299,7 @@ public:
  */
 struct BinaryOpStackInstruction : public BinaryOpInstruction {
 public:
-	virtual void processInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
+	virtual void ProcessInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
 };
 
 /**
@@ -297,7 +307,7 @@ public:
  */
 struct ReturnInstruction : public Instruction {
 public:
-    virtual void processInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
+    virtual void ProcessInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
 	virtual bool isReturn() const;
 };
 
@@ -306,7 +316,7 @@ public:
  */
 struct UnaryOpPrefixStackInstruction : public UnaryOpInstruction {
 public:
-	virtual void processInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
+	virtual void ProcessInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
 };
 
 /**
@@ -314,7 +324,7 @@ public:
  */
 struct UnaryOpPostfixStackInstruction : public UnaryOpInstruction {
 public:
-	virtual void processInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
+	virtual void ProcessInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
 };
 
 /**
@@ -322,7 +332,7 @@ public:
  */
 struct KernelCallStackInstruction : public Instruction {
 public:
-	virtual void processInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
+	virtual void ProcessInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
 };
 
 /**

+ 26 - 26
V-Gears-Installer/include/decompiler/test/cfg_test.cpp

@@ -32,7 +32,7 @@
 TEST(CFG, testUnreachable) {
     InstVec insts;
     Scumm::v6::Scummv6Engine *engine = new Scumm::v6::Scummv6Engine();
-    auto d = engine->getDisassembler(insts);
+    auto d = engine->GetDisassembler(insts);
     d->open("decompiler/test/unreachable.dmp");
     d->disassemble();
     ControlFlow *c = new ControlFlow(insts, *engine);
@@ -65,7 +65,7 @@ TEST(CFG, testUnreachable) {
 TEST(CFG, testBranching) {
     InstVec insts;
     Scumm::v6::Scummv6Engine *engine = new Scumm::v6::Scummv6Engine();
-    auto d = engine->getDisassembler(insts);
+    auto d = engine->GetDisassembler(insts);
     d->open("decompiler/test/branches.dmp");
     d->disassemble();
 
@@ -99,7 +99,7 @@ TEST(CFG, testBranching) {
 TEST(CFG, testGrouping) {
     InstVec insts;
     auto engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    auto d = engine->getDisassembler(insts);
+    auto d = engine->GetDisassembler(insts);
     d->open("decompiler/test/branches.dmp");
     d->disassemble();
 
@@ -132,7 +132,7 @@ TEST(CFG, testGrouping) {
 TEST(CFG, DISABLED_testShortCircuitDetection) {
     InstVec insts;
     auto engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    auto d = engine->getDisassembler(insts);
+    auto d = engine->GetDisassembler(insts);
     d->open("decompiler/test/short-circuit.dmp");
     d->disassemble();
     auto c = std::make_unique<ControlFlow>(insts, *engine);
@@ -144,7 +144,7 @@ TEST(CFG, DISABLED_testShortCircuitDetection) {
 TEST(CFG, testWhileDetection) {
     InstVec insts;
     auto engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    auto d = engine->getDisassembler(insts);
+    auto d = engine->GetDisassembler(insts);
     d->open("decompiler/test/while.dmp");
     d->disassemble();
     auto c = std::make_unique<ControlFlow>(insts, *engine);
@@ -162,7 +162,7 @@ TEST(CFG, testWhileDetection) {
 TEST(CFG, testDoWhileDetection) {
     InstVec insts;
     auto engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    auto d = engine->getDisassembler(insts);
+    auto d = engine->GetDisassembler(insts);
     d->open("decompiler/test/while.dmp");
     d->disassemble();
     auto c = std::make_unique<ControlFlow>(insts, *engine);
@@ -179,7 +179,7 @@ TEST(CFG, testDoWhileDetection) {
 TEST(CFG, testBreakDetection) {
     InstVec insts;
     auto engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    auto d = engine->getDisassembler(insts);
+    auto d = engine->GetDisassembler(insts);
     d->open("decompiler/test/break-while.dmp");
     d->disassemble();
     auto c = std::make_unique<ControlFlow>(insts, *engine);
@@ -195,7 +195,7 @@ TEST(CFG, testBreakDetection) {
 
     insts.clear();
     engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    d = engine->getDisassembler(insts);
+    d = engine->GetDisassembler(insts);
     d->open("decompiler/test/break-do-while.dmp");
     d->disassemble();
 
@@ -211,7 +211,7 @@ TEST(CFG, testBreakDetection) {
 
     insts.clear();
     engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    d = engine->getDisassembler(insts);
+    d = engine->GetDisassembler(insts);
     d->open("decompiler/test/break-do-while2.dmp");
     d->disassemble();
     c = std::make_unique<ControlFlow>(insts, *engine);
@@ -229,7 +229,7 @@ TEST(CFG, testBreakDetection) {
 TEST(CFG, testContinueDetection) {
     InstVec insts;
     auto engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    auto d = engine->getDisassembler(insts);
+    auto d = engine->GetDisassembler(insts);
     d->open("decompiler/test/continue-while.dmp");
     d->disassemble();
     auto c = std::make_unique<ControlFlow>(insts, *engine);
@@ -247,7 +247,7 @@ TEST(CFG, testContinueDetection) {
 
     insts.clear();
     engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    d = engine->getDisassembler(insts);
+    d = engine->GetDisassembler(insts);
     d->open("decompiler/test/continue-do-while.dmp");
     d->disassemble();
     c = std::make_unique<ControlFlow>(insts, *engine);
@@ -262,7 +262,7 @@ TEST(CFG, testContinueDetection) {
 
     insts.clear();
     engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    d = engine->getDisassembler(insts);
+    d = engine->GetDisassembler(insts);
     d->open("decompiler/test/continue-do-while2.dmp");
     d->disassemble();
     c = std::make_unique<ControlFlow>(insts, *engine);
@@ -279,7 +279,7 @@ TEST(CFG, testContinueDetection) {
 TEST(CFG, testIfDetection) {
     InstVec insts;
     auto engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    auto d = engine->getDisassembler(insts);
+    auto d = engine->GetDisassembler(insts);
     d->open("decompiler/test/if.dmp");
     d->disassemble();
     auto c = std::make_unique<ControlFlow>(insts, *engine);
@@ -294,7 +294,7 @@ TEST(CFG, testIfDetection) {
 
     insts.clear();
     engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    d = engine->getDisassembler(insts);
+    d = engine->GetDisassembler(insts);
     d->open("decompiler/test/break-do-while.dmp");
     d->disassemble();
 
@@ -310,7 +310,7 @@ TEST(CFG, testIfDetection) {
 
     insts.clear();
     engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    d = engine->getDisassembler(insts);
+    d = engine->GetDisassembler(insts);
     d->open("decompiler/test/break-do-while2.dmp");
     d->disassemble();
     c = std::make_unique<ControlFlow>(insts, *engine);
@@ -326,7 +326,7 @@ TEST(CFG, testIfDetection) {
 
     insts.clear();
     engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    d = engine->getDisassembler(insts);
+    d = engine->GetDisassembler(insts);
     d->open("decompiler/test/continue-do-while.dmp");
     d->disassemble();
     c = std::make_unique<ControlFlow>(insts, *engine);
@@ -341,7 +341,7 @@ TEST(CFG, testIfDetection) {
 
     insts.clear();
     engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    d = engine->getDisassembler(insts);
+    d = engine->GetDisassembler(insts);
     d->open("decompiler/test/continue-do-while2.dmp");
     d->disassemble();
     c = std::make_unique<ControlFlow>(insts, *engine);
@@ -358,7 +358,7 @@ TEST(CFG, testIfDetection) {
 TEST(CFG, testElseDetection) {
     InstVec insts;
     auto engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    auto d = engine->getDisassembler(insts);
+    auto d = engine->GetDisassembler(insts);
     d->open("decompiler/test/if-else.dmp");
     d->disassemble();
     auto c = std::make_unique<ControlFlow>(insts, *engine);
@@ -375,7 +375,7 @@ TEST(CFG, testElseDetection) {
 
     insts.clear();
     engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    d = engine->getDisassembler(insts);
+    d = engine->GetDisassembler(insts);
     d->open("decompiler/test/if-no-else.dmp");
     d->disassemble();
 
@@ -394,7 +394,7 @@ TEST(CFG, testElseDetection) {
 TEST(CFG, testNestedLoops) {
     InstVec insts;
     auto engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    auto d = engine->getDisassembler(insts);
+    auto d = engine->GetDisassembler(insts);
     d->open("decompiler/test/do-while-in-while.dmp");
     d->disassemble();
     auto c = std::make_unique<ControlFlow>(insts, *engine);
@@ -411,7 +411,7 @@ TEST(CFG, testNestedLoops) {
 
     insts.clear();
     engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    d = engine->getDisassembler(insts);
+    d = engine->GetDisassembler(insts);
     d->open("decompiler/test/nested-do-while.dmp");
     d->disassemble();
 
@@ -429,7 +429,7 @@ TEST(CFG, testNestedLoops) {
 
     insts.clear();
     engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    d = engine->getDisassembler(insts);
+    d = engine->GetDisassembler(insts);
     d->open("decompiler/test/nested-while.dmp");
     d->disassemble();
     c = std::make_unique<ControlFlow>(insts, *engine);
@@ -446,7 +446,7 @@ TEST(CFG, testNestedLoops) {
 
     insts.clear();
     engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    d = engine->getDisassembler(insts);
+    d = engine->GetDisassembler(insts);
     d->open("decompiler/test/nested-while2.dmp");
     d->disassemble();
     c = std::make_unique<ControlFlow>(insts, *engine);
@@ -463,7 +463,7 @@ TEST(CFG, testNestedLoops) {
 
     insts.clear();
     engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    d = engine->getDisassembler(insts);
+    d = engine->GetDisassembler(insts);
     d->open("decompiler/test/while-in-do-while.dmp");
     d->disassemble();
     c = std::make_unique<ControlFlow>(insts, *engine);
@@ -480,7 +480,7 @@ TEST(CFG, testNestedLoops) {
 
     insts.clear();
     engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    d = engine->getDisassembler(insts);
+    d = engine->GetDisassembler(insts);
     d->open("decompiler/test/while-in-do-while2.dmp");
     d->disassemble();
 
@@ -503,7 +503,7 @@ TEST(CFG, testNestedLoops) {
 TEST(CFG, DISABLED_testSamAndMaxScript30) {
     InstVec insts;
     auto engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    auto d = engine->getDisassembler(insts);
+    auto d = engine->GetDisassembler(insts);
     d->open("decompiler/test/script-30.dmp");
     d->disassemble();
     auto c = std::make_unique<ControlFlow>(insts, *engine);

+ 10 - 10
V-Gears-Installer/include/decompiler/test/codegen.cpp

@@ -47,14 +47,14 @@ typedef std::vector<std::string>::iterator CodeIterator;
 TEST(CodeGen, testContinue) {
     InstVec insts;
     auto engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    auto d = engine->getDisassembler(insts);
+    auto d = engine->GetDisassembler(insts);
     d->open("decompiler/test/continue-do-while.dmp");
     d->disassemble();
     auto c = std::make_unique<ControlFlow>(insts, *engine);
     c->createGroups();
     Graph g = c->analyze();
     onullstream ns;
-    auto cg = engine->getCodeGenerator(insts, ns);
+    auto cg = engine->GetCodeGenerator(insts, ns);
     cg->generate(insts, g);
 
     VertexIterator v = boost::vertices(g).first;
@@ -86,14 +86,14 @@ TEST(CodeGen, testContinue) {
 TEST(CodeGen, testBreak) {
     InstVec insts;
     auto engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    auto d = engine->getDisassembler(insts);
+    auto d = engine->GetDisassembler(insts);
     d->open("decompiler/test/break-while.dmp");
     d->disassemble();
     auto c = std::make_unique<ControlFlow>(insts, *engine);
     c->createGroups();
     Graph g = c->analyze();
     onullstream ns;
-    auto cg = engine->getCodeGenerator(insts, ns);
+    auto cg = engine->GetCodeGenerator(insts, ns);
     cg->generate(insts, g);
 
     VertexIterator v = boost::vertices(g).first;
@@ -125,14 +125,14 @@ TEST(CodeGen, testBreak) {
 TEST(CodeGen, testElse) {
     InstVec insts;
     auto engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    auto d = engine->getDisassembler(insts);
+    auto d = engine->GetDisassembler(insts);
     d->open("decompiler/test/if-else.dmp");
     d->disassemble();
     auto c = std::make_unique<ControlFlow>(insts, *engine);
     c->createGroups();
     Graph g = c->analyze();
     onullstream ns;
-    auto cg = engine->getCodeGenerator(insts, ns);
+    auto cg = engine->GetCodeGenerator(insts, ns);
     cg->generate(insts, g);
 
     VertexIterator v = boost::vertices(g).first;
@@ -167,14 +167,14 @@ TEST(CodeGen, testElse) {
 TEST(CodeGen, DISABLED_testCoalescing) {
     InstVec insts;
     auto engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    auto d = engine->getDisassembler(insts);
+    auto d = engine->GetDisassembler(insts);
     d->open("decompiler/test/script-30.dmp");
     d->disassemble();
     auto c = std::make_unique<ControlFlow>(insts, *engine);
     c->createGroups();
     Graph g = c->analyze();
     onullstream ns;
-    auto cg = engine->getCodeGenerator(insts, ns);
+    auto cg = engine->GetCodeGenerator(insts, ns);
     cg->generate(insts, g);
 
     VertexIterator v = boost::vertices(g).first;
@@ -192,14 +192,14 @@ TEST(CodeGen, DISABLED_testCoalescing) {
 
     insts.clear();
     engine = std::make_unique<Scumm::v6::Scummv6Engine>();
-    d = engine->getDisassembler(insts);
+    d = engine->GetDisassembler(insts);
     d->open("decompiler/test/script-48.dmp");
     d->disassemble();
 
     c = std::make_unique<ControlFlow>(insts, *engine);
     c->createGroups();
     g = c->analyze();
-    cg = engine->getCodeGenerator(insts, ns);
+    cg = engine->GetCodeGenerator(insts, ns);
     cg->generate(insts, g);
 
     v = boost::vertices(g).first;

+ 1 - 1
V-Gears-Installer/include/decompiler/test/disassembler/pasc.h

@@ -33,7 +33,7 @@ public:
 
 class PasCFakeInstruction : public Instruction {
 public:
-    virtual void processInst(Function&, ValueStack&, Engine*, CodeGenerator*) override {}
+    virtual void ProcessInst(Function&, ValueStack&, Engine*, CodeGenerator*) override {}
 };
 
 #endif

+ 1 - 1
V-Gears-Installer/include/decompiler/test/disassembler/subopcode.h

@@ -32,7 +32,7 @@ public:
 
 class SubOpcodeFakeInstruction : public Instruction {
 public:
-    virtual void processInst(Function&, ValueStack&, Engine*, CodeGenerator*) override {}
+    virtual void ProcessInst(Function&, ValueStack&, Engine*, CodeGenerator*) override {}
 };
 
 #endif

+ 2 - 2
V-Gears-Installer/include/decompiler/test/ff7_field_all_opcodes_disassembler_test.cpp

@@ -12,9 +12,9 @@ TEST(FF7Field, AllOpcodesDisassembler)
 {
     InstVec insts;
     DummyFormatter formatter;
-    FF7FieldEngine engine(formatter);
+    FieldEngine engine(formatter);
 
-    auto d = engine.getDisassembler(insts);
+    auto d = engine.GetDisassembler(insts);
     d->open("decompiler/test/ff7_all_opcodes.dat");
     d->disassemble();
     d->dumpDisassembly(std::cout);

+ 4 - 4
V-Gears-Installer/include/decompiler/test/ff7_field_control_flow_test.cpp

@@ -29,7 +29,7 @@ static void CheckForwardJump(OPCODE opCode, size_t paramsSize, InstVec& insts, u
     ASSERT_EQ(jumpInst->_params.size(), paramsSize);
 
     const uint32 lastNopAddr = Is3Nops(insts, pos);
-    ASSERT_EQ(jumpInst->getDestAddress(), lastNopAddr);
+    ASSERT_EQ(jumpInst->GetDestAddress(), lastNopAddr);
 }
 
 // Verify next instructions is a NOP and return address of final NOP
@@ -59,7 +59,7 @@ static void CheckBackwardJump(OPCODE opCode, size_t paramsSize, InstVec& insts,
 
     ASSERT_EQ(jumpInst->_opcode, opCode);
     ASSERT_EQ(jumpInst->_params.size(), paramsSize);
-    ASSERT_EQ(jumpInst->getDestAddress(), firstNopAddr);
+    ASSERT_EQ(jumpInst->GetDestAddress(), firstNopAddr);
 }
 
 
@@ -68,9 +68,9 @@ TEST(FF7Field, ControlFlow)
 {
     InstVec insts;
     DummyFormatter formatter;
-    FF7FieldEngine engine(formatter, "test");
+    FieldEngine engine(formatter, "test");
 
-    auto d = engine.getDisassembler(insts);
+    auto d = engine.GetDisassembler(insts);
     d->open("decompiler/test/ff7_control_flow_test.dat");
     d->disassemble();
     d->dumpDisassembly(std::cout);

+ 2 - 2
V-Gears-Installer/include/decompiler/test/ff7_field_disasm_all_opcodes_by_category_test.cpp

@@ -106,9 +106,9 @@ TEST(FF7Field, DisasmAllOpcodes)
 
     InstVec insts;
     DummyFormatter formatter;
-    FF7FieldEngine engine(formatter, "test");
+    FieldEngine engine(formatter, "test");
 
-    auto d = engine.getDisassembler(insts);
+    auto d = engine.GetDisassembler(insts);
     d->open("decompiler/test/ff7_all_opcodes_by_category.dat");
     d->disassemble();
     d->dumpDisassembly(tmp);

+ 5 - 5
V-Gears-Installer/include/decompiler/test/main.cpp

@@ -43,7 +43,7 @@ static InstPtr DoReadParameterTest(std::string str, std::vector<unsigned char> d
 {
     InstVec insts;
     TestReadParameterDisassembler d(std::move(data), insts);
-    InstPtr inst = new FF7::FF7NoOperationInstruction();
+    InstPtr inst = new FF7::FieldNoOperationInstruction();
     d.readParams(inst, str.c_str());
     return inst;
 }
@@ -199,7 +199,7 @@ TEST(FF7World, DisAsm)
         std::cout << "SCRIPT(" << i << ")" << std::endl;
 
 
-        auto d = engine.getDisassembler(insts);
+        auto d = engine.GetDisassembler(insts);
         d->open("decompiler/ff7_world/wm0.ev");
         d->disassemble();
         d->dumpDisassembly(std::cout);
@@ -214,11 +214,11 @@ TEST(FF7World, DisAsm)
 
         Graph g = c->analyze();
 
-        engine.postCFG(insts, g);
+        engine.PostCFG(insts, g);
 
 
         onullstream ns;
-        auto cg = engine.getCodeGenerator(insts, std::cout);
+        auto cg = engine.GetCodeGenerator(insts, std::cout);
 
         std::ofstream out;
         out.open("graph.dot");
@@ -1507,7 +1507,7 @@ TEST(Parser, ZeroGapIf)
 TEST(FF7Field, Asm)
 {
     DummyFormatter dummy;
-    FF7FieldEngine eng(dummy, "test");
+    FieldEngine eng(dummy, "test");
 
     InstVec insts;
     FieldDisassembler d(dummy, &eng, insts);

+ 19 - 19
V-Gears-Installer/include/decompiler/world/ff7_world_engine.h

@@ -14,11 +14,11 @@ namespace FF7
         {
             setOutputStackEffect(true);
         }
-        std::unique_ptr<Disassembler> getDisassembler(InstVec &insts) override;
-        std::unique_ptr<CodeGenerator> getCodeGenerator(const InstVec& insts, std::ostream &output) override;
-        virtual void postCFG(InstVec &insts, Graph g) override;
+        std::unique_ptr<Disassembler> GetDisassembler(InstVec &insts) override;
+        std::unique_ptr<CodeGenerator> GetCodeGenerator(const InstVec& insts, std::ostream &output) override;
+        virtual void PostCFG(InstVec &insts, Graph g) override;
         virtual void getVariants(std::vector<std::string> &variants) const override;
-        virtual bool usePureGrouping() const override { return false; }
+        virtual bool UsePureGrouping() const override { return false; }
         std::vector<std::string> _textStrings; ///< Container for strings from the TEXT chunk.
     private:
         int mScriptNumber;
@@ -27,7 +27,7 @@ namespace FF7
     class FF7WorldLoadBankInstruction : public LoadInstruction
     {
     public:
-        virtual void processInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
+        virtual void ProcessInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
     };
 
     class BankValue : public VarValue
@@ -39,43 +39,43 @@ namespace FF7
     class FF7WorldLoadInstruction : public LoadInstruction 
     {
     public:
-        virtual void processInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
+        virtual void ProcessInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
     };
 
     class FF7SubStackInstruction : public StackInstruction
     {
     public:
-        virtual void processInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
+        virtual void ProcessInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
     };
 
     class BinaryEqualStackInstruction : public BinaryOpStackInstruction 
     {
     public:
-        virtual void processInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override
+        virtual void ProcessInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override
         {
             _codeGenData = "==";
-            BinaryOpStackInstruction::processInst(func, stack, engine, codeGen);
+            BinaryOpStackInstruction::ProcessInst(func, stack, engine, codeGen);
         }
     };
 
     class FF7WorldStoreInstruction : public StoreInstruction
     {
     public:
-        virtual void processInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
+        virtual void ProcessInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
     };
 
 
     class FF7WorldStackInstruction : public StackInstruction
     {
     public:
-        virtual void processInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
+        virtual void ProcessInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
     };
 
     class FF7WorldCondJumpInstruction : public CondJumpInstruction
     {
     public:
-        virtual void processInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
-        virtual uint32 getDestAddress() const;
+        virtual void ProcessInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
+        virtual uint32 GetDestAddress() const;
         virtual std::ostream& print(std::ostream &output) const override;
     };
 
@@ -84,10 +84,10 @@ namespace FF7
     public:
         bool _isCall;  ///< Whether or not this is really a call to a script function.
         FF7WorldUncondJumpInstruction() : _isCall(false) { }
-        virtual bool isFuncCall() const;
-        virtual bool isUncondJump() const;
-        virtual uint32 getDestAddress() const;
-        virtual void processInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
+        virtual bool IsFuncCall() const;
+        virtual bool IsUncondJump() const;
+        virtual uint32 GetDestAddress() const;
+        virtual void ProcessInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
         virtual std::ostream& print(std::ostream &output) const override;
 
     };
@@ -96,13 +96,13 @@ namespace FF7
     class FF7WorldKernelCallInstruction : public KernelCallInstruction
     {
     public:
-        virtual void processInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
+        virtual void ProcessInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
     };
 
     class FF7WorldNoOutputInstruction : public Instruction
     {
     public:
-        virtual void processInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
+        virtual void ProcessInst(Function& func, ValueStack &stack, Engine *engine, CodeGenerator *codeGen) override;
     };
 
 }

+ 8 - 8
V-Gears-Installer/src/decompiler/control_flow.cpp

@@ -80,7 +80,7 @@ ControlFlow::ControlFlow(InstVec& insts, Engine& engine)
 		}
 
 		last = cur;
-		addEdge = !((*it)->isUncondJump() || (*it)->isReturn());
+		addEdge = !((*it)->IsUncondJump() || (*it)->isReturn());
 		prev = GET(cur);
 
 	}
@@ -88,7 +88,7 @@ ControlFlow::ControlFlow(InstVec& insts, Engine& engine)
 	// Add jump edges
 	for (InstIterator it = insts.begin(); it != insts.end(); ++it) {
 		if ((*it)->isJump()) {
-			GraphEdge e = boost::add_edge(find(it), find((*it)->getDestAddress()), _g).first;
+			GraphEdge e = boost::add_edge(find(it), find((*it)->GetDestAddress()), _g).first;
 			PUT_EDGE(e, true);
 		}
 	}
@@ -231,7 +231,7 @@ void ControlFlow::createGroups()
 		}
 
 		// This part is only relevant if we use the stack level.
-		if (!mEngine.usePureGrouping()) {
+		if (!mEngine.UsePureGrouping()) {
 			// If group has no instructions with stack effect >= 0, don't merge on balanced stack
 			bool forceMerge = true;
 			ConstInstIterator it = grCur->_start;
@@ -347,7 +347,7 @@ void ControlFlow::detectBreak() {
 	for (VertexIterator v = vr.first; v != vr.second; ++v) {
 		GroupPtr gr = GET(*v);
 		// Undetermined block with unconditional jump...
-		if (gr->_type == kNormalGroupType && ((*gr->_end)->isUncondJump()) && out_degree(*v, _g) == 1) {
+		if (gr->_type == kNormalGroupType && ((*gr->_end)->IsUncondJump()) && out_degree(*v, _g) == 1) {
 			OutEdgeIterator oe = boost::out_edges(*v, _g).first;
 			GraphVertex target = boost::target(*oe, _g);
 			GroupPtr targetGr = GET(target);
@@ -372,7 +372,7 @@ void ControlFlow::detectContinue() {
 	for (VertexIterator v = vr.first; v != vr.second; ++v) {
 		GroupPtr gr = GET(*v);
 		// Undetermined block with unconditional jump...
-		if (gr->_type == kNormalGroupType && ((*gr->_end)->isUncondJump()) && out_degree(*v, _g) == 1) {
+		if (gr->_type == kNormalGroupType && ((*gr->_end)->IsUncondJump()) && out_degree(*v, _g) == 1) {
 			OutEdgeIterator oe = boost::out_edges(*v, _g).first;
 			GraphVertex target = boost::target(*oe, _g);
 			GroupPtr targetGr = GET(target);
@@ -466,7 +466,7 @@ void ControlFlow::detectElse() {
 			}
 			targetGr = GET(target);
 			// else: Jump target of if immediately preceded by an unconditional jump...
-			if (!(*targetGr->_prev->_end)->isUncondJump())
+			if (!(*targetGr->_prev->_end)->IsUncondJump())
 				continue;
 			// ...which is not a break or a continue...
 			if (targetGr->_prev->_type == kContinueGroupType || targetGr->_prev->_type == kBreakGroupType)
@@ -506,7 +506,7 @@ bool ControlFlow::validateElseBlock(GroupPtr ifGroup, GroupPtr start, GroupPtr e
 		}
 
 		// Unless group is a simple unconditional jump...
-		if ((*cursor->_start)->isUncondJump())
+		if ((*cursor->_start)->IsUncondJump())
 			continue;
 
 		// ...validate ingoing edges
@@ -520,7 +520,7 @@ bool ControlFlow::validateElseBlock(GroupPtr ifGroup, GroupPtr start, GroupPtr e
 				// ...must not come from outside the range [start, end]...
 				if ((*start->_start)->_address > (*sourceGr->_start)->_address || (*sourceGr->_start)->_address > (*end->_start)->_address) {
 					// ...unless source is simple unconditional jump...
-					if ((*sourceGr->_start)->isUncondJump())
+					if ((*sourceGr->_start)->IsUncondJump())
 						continue;
 					// ...or the edge is from the if condition associated with this else
 					if (ifGroup == sourceGr)

+ 3 - 3
V-Gears-Installer/src/decompiler/decompiler.cpp

@@ -139,7 +139,7 @@ int main(int argc, char** argv) {
 
 		// Disassembly
 		InstVec insts;
-		auto disassembler = engine->getDisassembler(insts);
+		auto disassembler = engine->GetDisassembler(insts);
 		disassembler->open(inputFile.c_str());
 
 		disassembler->disassemble();
@@ -191,10 +191,10 @@ int main(int argc, char** argv) {
 		}
 
 		// Post-processing of CFG
-		engine->postCFG(insts, g);
+		engine->PostCFG(insts, g);
 
 		// Code generation
-        auto cg = engine->getCodeGenerator(insts, std::cout);
+        auto cg = engine->GetCodeGenerator(insts, std::cout);
         cg->generate(insts, g);
 
 		if (vm.count("show-unreachable")) {

+ 6 - 6
V-Gears-Installer/src/decompiler/decompiler_codegen.cpp

@@ -240,7 +240,7 @@ void CodeGenerator::process(Function& func, InstVec& insts, GraphVertex v)
         {
             AddOutputLine(target_lang_->Label((*it)->_address));
         }
-        processInst(func, insts, *it);
+        ProcessInst(func, insts, *it);
     } while (it++ != mCurGroup->_end);
 
     // Add else end if necessary
@@ -300,7 +300,7 @@ void CodeGenerator::processUncondJumpInst(Function& func, InstVec& insts, const
                 {
                     // Check if this instruction is the last instruction in the function
                     // and its an uncond jump
-                    if (mCurGroup->_type == kDoWhileCondGroupType && inst->_address == func.mEndAddr && inst->isUncondJump())
+                    if (mCurGroup->_type == kDoWhileCondGroupType && inst->_address == func.mEndAddr && inst->IsUncondJump())
                     {
                         printJump = false;
                         AddOutputLine(target_lang_->DoLoopFooter(true) + "true" + target_lang_->DoLoopFooter(false), true, false);
@@ -311,7 +311,7 @@ void CodeGenerator::processUncondJumpInst(Function& func, InstVec& insts, const
 
         if (printJump)
         {
-            const uint32 dstAddr = inst->getDestAddress();
+            const uint32 dstAddr = inst->GetDestAddress();
             if (mIsLabelPass)
             {
                 // Mark the goto target
@@ -417,14 +417,14 @@ void CodeGenerator::processCondJumpInst(const InstPtr inst)
     }
 }
 
-void CodeGenerator::processInst(Function& func, InstVec& insts, const InstPtr inst)
+void CodeGenerator::ProcessInst(Function& func, InstVec& insts, const InstPtr inst)
 {
-    inst->processInst(func, _stack, _engine, this);
+    inst->ProcessInst(func, _stack, _engine, this);
     if (inst->isCondJump())
     {
         processCondJumpInst(inst);
     }
-    else if (inst->isUncondJump())
+    else if (inst->IsUncondJump())
     {
         processUncondJumpInst(func, insts, inst);
     }

+ 12 - 11
V-Gears-Installer/src/decompiler/field/FieldCodeGenerator.cpp

@@ -16,7 +16,8 @@
 #include <boost/algorithm/string/predicate.hpp>
 
 #include "decompiler/field/FieldCodeGenerator.h"
-#include "decompiler/field/ff7_field_engine.h"
+
+#include "../../../include/decompiler/field/FieldEngine.h"
 
 const std::string FunctionMetaData::DELIMITER("_");
 
@@ -117,8 +118,8 @@ void FieldCodeGenerator::Generate(InstVec& insts, const Graph& graph){
           instruction != function->second.end();
           ++ instruction
         ){
-            if ((*instruction)->isCondJump() || (*instruction)->isUncondJump()){
-                auto targetAddr = (*instruction)->getDestAddress();
+            if ((*instruction)->isCondJump() || (*instruction)->IsUncondJump()){
+                auto targetAddr = (*instruction)->GetDestAddress();
                 auto label = labels.find(targetAddr);
                 if (label == labels.end()) labels.insert({targetAddr, InstVec()});
                 labels[targetAddr].push_back(*instruction);
@@ -148,7 +149,7 @@ void FieldCodeGenerator::Generate(InstVec& insts, const Graph& graph){
                     AddOutputLine((boost::format("::label_0x%1$X::") % label->first).str());
             }
             ValueStack stack;
-            (*instruction)->processInst(function->first, stack, _engine, this);
+            (*instruction)->ProcessInst(function->first, stack, _engine, this);
             if (end_needed){
                 AddOutputLine("end -- end if", true, false);
                 end_needed = false;
@@ -162,12 +163,12 @@ void FieldCodeGenerator::Generate(InstVec& insts, const Graph& graph){
                 if ((*(instruction + 1))->_address == (*(function->second.back()))._address)
                     end_needed = true;
             }
-            else if ((*instruction)->isUncondJump()){
+            else if ((*instruction)->IsUncondJump()){
                 // If destination address is outside the functions, turn goto into a return.
-                if ((*instruction)->getDestAddress() > function->first.mEndAddr){
+                if ((*instruction)->GetDestAddress() > function->first.mEndAddr){
                     AddOutputLine(
                       "-- Overflowed jump to "
-                      + (boost::format("0x%1$X") % (*instruction)->getDestAddress()).str()
+                      + (boost::format("0x%1$X") % (*instruction)->GetDestAddress()).str()
                       + " (last address in function is "
                       + (boost::format("0x%1$X)") % function->first.mEndAddr).str()
                     );
@@ -176,16 +177,16 @@ void FieldCodeGenerator::Generate(InstVec& insts, const Graph& graph){
                 // Prevent backward jumps in the on_start script.
                 else if (
                   "on_start" == function->first._name
-                  && (*instruction)->getDestAddress() <= (*instruction)->_address
+                  && (*instruction)->GetDestAddress() <= (*instruction)->_address
                 ){
                     AddOutputLine("-- No infinite loops in the on_start script.");
                     AddOutputLine((
-                      boost::format("-- goto label_0x%1$X") % (*instruction)->getDestAddress()
+                      boost::format("-- goto label_0x%1$X") % (*instruction)->GetDestAddress()
                     ).str());
                 }
                 else{
                     AddOutputLine(
-                      (boost::format("goto label_0x%1$X") % (*instruction)->getDestAddress()).str()
+                      (boost::format("goto label_0x%1$X") % (*instruction)->GetDestAddress()).str()
                     );
                 }
             }
@@ -215,7 +216,7 @@ void FieldCodeGenerator::AddOutputLine(
 ){lines_.push_back(CodeLine(line, unindent_before, indent_after));}
 
 float FieldCodeGenerator::GetScaleFactor() const
-{return static_cast<FF7FieldEngine*>(_engine)->GetScaleFactor();}
+{return static_cast<FieldEngine*>(_engine)->GetScaleFactor();}
 
 void FieldCodeGenerator::OnBeforeStartFunction(const Function& function){
     FunctionMetaData meta_data(function._metadata);

+ 303 - 280
V-Gears-Installer/src/decompiler/field/FieldDisassembler.cpp

@@ -17,19 +17,32 @@
 #include <boost/format.hpp>
 #include <boost/algorithm/string/split.hpp>
 #include <boost/algorithm/string.hpp>
-
-#include "../../../include/decompiler/field/FieldDisassembler.h"
 #include "common/Lzs.h"
-#include "decompiler/field/ff7_field_engine.h"
 #include "decompiler/decompiler_engine.h"
+#include "decompiler/field/FieldDisassembler.h"
+#include "decompiler/field/FieldEngine.h"
 #include "decompiler/field/FieldCodeGenerator.h"
+#include "decompiler/field/instruction/FieldBackgroundInstruction.h"
+#include "decompiler/field/instruction/FieldCameraInstruction.h"
+#include "decompiler/field/instruction/FieldCondJumpInstruction.h"
+#include "decompiler/field/instruction/FieldControlFlowInstruction.h"
+#include "decompiler/field/instruction/FieldMathInstruction.h"
+#include "decompiler/field/instruction/FieldMediaInstruction.h"
+#include "decompiler/field/instruction/FieldModelInstruction.h"
+#include "decompiler/field/instruction/FieldModuleInstruction.h"
+#include "decompiler/field/instruction/FieldNoOperationInstruction.h"
+#include "decompiler/field/instruction/FieldPartyInstruction.h"
+#include "decompiler/field/instruction/FieldUncategorizedInstruction.h"
+#include "decompiler/field/instruction/FieldUncondJumpInstruction.h"
+#include "decompiler/field/instruction/FieldWalkmeshInstruction.h"
+#include "decompiler/field/instruction/FieldWindowInstruction.h"
 
 const int FieldDisassembler::MAGIC(0x0502);
 
 const int FieldDisassembler::NUM_SECTIONS(7);
 
 FieldDisassembler::FieldDisassembler(
-  SUDM::IScriptFormatter& formatter, FF7FieldEngine* engine, InstVec& insts,
+  SUDM::IScriptFormatter& formatter, FieldEngine* engine, InstVec& insts,
   const std::vector<unsigned char>& raw_script_data
 ) : SimpleDisassembler(insts), engine_(engine), formatter_(formatter){
     loaded_from_raw_ = true;
@@ -41,7 +54,7 @@ FieldDisassembler::FieldDisassembler(
 }
 
 FieldDisassembler::FieldDisassembler(
-  SUDM::IScriptFormatter& formatter, FF7FieldEngine *engine, InstVec &insts
+  SUDM::IScriptFormatter& formatter, FieldEngine *engine, InstVec &insts
 ) : SimpleDisassembler(insts), engine_(engine), formatter_(formatter){
     section_pointers_size_ = (sizeof(uint32) * NUM_SECTIONS);
 }
@@ -295,12 +308,12 @@ void FieldDisassembler::DisassembleIndivdualScript(
  */
 const InstructionRecord kOpcodes[] ={
     // Flow
-    { 1, OPCODE::RET, "RET", "", FF7ControlFlowInstruction::Create },
-    { 1, OPCODE::REQ, "REQ", "BU", FF7ControlFlowInstruction::Create },
-    { 1, OPCODE::REQSW, "REQSW", "BU", FF7ControlFlowInstruction::Create },
-    { 1, OPCODE::REQEW, "REQEW", "BU", FF7ControlFlowInstruction::Create },
-    { 1, OPCODE::NOP, "NOP", "", FF7NoOperationInstruction::Create },
-    { 1, OPCODE::IFUB, "IFUB", "NNBBBL", FF7NoOperationInstruction::Create }
+    { 1, OPCODE::RET, "RET", "", FieldControlFlowInstruction::Create },
+    { 1, OPCODE::REQ, "REQ", "BU", FieldControlFlowInstruction::Create },
+    { 1, OPCODE::REQSW, "REQSW", "BU", FieldControlFlowInstruction::Create },
+    { 1, OPCODE::REQEW, "REQEW", "BU", FieldControlFlowInstruction::Create },
+    { 1, OPCODE::NOP, "NOP", "", FieldNoOperationInstruction::Create },
+    { 1, OPCODE::IFUB, "IFUB", "NNBBBL", FieldNoOperationInstruction::Create }
 };
 
 /**
@@ -326,158 +339,168 @@ bool FieldDisassembler::ReadOpCodesToPositionOrReturn(
         std::string opcodePrefix;
         switch (opcode){
             // Flow
-            CASE_OPCODE(OPCODE::IFUB, "IFUB", FF7CondJumpInstruction, 0, "NBBBB");
-            CASE_OPCODE(OPCODE::RET, "RET", FF7ControlFlowInstruction, 0, "");
-            CASE_OPCODE(OPCODE::REQ, "REQ", FF7ControlFlowInstruction, 0, "BU");
-            CASE_OPCODE(OPCODE::REQSW, "REQSW", FF7ControlFlowInstruction, 0, "BU");
-            CASE_OPCODE(OPCODE::REQEW, "REQEW", FF7ControlFlowInstruction, 0, "BU");
-            CASE_OPCODE(OPCODE::PREQ, "PREQ", FF7ControlFlowInstruction, 0, "BU");
-            CASE_OPCODE(OPCODE::PRQSW, "PRQSW", FF7ControlFlowInstruction, 0, "BU");
-            CASE_OPCODE(OPCODE::PRQEW, "PRQEW", FF7ControlFlowInstruction, 0, "BU");
-            CASE_OPCODE(OPCODE::RETTO, "RETTO", FF7ControlFlowInstruction, 0, "U");
-            CASE_OPCODE(OPCODE::JMPF, "JMPF", FF7UncondJumpInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::JMPFL, "JMPFL", FF7UncondJumpInstruction, 0, "w");
-            CASE_OPCODE(OPCODE::JMPB, "JMPB", FF7UncondJumpInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::JMPBL, "JMPBL", FF7UncondJumpInstruction, 0, "w");
-            CASE_OPCODE(OPCODE::IFUBL, "IFUBL", FF7CondJumpInstruction, 0, "NBBBw");
-            CASE_OPCODE(OPCODE::IFSW, "IFSW", FF7CondJumpInstruction, 0, "NwwBB");
-            CASE_OPCODE(OPCODE::IFSWL, "IFSWL", FF7CondJumpInstruction, 0, "NwwBw");
-            CASE_OPCODE(OPCODE::IFUW, "IFUW", FF7CondJumpInstruction, 0, "NwwBB");
-            CASE_OPCODE(OPCODE::IFUWL, "IFUWL", FF7CondJumpInstruction, 0, "NwwBw");
-            CASE_OPCODE(OPCODE::WAIT, "WAIT", FF7ControlFlowInstruction, 0, "w");
-            CASE_OPCODE(OPCODE::IFKEY, "IFKEY", FF7CondJumpInstruction, 0, "wB");
-            CASE_OPCODE(OPCODE::IFKEYON, "IFKEYON", FF7CondJumpInstruction, 0, "wB");
-            CASE_OPCODE(OPCODE::IFKEYOFF, "IFKEYOFF", FF7CondJumpInstruction, 0, "wB");
-            CASE_OPCODE(OPCODE::NOP, "NOP", FF7NoOperationInstruction, 0, "");
-            CASE_OPCODE(OPCODE::IFPRTYQ, "IFPRTYQ", FF7CondJumpInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE::IFMEMBQ, "IFMEMBQ", FF7CondJumpInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::IFUB, "IFUB", FieldCondJumpInstruction, 0, "NBBBB");
+            /*case OPCODE::IFUB:
+                full_opcode = (full_opcode << 8) + OPCODE::IFUB;
+                this->_insts.push_back(new FieldCondJumpInstruction());
+                (this->_insts.back())->_opcode = full_opcode;
+                (this->_insts.back())->_address = this->address_;
+                (this->_insts.back())->_stackChange = 0;
+                (this->_insts.back())->_name = opcodePrefix + std::string("IFUB");
+                (this->_insts.back())->_codeGenData = "";
+                this->readParams((this->_insts.back()), "NBBBB");
+                break;*/
+            CASE_OPCODE(OPCODE::RET, "RET", FieldControlFlowInstruction, 0, "");
+            CASE_OPCODE(OPCODE::REQ, "REQ", FieldControlFlowInstruction, 0, "BU");
+            CASE_OPCODE(OPCODE::REQSW, "REQSW", FieldControlFlowInstruction, 0, "BU");
+            CASE_OPCODE(OPCODE::REQEW, "REQEW", FieldControlFlowInstruction, 0, "BU");
+            CASE_OPCODE(OPCODE::PREQ, "PREQ", FieldControlFlowInstruction, 0, "BU");
+            CASE_OPCODE(OPCODE::PRQSW, "PRQSW", FieldControlFlowInstruction, 0, "BU");
+            CASE_OPCODE(OPCODE::PRQEW, "PRQEW", FieldControlFlowInstruction, 0, "BU");
+            CASE_OPCODE(OPCODE::RETTO, "RETTO", FieldControlFlowInstruction, 0, "U");
+            CASE_OPCODE(OPCODE::JMPF, "JMPF", FieldUncondJumpInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::JMPFL, "JMPFL", FieldUncondJumpInstruction, 0, "w");
+            CASE_OPCODE(OPCODE::JMPB, "JMPB", FieldUncondJumpInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::JMPBL, "JMPBL", FieldUncondJumpInstruction, 0, "w");
+            CASE_OPCODE(OPCODE::IFUBL, "IFUBL", FieldCondJumpInstruction, 0, "NBBBw");
+            CASE_OPCODE(OPCODE::IFSW, "IFSW", FieldCondJumpInstruction, 0, "NwwBB");
+            CASE_OPCODE(OPCODE::IFSWL, "IFSWL", FieldCondJumpInstruction, 0, "NwwBw");
+            CASE_OPCODE(OPCODE::IFUW, "IFUW", FieldCondJumpInstruction, 0, "NwwBB");
+            CASE_OPCODE(OPCODE::IFUWL, "IFUWL", FieldCondJumpInstruction, 0, "NwwBw");
+            CASE_OPCODE(OPCODE::WAIT, "WAIT", FieldControlFlowInstruction, 0, "w");
+            CASE_OPCODE(OPCODE::IFKEY, "IFKEY", FieldCondJumpInstruction, 0, "wB");
+            CASE_OPCODE(OPCODE::IFKEYON, "IFKEYON", FieldCondJumpInstruction, 0, "wB");
+            CASE_OPCODE(OPCODE::IFKEYOFF, "IFKEYOFF", FieldCondJumpInstruction, 0, "wB");
+            CASE_OPCODE(OPCODE::NOP, "NOP", FieldNoOperationInstruction, 0, "");
+            CASE_OPCODE(OPCODE::IFPRTYQ, "IFPRTYQ", FieldCondJumpInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::IFMEMBQ, "IFMEMBQ", FieldCondJumpInstruction, 0, "BB");
 
             // Module
-            CASE_OPCODE(OPCODE::DSKCG, "DSKCG", FF7ModuleInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::DSKCG, "DSKCG", FieldModuleInstruction, 0, "B");
             START_SUBOPCODE(OPCODE::SPECIAL)
-                CASE_OPCODE(OPCODE_SPECIAL::ARROW, "ARROW", FF7ModuleInstruction, 0, "B");
-            CASE_OPCODE(OPCODE_SPECIAL::PNAME, "PNAME", FF7ModuleInstruction, 0, "B");
-            CASE_OPCODE(OPCODE_SPECIAL::GMSPD, "GMSPD", FF7ModuleInstruction, 0, "B");
-            CASE_OPCODE(OPCODE_SPECIAL::SMSPD, "SMSPD", FF7ModuleInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE_SPECIAL::FLMAT, "FLMAT", FF7ModuleInstruction, 0, "");
-            CASE_OPCODE(OPCODE_SPECIAL::FLITM, "FLITM", FF7ModuleInstruction, 0, "");
-            CASE_OPCODE(OPCODE_SPECIAL::BTLCK, "BTLCK", FF7ModuleInstruction, 0, "B");
-            CASE_OPCODE(OPCODE_SPECIAL::MVLCK, "MVLCK", FF7ModuleInstruction, 0, "B");
-            CASE_OPCODE(OPCODE_SPECIAL::SPCNM, "SPCNM", FF7ModuleInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE_SPECIAL::RSGLB, "RSGLB", FF7ModuleInstruction, 0, "");
-            CASE_OPCODE(OPCODE_SPECIAL::CLITM, "CLITM", FF7ModuleInstruction, 0, "");
+                CASE_OPCODE(OPCODE_SPECIAL::ARROW, "ARROW", FieldModuleInstruction, 0, "B");
+            CASE_OPCODE(OPCODE_SPECIAL::PNAME, "PNAME", FieldModuleInstruction, 0, "B");
+            CASE_OPCODE(OPCODE_SPECIAL::GMSPD, "GMSPD", FieldModuleInstruction, 0, "B");
+            CASE_OPCODE(OPCODE_SPECIAL::SMSPD, "SMSPD", FieldModuleInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE_SPECIAL::FLMAT, "FLMAT", FieldModuleInstruction, 0, "");
+            CASE_OPCODE(OPCODE_SPECIAL::FLITM, "FLITM", FieldModuleInstruction, 0, "");
+            CASE_OPCODE(OPCODE_SPECIAL::BTLCK, "BTLCK", FieldModuleInstruction, 0, "B");
+            CASE_OPCODE(OPCODE_SPECIAL::MVLCK, "MVLCK", FieldModuleInstruction, 0, "B");
+            CASE_OPCODE(OPCODE_SPECIAL::SPCNM, "SPCNM", FieldModuleInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE_SPECIAL::RSGLB, "RSGLB", FieldModuleInstruction, 0, "");
+            CASE_OPCODE(OPCODE_SPECIAL::CLITM, "CLITM", FieldModuleInstruction, 0, "");
             END_SUBOPCODE
-                CASE_OPCODE(OPCODE::MINIGAME, "MINIGAME", FF7ModuleInstruction, 0, "wsswBB");
-            CASE_OPCODE(OPCODE::BTMD2, "BTMD2", FF7ModuleInstruction, 0, "d");
-            CASE_OPCODE(OPCODE::BTRLD, "BTRLD", FF7ModuleInstruction, 0, "NB");
-            CASE_OPCODE(OPCODE::BTLTB, "BTLTB", FF7ModuleInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::MAPJUMP, "MAPJUMP", FF7ModuleInstruction, 0, "wsswB");
-            CASE_OPCODE(OPCODE::LSTMP, "LSTMP", FF7ModuleInstruction, 0, "NB");
-            CASE_OPCODE(OPCODE::BATTLE, "BATTLE", FF7ModuleInstruction, 0, "Nw");
-            CASE_OPCODE(OPCODE::BTLON, "BTLON", FF7ModuleInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::BTLMD, "BTLMD", FF7ModuleInstruction, 0, "w");
-            CASE_OPCODE(OPCODE::MPJPO, "MPJPO", FF7ModuleInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::PMJMP, "PMJMP", FF7ModuleInstruction, 0, "w");
-            CASE_OPCODE(OPCODE::PMJMP2, "PMJMP2", FF7ModuleInstruction, 0, "");
-            CASE_OPCODE(OPCODE::GAMEOVER, "GAMEOVER", FF7ModuleInstruction, 0, "");
+                CASE_OPCODE(OPCODE::MINIGAME, "MINIGAME", FieldModuleInstruction, 0, "wsswBB");
+            CASE_OPCODE(OPCODE::BTMD2, "BTMD2", FieldModuleInstruction, 0, "d");
+            CASE_OPCODE(OPCODE::BTRLD, "BTRLD", FieldModuleInstruction, 0, "NB");
+            CASE_OPCODE(OPCODE::BTLTB, "BTLTB", FieldModuleInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::MAPJUMP, "MAPJUMP", FieldModuleInstruction, 0, "wsswB");
+            CASE_OPCODE(OPCODE::LSTMP, "LSTMP", FieldModuleInstruction, 0, "NB");
+            CASE_OPCODE(OPCODE::BATTLE, "BATTLE", FieldModuleInstruction, 0, "Nw");
+            CASE_OPCODE(OPCODE::BTLON, "BTLON", FieldModuleInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::BTLMD, "BTLMD", FieldModuleInstruction, 0, "w");
+            CASE_OPCODE(OPCODE::MPJPO, "MPJPO", FieldModuleInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::PMJMP, "PMJMP", FieldModuleInstruction, 0, "w");
+            CASE_OPCODE(OPCODE::PMJMP2, "PMJMP2", FieldModuleInstruction, 0, "");
+            CASE_OPCODE(OPCODE::GAMEOVER, "GAMEOVER", FieldModuleInstruction, 0, "");
 
             // Math
-            CASE_OPCODE(OPCODE::PLUS_, "PLUS!", FF7MathInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::PLUS2_, "PLUS2!", FF7MathInstruction, 0, "NBw");
-            CASE_OPCODE(OPCODE::MINUS_, "MINUS!", FF7MathInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::MINUS2_, "MINUS2!", FF7MathInstruction, 0, "NBw");
-            CASE_OPCODE(OPCODE::INC_, "INC!", FF7MathInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE::INC2_, "INC2!", FF7MathInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE::DEC_, "DEC!", FF7MathInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE::DEC2_, "DEC2!", FF7MathInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE::RDMSD, "RDMSD", FF7MathInstruction, 0, "NB");
-            CASE_OPCODE(OPCODE::SETBYTE, "SETBYTE", FF7MathInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::SETWORD, "SETWORD", FF7MathInstruction, 0, "NBw");
-            CASE_OPCODE(OPCODE::BITON, "BITON", FF7MathInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::BITOFF, "BITOFF", FF7MathInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::BITXOR, "BITXOR", FF7MathInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::PLUS, "PLUS", FF7MathInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::PLUS2, "PLUS2", FF7MathInstruction, 0, "NBw");
-            CASE_OPCODE(OPCODE::MINUS, "MINUS", FF7MathInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::MINUS2, "MINUS2", FF7MathInstruction, 0, "NBw");
-            CASE_OPCODE(OPCODE::MUL, "MUL", FF7MathInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::MUL2, "MUL2", FF7MathInstruction, 0, "NBw");
-            CASE_OPCODE(OPCODE::DIV, "DIV", FF7MathInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::DIV2, "DIV2", FF7MathInstruction, 0, "NBw");
-            CASE_OPCODE(OPCODE::MOD, "MOD", FF7MathInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::MOD2, "MOD2", FF7MathInstruction, 0, "NBw");
-            CASE_OPCODE(OPCODE::AND, "AND", FF7MathInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::AND2, "AND2", FF7MathInstruction, 0, "NBw");
-            CASE_OPCODE(OPCODE::OR, "OR", FF7MathInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::OR2, "OR2", FF7MathInstruction, 0, "NBw");
-            CASE_OPCODE(OPCODE::XOR, "XOR", FF7MathInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::XOR2, "XOR2", FF7MathInstruction, 0, "NBw");
-            CASE_OPCODE(OPCODE::INC, "INC", FF7MathInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE::INC2, "INC2", FF7MathInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE::DEC, "DEC", FF7MathInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE::DEC2, "DEC2", FF7MathInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE::RANDOM, "RANDOM", FF7MathInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE::LBYTE, "LBYTE", FF7MathInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::HBYTE, "HBYTE", FF7MathInstruction, 0, "NBw");
-            CASE_OPCODE(OPCODE::TWOBYTE, "2BYTE", FF7MathInstruction, 0, "NNBBB");
-            CASE_OPCODE(OPCODE::SIN, "SIN", FF7MathInstruction, 0, "NNwwwB");
-            CASE_OPCODE(OPCODE::COS, "COS", FF7MathInstruction, 0, "NNwwwB");
+            CASE_OPCODE(OPCODE::PLUS_, "PLUS!", FieldMathInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::PLUS2_, "PLUS2!", FieldMathInstruction, 0, "NBw");
+            CASE_OPCODE(OPCODE::MINUS_, "MINUS!", FieldMathInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::MINUS2_, "MINUS2!", FieldMathInstruction, 0, "NBw");
+            CASE_OPCODE(OPCODE::INC_, "INC!", FieldMathInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::INC2_, "INC2!", FieldMathInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::DEC_, "DEC!", FieldMathInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::DEC2_, "DEC2!", FieldMathInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::RDMSD, "RDMSD", FieldMathInstruction, 0, "NB");
+            CASE_OPCODE(OPCODE::SETBYTE, "SETBYTE", FieldMathInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::SETWORD, "SETWORD", FieldMathInstruction, 0, "NBw");
+            CASE_OPCODE(OPCODE::BITON, "BITON", FieldMathInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::BITOFF, "BITOFF", FieldMathInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::BITXOR, "BITXOR", FieldMathInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::PLUS, "PLUS", FieldMathInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::PLUS2, "PLUS2", FieldMathInstruction, 0, "NBw");
+            CASE_OPCODE(OPCODE::MINUS, "MINUS", FieldMathInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::MINUS2, "MINUS2", FieldMathInstruction, 0, "NBw");
+            CASE_OPCODE(OPCODE::MUL, "MUL", FieldMathInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::MUL2, "MUL2", FieldMathInstruction, 0, "NBw");
+            CASE_OPCODE(OPCODE::DIV, "DIV", FieldMathInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::DIV2, "DIV2", FieldMathInstruction, 0, "NBw");
+            CASE_OPCODE(OPCODE::MOD, "MOD", FieldMathInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::MOD2, "MOD2", FieldMathInstruction, 0, "NBw");
+            CASE_OPCODE(OPCODE::AND, "AND", FieldMathInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::AND2, "AND2", FieldMathInstruction, 0, "NBw");
+            CASE_OPCODE(OPCODE::OR, "OR", FieldMathInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::OR2, "OR2", FieldMathInstruction, 0, "NBw");
+            CASE_OPCODE(OPCODE::XOR, "XOR", FieldMathInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::XOR2, "XOR2", FieldMathInstruction, 0, "NBw");
+            CASE_OPCODE(OPCODE::INC, "INC", FieldMathInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::INC2, "INC2", FieldMathInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::DEC, "DEC", FieldMathInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::DEC2, "DEC2", FieldMathInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::RANDOM, "RANDOM", FieldMathInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::LBYTE, "LBYTE", FieldMathInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::HBYTE, "HBYTE", FieldMathInstruction, 0, "NBw");
+            CASE_OPCODE(OPCODE::TWOBYTE, "2BYTE", FieldMathInstruction, 0, "NNBBB");
+            CASE_OPCODE(OPCODE::SIN, "SIN", FieldMathInstruction, 0, "NNwwwB");
+            CASE_OPCODE(OPCODE::COS, "COS", FieldMathInstruction, 0, "NNwwwB");
 
             // Window
-            CASE_OPCODE(OPCODE::TUTOR, "TUTOR", FF7WindowInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::WCLS, "WCLS", FF7WindowInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::WSIZW, "WSIZW", FF7WindowInstruction, 0, "Bwwww");
-            CASE_OPCODE(OPCODE::WSPCL, "WSPCL", FF7WindowInstruction, 0, "BBBB");
-            CASE_OPCODE(OPCODE::WNUMB, "WNUMB", FF7WindowInstruction, 0, "NBwwB"); // NBdB when N == 0
-            CASE_OPCODE(OPCODE::STTIM, "STTIM", FF7WindowInstruction, 0, "NNBBB");
-            CASE_OPCODE(OPCODE::MESSAGE, "MESSAGE", FF7WindowInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE::MPARA, "MPARA", FF7WindowInstruction, 0, "NBBB");
-            CASE_OPCODE(OPCODE::MPRA2, "MPRA2", FF7WindowInstruction, 0, "NBBw");
-            CASE_OPCODE(OPCODE::MPNAM, "MPNAM", FF7WindowInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::ASK, "ASK", FF7WindowInstruction, 0, "NBBBBB");
-            CASE_OPCODE(OPCODE::MENU, "MENU", FF7WindowInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::MENU2, "MENU2", FF7WindowInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::WINDOW, "WINDOW", FF7WindowInstruction, 0, "Bwwww");
-            CASE_OPCODE(OPCODE::WMOVE, "WMOVE", FF7WindowInstruction, 0, "Bss");
-            CASE_OPCODE(OPCODE::WMODE, "WMODE", FF7WindowInstruction, 0, "BBB");
-            CASE_OPCODE(OPCODE::WREST, "WREST", FF7WindowInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::WCLSE, "WCLSE", FF7WindowInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::WROW, "WROW", FF7WindowInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE::GWCOL, "GWCOL", FF7WindowInstruction, 0, "NNBBBB");
-            CASE_OPCODE(OPCODE::SWCOL, "SWCOL", FF7WindowInstruction, 0, "NNBBBB");
+            CASE_OPCODE(OPCODE::TUTOR, "TUTOR", FieldWindowInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::WCLS, "WCLS", FieldWindowInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::WSIZW, "WSIZW", FieldWindowInstruction, 0, "Bwwww");
+            CASE_OPCODE(OPCODE::WSPCL, "WSPCL", FieldWindowInstruction, 0, "BBBB");
+            CASE_OPCODE(OPCODE::WNUMB, "WNUMB", FieldWindowInstruction, 0, "NBwwB"); // NBdB when N == 0
+            CASE_OPCODE(OPCODE::STTIM, "STTIM", FieldWindowInstruction, 0, "NNBBB");
+            CASE_OPCODE(OPCODE::MESSAGE, "MESSAGE", FieldWindowInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::MPARA, "MPARA", FieldWindowInstruction, 0, "NBBB");
+            CASE_OPCODE(OPCODE::MPRA2, "MPRA2", FieldWindowInstruction, 0, "NBBw");
+            CASE_OPCODE(OPCODE::MPNAM, "MPNAM", FieldWindowInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::ASK, "ASK", FieldWindowInstruction, 0, "NBBBBB");
+            CASE_OPCODE(OPCODE::MENU, "MENU", FieldWindowInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::MENU2, "MENU2", FieldWindowInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::WINDOW, "WINDOW", FieldWindowInstruction, 0, "Bwwww");
+            CASE_OPCODE(OPCODE::WMOVE, "WMOVE", FieldWindowInstruction, 0, "Bss");
+            CASE_OPCODE(OPCODE::WMODE, "WMODE", FieldWindowInstruction, 0, "BBB");
+            CASE_OPCODE(OPCODE::WREST, "WREST", FieldWindowInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::WCLSE, "WCLSE", FieldWindowInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::WROW, "WROW", FieldWindowInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::GWCOL, "GWCOL", FieldWindowInstruction, 0, "NNBBBB");
+            CASE_OPCODE(OPCODE::SWCOL, "SWCOL", FieldWindowInstruction, 0, "NNBBBB");
 
             // Party
-            CASE_OPCODE(OPCODE::SPTYE, "SPTYE", FF7PartyInstruction, 0, "NNBBB");
-            CASE_OPCODE(OPCODE::GTPYE, "GTPYE", FF7PartyInstruction, 0, "NNBBB");
-            CASE_OPCODE(OPCODE::GOLDU, "GOLDU", FF7PartyInstruction, 0, "Nww"); // Nd when N == 0
-            CASE_OPCODE(OPCODE::GOLDD, "GOLDD", FF7PartyInstruction, 0, "Nww"); // Nd when N == 0
-            CASE_OPCODE(OPCODE::CHGLD, "CHGLD", FF7PartyInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::HMPMAX1, "HMPMAX1", FF7PartyInstruction, 0, "");
-            CASE_OPCODE(OPCODE::HMPMAX2, "HMPMAX2", FF7PartyInstruction, 0, "");
-            CASE_OPCODE(OPCODE::MHMMX, "MHMMX", FF7PartyInstruction, 0, "");
-            CASE_OPCODE(OPCODE::HMPMAX3, "HMPMAX3", FF7PartyInstruction, 0, "");
-            CASE_OPCODE(OPCODE::MPU, "MPU", FF7PartyInstruction, 0, "NBw");
-            CASE_OPCODE(OPCODE::MPD, "MPD", FF7PartyInstruction, 0, "NBw");
-            CASE_OPCODE(OPCODE::HPU, "HPU", FF7PartyInstruction, 0, "NBw");
-            CASE_OPCODE(OPCODE::HPD, "HPD", FF7PartyInstruction, 0, "NBw");
-            CASE_OPCODE(OPCODE::STITM, "STITM", FF7PartyInstruction, 0, "NwB");
-            CASE_OPCODE(OPCODE::DLITM, "DLITM", FF7PartyInstruction, 0, "NwB");
-            CASE_OPCODE(OPCODE::CKITM, "CKITM", FF7PartyInstruction, 0, "NwB");
-            CASE_OPCODE(OPCODE::SMTRA, "SMTRA", FF7PartyInstruction, 0, "NNBBBB");
-            CASE_OPCODE(OPCODE::DMTRA, "DMTRA", FF7PartyInstruction, 0, "NNBBBBB");
-            CASE_OPCODE(OPCODE::CMTRA, "CMTRA", FF7PartyInstruction, 0, "NNNBBBBBB");
-            CASE_OPCODE(OPCODE::GETPC, "GETPC", FF7PartyInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::PRTYP, "PRTYP", FF7PartyInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::PRTYM, "PRTYM", FF7PartyInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::PRTYE, "PRTYE", FF7PartyInstruction, 0, "BBB");
-            CASE_OPCODE(OPCODE::MMBUD, "MMBUD", FF7PartyInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE::MMBLK, "MMBLK", FF7PartyInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::MMBUK, "MMBUK", FF7PartyInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::SPTYE, "SPTYE", FieldPartyInstruction, 0, "NNBBB");
+            CASE_OPCODE(OPCODE::GTPYE, "GTPYE", FieldPartyInstruction, 0, "NNBBB");
+            CASE_OPCODE(OPCODE::GOLDU, "GOLDU", FieldPartyInstruction, 0, "Nww"); // Nd when N == 0
+            CASE_OPCODE(OPCODE::GOLDD, "GOLDD", FieldPartyInstruction, 0, "Nww"); // Nd when N == 0
+            CASE_OPCODE(OPCODE::CHGLD, "CHGLD", FieldPartyInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::HMPMAX1, "HMPMAX1", FieldPartyInstruction, 0, "");
+            CASE_OPCODE(OPCODE::HMPMAX2, "HMPMAX2", FieldPartyInstruction, 0, "");
+            CASE_OPCODE(OPCODE::MHMMX, "MHMMX", FieldPartyInstruction, 0, "");
+            CASE_OPCODE(OPCODE::HMPMAX3, "HMPMAX3", FieldPartyInstruction, 0, "");
+            CASE_OPCODE(OPCODE::MPU, "MPU", FieldPartyInstruction, 0, "NBw");
+            CASE_OPCODE(OPCODE::MPD, "MPD", FieldPartyInstruction, 0, "NBw");
+            CASE_OPCODE(OPCODE::HPU, "HPU", FieldPartyInstruction, 0, "NBw");
+            CASE_OPCODE(OPCODE::HPD, "HPD", FieldPartyInstruction, 0, "NBw");
+            CASE_OPCODE(OPCODE::STITM, "STITM", FieldPartyInstruction, 0, "NwB");
+            CASE_OPCODE(OPCODE::DLITM, "DLITM", FieldPartyInstruction, 0, "NwB");
+            CASE_OPCODE(OPCODE::CKITM, "CKITM", FieldPartyInstruction, 0, "NwB");
+            CASE_OPCODE(OPCODE::SMTRA, "SMTRA", FieldPartyInstruction, 0, "NNBBBB");
+            CASE_OPCODE(OPCODE::DMTRA, "DMTRA", FieldPartyInstruction, 0, "NNBBBBB");
+            CASE_OPCODE(OPCODE::CMTRA, "CMTRA", FieldPartyInstruction, 0, "NNNBBBBBB");
+            CASE_OPCODE(OPCODE::GETPC, "GETPC", FieldPartyInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::PRTYP, "PRTYP", FieldPartyInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::PRTYM, "PRTYM", FieldPartyInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::PRTYE, "PRTYE", FieldPartyInstruction, 0, "BBB");
+            CASE_OPCODE(OPCODE::MMBUD, "MMBUD", FieldPartyInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::MMBLK, "MMBLK", FieldPartyInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::MMBUK, "MMBUK", FieldPartyInstruction, 0, "B");
 
             // Model
-            CASE_OPCODE(OPCODE::JOIN, "JOIN", FF7ModelInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::SPLIT, "SPLIT", FF7ModelInstruction, 0, "NNNssBssBB");
-            CASE_OPCODE(OPCODE::BLINK, "BLINK", FF7ModelInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::JOIN, "JOIN", FieldModelInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::SPLIT, "SPLIT", FieldModelInstruction, 0, "NNNssBssBB");
+            CASE_OPCODE(OPCODE::BLINK, "BLINK", FieldModelInstruction, 0, "B");
             OPCODE_BASE(OPCODE::KAWAI){
                 int length = this->stream_->ReadU8();
                 assert(length >= 3);
@@ -488,58 +511,58 @@ bool FieldDisassembler::ReadOpCodesToPositionOrReturn(
                 opcode = this->stream_->ReadU8();
                 switch (opcode){
                     CASE_OPCODE(
-                        OPCODE_KAWAI::EYETX, "EYETX", FF7ModelInstruction, 0, parameters.c_str()
+                        OPCODE_KAWAI::EYETX, "EYETX", FieldModelInstruction, 0, parameters.c_str()
                     ); // was BBBB
                     CASE_OPCODE(
-                        OPCODE_KAWAI::TRNSP, "TRNSP", FF7ModelInstruction, 0, parameters.c_str()
+                        OPCODE_KAWAI::TRNSP, "TRNSP", FieldModelInstruction, 0, parameters.c_str()
                     ); // was B
                     CASE_OPCODE(
-                        OPCODE_KAWAI::AMBNT, "AMBNT", FF7ModelInstruction, 0, parameters.c_str()
+                        OPCODE_KAWAI::AMBNT, "AMBNT", FieldModelInstruction, 0, parameters.c_str()
                     ); // was BBBBBBB
                     CASE_OPCODE(
                         OPCODE_KAWAI::Unknown03, "Unknown03",
-                        FF7ModelInstruction, 0, parameters.c_str()
+                        FieldModelInstruction, 0, parameters.c_str()
                     );
                     CASE_OPCODE(
                         OPCODE_KAWAI::Unknown04, "Unknown04",
-                        FF7ModelInstruction, 0, parameters.c_str()
+                        FieldModelInstruction, 0, parameters.c_str()
                     );
                     CASE_OPCODE(
                         OPCODE_KAWAI::Unknown05, "Unknown05",
-                        FF7ModelInstruction, 0, parameters.c_str()
+                        FieldModelInstruction, 0, parameters.c_str()
                     );
                     CASE_OPCODE(
-                        OPCODE_KAWAI::LIGHT, "LIGHT",FF7ModelInstruction, 0, parameters.c_str()
+                        OPCODE_KAWAI::LIGHT, "LIGHT",FieldModelInstruction, 0, parameters.c_str()
                     );
                     CASE_OPCODE(
                         OPCODE_KAWAI::Unknown07, "Unknown07",
-                        FF7ModelInstruction, 0, parameters.c_str()
+                        FieldModelInstruction, 0, parameters.c_str()
                     );
                     CASE_OPCODE(
                         OPCODE_KAWAI::Unknown08, "Unknown08",
-                        FF7ModelInstruction, 0, parameters.c_str()
+                        FieldModelInstruction, 0, parameters.c_str()
                     );
                     CASE_OPCODE(
                         OPCODE_KAWAI::Unknown09, "Unknown09",
-                        FF7ModelInstruction, 0, parameters.c_str()
+                        FieldModelInstruction, 0, parameters.c_str()
                     );
                     CASE_OPCODE(
                         OPCODE_KAWAI::SBOBJ, "SBOBJ",
-                        FF7ModelInstruction, 0, parameters.c_str()
+                        FieldModelInstruction, 0, parameters.c_str()
                     );
                     CASE_OPCODE(
                       OPCODE_KAWAI::Unknown0B, "Unknown0B",
-                      FF7ModelInstruction, 0, parameters.c_str()
+                      FieldModelInstruction, 0, parameters.c_str()
                     );
                     CASE_OPCODE(
                         OPCODE_KAWAI::Unknown0C, "Unknown0C",
-                        FF7ModelInstruction, 0, parameters.c_str()
+                        FieldModelInstruction, 0, parameters.c_str()
                     );
                     CASE_OPCODE(
-                        OPCODE_KAWAI::SHINE, "SHINE", FF7ModelInstruction, 0, parameters.c_str()
+                        OPCODE_KAWAI::SHINE, "SHINE", FieldModelInstruction, 0, parameters.c_str()
                     );
                     CASE_OPCODE(
-                        OPCODE_KAWAI::RESET, "RESET", FF7ModelInstruction, 0, parameters.c_str()
+                        OPCODE_KAWAI::RESET, "RESET", FieldModelInstruction, 0, parameters.c_str()
                     );
                 default:
                     throw UnknownSubOpcodeException(this->address_, opcode);
@@ -548,71 +571,71 @@ bool FieldDisassembler::ReadOpCodesToPositionOrReturn(
                 INC_ADDR;
             }
             OPCODE_END
-            CASE_OPCODE(OPCODE::KAWIW, "KAWIW", FF7ModelInstruction, 0, "");
-            CASE_OPCODE(OPCODE::PMOVA, "PMOVA", FF7ModelInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::PDIRA, "PDIRA", FF7ModelInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::PTURA, "PTURA", FF7ModelInstruction, 0, "BBB");
-            CASE_OPCODE(OPCODE::PGTDR, "PGTDR", FF7ModelInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::PXYZI, "PXYZI", FF7ModelInstruction, 0, "NNBBBBB");
-            CASE_OPCODE(OPCODE::TLKON, "TLKON", FF7ModelInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::PC, "PC", FF7ModelInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::opCodeCHAR, "CHAR", FF7ModelInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::DFANM, "DFANM", FF7ModelInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE::ANIME1, "ANIME1", FF7ModelInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE::VISI, "VISI", FF7ModelInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::XYZI, "XYZI", FF7ModelInstruction, 0, "NNsssw");
-            CASE_OPCODE(OPCODE::XYI, "XYI", FF7ModelInstruction, 0, "NNssw");
-            CASE_OPCODE(OPCODE::XYZ, "XYZ", FF7ModelInstruction, 0, "NNsss");
-            CASE_OPCODE(OPCODE::MOVE, "MOVE", FF7ModelInstruction, 0, "Nss");
-            CASE_OPCODE(OPCODE::CMOVE, "CMOVE", FF7ModelInstruction, 0, "Nss");
-            CASE_OPCODE(OPCODE::MOVA, "MOVA", FF7ModelInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::TURA, "TURA", FF7ModelInstruction, 0, "BBB");
-            CASE_OPCODE(OPCODE::ANIMW, "ANIMW", FF7ModelInstruction, 0, "");
-            CASE_OPCODE(OPCODE::FMOVE, "FMOVE", FF7ModelInstruction, 0, "Nss");
-            CASE_OPCODE(OPCODE::ANIME2, "ANIME2", FF7ModelInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE::ANIM_1, "ANIM!1", FF7ModelInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE::CANIM1, "CANIM1", FF7ModelInstruction, 0, "BBBB");
-            CASE_OPCODE(OPCODE::CANM_1, "CANM!1", FF7ModelInstruction, 0, "BBBB");
-            CASE_OPCODE(OPCODE::MSPED, "MSPED", FF7ModelInstruction, 0, "Nw");
-            CASE_OPCODE(OPCODE::DIR, "DIR", FF7ModelInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE::TURNGEN, "TURNGEN", FF7ModelInstruction, 0, "NBBBB");
-            CASE_OPCODE(OPCODE::TURN, "TURN", FF7ModelInstruction, 0, "NBBBB");
-            CASE_OPCODE(OPCODE::DIRA, "DIRA", FF7ModelInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::GETDIR, "GETDIR", FF7ModelInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::GETAXY, "GETAXY", FF7ModelInstruction, 0, "NBBB");
-            CASE_OPCODE(OPCODE::GETAI, "GETAI", FF7ModelInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::ANIM_2, "ANIM!2", FF7ModelInstruction, 0, "BB");
-            CASE_OPCODE(OPCODE::CANIM2, "CANIM2", FF7ModelInstruction, 0, "BBBB");
-            CASE_OPCODE(OPCODE::CANM_2, "CANM!2", FF7ModelInstruction, 0, "BBBB");
-            CASE_OPCODE(OPCODE::ASPED, "ASPED", FF7ModelInstruction, 0, "Nw");
-            CASE_OPCODE(OPCODE::CC, "CC", FF7ModelInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::JUMP, "JUMP", FF7ModelInstruction, 0, "NNssww");
-            CASE_OPCODE(OPCODE::AXYZI, "AXYZI", FF7ModelInstruction, 0, "NNBBBBB");
-            CASE_OPCODE(OPCODE::LADER, "LADER", FF7ModelInstruction, 0, "NNssswBBBB");
-            CASE_OPCODE(OPCODE::OFST, "OFST", FF7ModelInstruction, 0, "NNBsssw");
-            CASE_OPCODE(OPCODE::OFSTW, "OFSTW", FF7ModelInstruction, 0, "");
-            CASE_OPCODE(OPCODE::TALKR, "TALKR", FF7ModelInstruction, 0, "NB");
-            CASE_OPCODE(OPCODE::SLIDR, "SLIDR", FF7ModelInstruction, 0, "NB");
-            CASE_OPCODE(OPCODE::SOLID, "SOLID", FF7ModelInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::TLKR2, "TLKR2", FF7ModelInstruction, 0, "Nw");
-            CASE_OPCODE(OPCODE::SLDR2, "SLDR2", FF7ModelInstruction, 0, "Nw");
-            CASE_OPCODE(OPCODE::CCANM, "CCANM", FF7ModelInstruction, 0, "BBB");
-            CASE_OPCODE(OPCODE::FCFIX, "FCFIX", FF7ModelInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::ANIMB, "ANIMB", FF7ModelInstruction, 0, "");
-            CASE_OPCODE(OPCODE::TURNW, "TURNW", FF7ModelInstruction, 0, "");
+            CASE_OPCODE(OPCODE::KAWIW, "KAWIW", FieldModelInstruction, 0, "");
+            CASE_OPCODE(OPCODE::PMOVA, "PMOVA", FieldModelInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::PDIRA, "PDIRA", FieldModelInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::PTURA, "PTURA", FieldModelInstruction, 0, "BBB");
+            CASE_OPCODE(OPCODE::PGTDR, "PGTDR", FieldModelInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::PXYZI, "PXYZI", FieldModelInstruction, 0, "NNBBBBB");
+            CASE_OPCODE(OPCODE::TLKON, "TLKON", FieldModelInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::PC, "PC", FieldModelInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::opCodeCHAR, "CHAR", FieldModelInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::DFANM, "DFANM", FieldModelInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::ANIME1, "ANIME1", FieldModelInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::VISI, "VISI", FieldModelInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::XYZI, "XYZI", FieldModelInstruction, 0, "NNsssw");
+            CASE_OPCODE(OPCODE::XYI, "XYI", FieldModelInstruction, 0, "NNssw");
+            CASE_OPCODE(OPCODE::XYZ, "XYZ", FieldModelInstruction, 0, "NNsss");
+            CASE_OPCODE(OPCODE::MOVE, "MOVE", FieldModelInstruction, 0, "Nss");
+            CASE_OPCODE(OPCODE::CMOVE, "CMOVE", FieldModelInstruction, 0, "Nss");
+            CASE_OPCODE(OPCODE::MOVA, "MOVA", FieldModelInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::TURA, "TURA", FieldModelInstruction, 0, "BBB");
+            CASE_OPCODE(OPCODE::ANIMW, "ANIMW", FieldModelInstruction, 0, "");
+            CASE_OPCODE(OPCODE::FMOVE, "FMOVE", FieldModelInstruction, 0, "Nss");
+            CASE_OPCODE(OPCODE::ANIME2, "ANIME2", FieldModelInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::ANIM_1, "ANIM!1", FieldModelInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::CANIM1, "CANIM1", FieldModelInstruction, 0, "BBBB");
+            CASE_OPCODE(OPCODE::CANM_1, "CANM!1", FieldModelInstruction, 0, "BBBB");
+            CASE_OPCODE(OPCODE::MSPED, "MSPED", FieldModelInstruction, 0, "Nw");
+            CASE_OPCODE(OPCODE::DIR, "DIR", FieldModelInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::TURNGEN, "TURNGEN", FieldModelInstruction, 0, "NBBBB");
+            CASE_OPCODE(OPCODE::TURN, "TURN", FieldModelInstruction, 0, "NBBBB");
+            CASE_OPCODE(OPCODE::DIRA, "DIRA", FieldModelInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::GETDIR, "GETDIR", FieldModelInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::GETAXY, "GETAXY", FieldModelInstruction, 0, "NBBB");
+            CASE_OPCODE(OPCODE::GETAI, "GETAI", FieldModelInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::ANIM_2, "ANIM!2", FieldModelInstruction, 0, "BB");
+            CASE_OPCODE(OPCODE::CANIM2, "CANIM2", FieldModelInstruction, 0, "BBBB");
+            CASE_OPCODE(OPCODE::CANM_2, "CANM!2", FieldModelInstruction, 0, "BBBB");
+            CASE_OPCODE(OPCODE::ASPED, "ASPED", FieldModelInstruction, 0, "Nw");
+            CASE_OPCODE(OPCODE::CC, "CC", FieldModelInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::JUMP, "JUMP", FieldModelInstruction, 0, "NNssww");
+            CASE_OPCODE(OPCODE::AXYZI, "AXYZI", FieldModelInstruction, 0, "NNBBBBB");
+            CASE_OPCODE(OPCODE::LADER, "LADER", FieldModelInstruction, 0, "NNssswBBBB");
+            CASE_OPCODE(OPCODE::OFST, "OFST", FieldModelInstruction, 0, "NNBsssw");
+            CASE_OPCODE(OPCODE::OFSTW, "OFSTW", FieldModelInstruction, 0, "");
+            CASE_OPCODE(OPCODE::TALKR, "TALKR", FieldModelInstruction, 0, "NB");
+            CASE_OPCODE(OPCODE::SLIDR, "SLIDR", FieldModelInstruction, 0, "NB");
+            CASE_OPCODE(OPCODE::SOLID, "SOLID", FieldModelInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::TLKR2, "TLKR2", FieldModelInstruction, 0, "Nw");
+            CASE_OPCODE(OPCODE::SLDR2, "SLDR2", FieldModelInstruction, 0, "Nw");
+            CASE_OPCODE(OPCODE::CCANM, "CCANM", FieldModelInstruction, 0, "BBB");
+            CASE_OPCODE(OPCODE::FCFIX, "FCFIX", FieldModelInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::ANIMB, "ANIMB", FieldModelInstruction, 0, "");
+            CASE_OPCODE(OPCODE::TURNW, "TURNW", FieldModelInstruction, 0, "");
 
             // Walkmesh
-            CASE_OPCODE(OPCODE::SLIP, "SLIP", FF7WalkmeshInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::UC, "UC", FF7WalkmeshInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::IDLCK, "IDLCK", FF7WalkmeshInstruction, 0, "wB");
-            CASE_OPCODE(OPCODE::LINON, "LINON", FF7WalkmeshInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::SLINE, "SLINE", FF7WalkmeshInstruction, 0, "NNNssssss");
-            //CASE_OPCODE(OPCODE::LINE, "LINE", FF7WalkmeshInstruction, 0, "ssssss");
+            CASE_OPCODE(OPCODE::SLIP, "SLIP", FieldWalkmeshInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::UC, "UC", FieldWalkmeshInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::IDLCK, "IDLCK", FieldWalkmeshInstruction, 0, "wB");
+            CASE_OPCODE(OPCODE::LINON, "LINON", FieldWalkmeshInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::SLINE, "SLINE", FieldWalkmeshInstruction, 0, "NNNssssss");
+            //CASE_OPCODE(OPCODE::LINE, "LINE", FieldWalkmeshInstruction, 0, "ssssss");
             // LINE is done like this to save opcode params to the function out params.
             case OPCODE::LINE:
                 is_line = true;
                 full_opcode = (full_opcode << 8) + OPCODE::LINE;
-                this->_insts.push_back(new FF7WalkmeshInstruction());
+                this->_insts.push_back(new FieldWalkmeshInstruction());
                 (this->_insts.back())->_opcode = full_opcode;
                 (this->_insts.back())->_address = this->address_;
                 (this->_insts.back())->_stackChange = 0;
@@ -628,66 +651,66 @@ bool FieldDisassembler::ReadOpCodesToPositionOrReturn(
                 break;
 
             // Backgnd
-            CASE_OPCODE(OPCODE::BGPDH, "BGPDH", FF7BackgroundInstruction, 0, "NBs");
-            CASE_OPCODE(OPCODE::BGSCR, "BGSCR", FF7BackgroundInstruction, 0, "NBss");
-            CASE_OPCODE(OPCODE::MPPAL, "MPPAL", FF7BackgroundInstruction, 0, "NNNBBBBBBB");
-            CASE_OPCODE(OPCODE::BGON, "BGON", FF7BackgroundInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::BGOFF, "BGOFF", FF7BackgroundInstruction, 0, "NBB");
-            CASE_OPCODE(OPCODE::BGROL, "BGROL", FF7BackgroundInstruction, 0, "NB");
-            CASE_OPCODE(OPCODE::BGROL2, "BGROL2", FF7BackgroundInstruction, 0, "NB");
-            CASE_OPCODE(OPCODE::BGCLR, "BGCLR", FF7BackgroundInstruction, 0, "NB");
-            CASE_OPCODE(OPCODE::STPAL, "STPAL", FF7BackgroundInstruction, 0, "NBBB");
-            CASE_OPCODE(OPCODE::LDPAL, "LDPAL", FF7BackgroundInstruction, 0, "NBBB");
-            CASE_OPCODE(OPCODE::CPPAL, "CPPAL", FF7BackgroundInstruction, 0, "NBBB");
-            CASE_OPCODE(OPCODE::RTPAL, "RTPAL", FF7BackgroundInstruction, 0, "NNBBBB");
-            CASE_OPCODE(OPCODE::ADPAL, "ADPAL", FF7BackgroundInstruction, 0, "NNNBBBBBB");
-            CASE_OPCODE(OPCODE::MPPAL2, "MPPAL2", FF7BackgroundInstruction, 0, "NNNBBBBBB");
-            CASE_OPCODE(OPCODE::STPLS, "STPLS", FF7BackgroundInstruction, 0, "BBBB");
-            CASE_OPCODE(OPCODE::LDPLS, "LDPLS", FF7BackgroundInstruction, 0, "BBBB");
-            CASE_OPCODE(OPCODE::CPPAL2, "CPPAL2", FF7BackgroundInstruction, 0, "BBBBBBB");
-            CASE_OPCODE(OPCODE::RTPAL2, "RTPAL2", FF7BackgroundInstruction, 0, "BBBBBBB");
-            CASE_OPCODE(OPCODE::ADPAL2, "ADPAL2", FF7BackgroundInstruction, 0, "BBBBBBBBBB");
+            CASE_OPCODE(OPCODE::BGPDH, "BGPDH", FieldBackgroundInstruction, 0, "NBs");
+            CASE_OPCODE(OPCODE::BGSCR, "BGSCR", FieldBackgroundInstruction, 0, "NBss");
+            CASE_OPCODE(OPCODE::MPPAL, "MPPAL", FieldBackgroundInstruction, 0, "NNNBBBBBBB");
+            CASE_OPCODE(OPCODE::BGON, "BGON", FieldBackgroundInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::BGOFF, "BGOFF", FieldBackgroundInstruction, 0, "NBB");
+            CASE_OPCODE(OPCODE::BGROL, "BGROL", FieldBackgroundInstruction, 0, "NB");
+            CASE_OPCODE(OPCODE::BGROL2, "BGROL2", FieldBackgroundInstruction, 0, "NB");
+            CASE_OPCODE(OPCODE::BGCLR, "BGCLR", FieldBackgroundInstruction, 0, "NB");
+            CASE_OPCODE(OPCODE::STPAL, "STPAL", FieldBackgroundInstruction, 0, "NBBB");
+            CASE_OPCODE(OPCODE::LDPAL, "LDPAL", FieldBackgroundInstruction, 0, "NBBB");
+            CASE_OPCODE(OPCODE::CPPAL, "CPPAL", FieldBackgroundInstruction, 0, "NBBB");
+            CASE_OPCODE(OPCODE::RTPAL, "RTPAL", FieldBackgroundInstruction, 0, "NNBBBB");
+            CASE_OPCODE(OPCODE::ADPAL, "ADPAL", FieldBackgroundInstruction, 0, "NNNBBBBBB");
+            CASE_OPCODE(OPCODE::MPPAL2, "MPPAL2", FieldBackgroundInstruction, 0, "NNNBBBBBB");
+            CASE_OPCODE(OPCODE::STPLS, "STPLS", FieldBackgroundInstruction, 0, "BBBB");
+            CASE_OPCODE(OPCODE::LDPLS, "LDPLS", FieldBackgroundInstruction, 0, "BBBB");
+            CASE_OPCODE(OPCODE::CPPAL2, "CPPAL2", FieldBackgroundInstruction, 0, "BBBBBBB");
+            CASE_OPCODE(OPCODE::RTPAL2, "RTPAL2", FieldBackgroundInstruction, 0, "BBBBBBB");
+            CASE_OPCODE(OPCODE::ADPAL2, "ADPAL2", FieldBackgroundInstruction, 0, "BBBBBBBBBB");
 
             // Camera
-            CASE_OPCODE(OPCODE::NFADE, "NFADE", FF7CameraInstruction, 0, "NNBBBBBB");
-            CASE_OPCODE(OPCODE::SHAKE, "SHAKE", FF7CameraInstruction, 0, "BBBBBBB");
-            CASE_OPCODE(OPCODE::SCRLO, "SCRLO", FF7CameraInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::SCRLC, "SCRLC", FF7CameraInstruction, 0, "BBBB");
-            CASE_OPCODE(OPCODE::SCRLA, "SCRLA", FF7CameraInstruction, 0, "NwBB");
-            CASE_OPCODE(OPCODE::SCR2D, "SCR2D", FF7CameraInstruction, 0, "Nss");
-            CASE_OPCODE(OPCODE::SCRCC, "SCRCC", FF7CameraInstruction, 0, "");
-            CASE_OPCODE(OPCODE::SCR2DC, "SCR2DC", FF7CameraInstruction, 0, "NNssw");
-            CASE_OPCODE(OPCODE::SCRLW, "SCRLW", FF7CameraInstruction, 0, "");
-            CASE_OPCODE(OPCODE::SCR2DL, "SCR2DL", FF7CameraInstruction, 0, "NNssw");
-            CASE_OPCODE(OPCODE::VWOFT, "VWOFT", FF7CameraInstruction, 0, "NssB");
-            CASE_OPCODE(OPCODE::FADE, "FADE", FF7CameraInstruction, 0, "NNBBBBBB");
-            CASE_OPCODE(OPCODE::FADEW, "FADEW", FF7CameraInstruction, 0, "");
-            CASE_OPCODE(OPCODE::SCRLP, "SCRLP", FF7CameraInstruction, 0, "NwBB");
-            CASE_OPCODE(OPCODE::MVCAM, "MVCAM", FF7CameraInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::NFADE, "NFADE", FieldCameraInstruction, 0, "NNBBBBBB");
+            CASE_OPCODE(OPCODE::SHAKE, "SHAKE", FieldCameraInstruction, 0, "BBBBBBB");
+            CASE_OPCODE(OPCODE::SCRLO, "SCRLO", FieldCameraInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::SCRLC, "SCRLC", FieldCameraInstruction, 0, "BBBB");
+            CASE_OPCODE(OPCODE::SCRLA, "SCRLA", FieldCameraInstruction, 0, "NwBB");
+            CASE_OPCODE(OPCODE::SCR2D, "SCR2D", FieldCameraInstruction, 0, "Nss");
+            CASE_OPCODE(OPCODE::SCRCC, "SCRCC", FieldCameraInstruction, 0, "");
+            CASE_OPCODE(OPCODE::SCR2DC, "SCR2DC", FieldCameraInstruction, 0, "NNssw");
+            CASE_OPCODE(OPCODE::SCRLW, "SCRLW", FieldCameraInstruction, 0, "");
+            CASE_OPCODE(OPCODE::SCR2DL, "SCR2DL", FieldCameraInstruction, 0, "NNssw");
+            CASE_OPCODE(OPCODE::VWOFT, "VWOFT", FieldCameraInstruction, 0, "NssB");
+            CASE_OPCODE(OPCODE::FADE, "FADE", FieldCameraInstruction, 0, "NNBBBBBB");
+            CASE_OPCODE(OPCODE::FADEW, "FADEW", FieldCameraInstruction, 0, "");
+            CASE_OPCODE(OPCODE::SCRLP, "SCRLP", FieldCameraInstruction, 0, "NwBB");
+            CASE_OPCODE(OPCODE::MVCAM, "MVCAM", FieldCameraInstruction, 0, "B");
 
             // AV
-            CASE_OPCODE(OPCODE::BGMOVIE, "BGMOVIE", FF7AudioVideoInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::AKAO2, "AKAO2", FF7AudioVideoInstruction, 0, "NNNBwwwww");
-            CASE_OPCODE(OPCODE::MUSIC, "MUSIC", FF7AudioVideoInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::SOUND, "SOUND", FF7AudioVideoInstruction, 0, "NwB");
-            CASE_OPCODE(OPCODE::AKAO, "AKAO", FF7AudioVideoInstruction, 0, "NNNBBwwww");
-            CASE_OPCODE(OPCODE::MUSVT, "MUSVT", FF7AudioVideoInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::MUSVM, "MUSVM", FF7AudioVideoInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::MULCK, "MULCK", FF7AudioVideoInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::BMUSC, "BMUSC", FF7AudioVideoInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::CHMPH, "CHMPH", FF7AudioVideoInstruction, 0, "BBB");
-            CASE_OPCODE(OPCODE::PMVIE, "PMVIE", FF7AudioVideoInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::MOVIE, "MOVIE", FF7AudioVideoInstruction, 0, "");
-            CASE_OPCODE(OPCODE::MVIEF, "MVIEF", FF7AudioVideoInstruction, 0, "NB");
-            CASE_OPCODE(OPCODE::FMUSC, "FMUSC", FF7AudioVideoInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::CMUSC, "CMUSC", FF7AudioVideoInstruction, 0, "BBBBBBB");
-            CASE_OPCODE(OPCODE::CHMST, "CHMST", FF7AudioVideoInstruction, 0, "NB");
+            CASE_OPCODE(OPCODE::BGMOVIE, "BGMOVIE", FieldMediaInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::AKAO2, "AKAO2", FieldMediaInstruction, 0, "NNNBwwwww");
+            CASE_OPCODE(OPCODE::MUSIC, "MUSIC", FieldMediaInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::SOUND, "SOUND", FieldMediaInstruction, 0, "NwB");
+            CASE_OPCODE(OPCODE::AKAO, "AKAO", FieldMediaInstruction, 0, "NNNBBwwww");
+            CASE_OPCODE(OPCODE::MUSVT, "MUSVT", FieldMediaInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::MUSVM, "MUSVM", FieldMediaInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::MULCK, "MULCK", FieldMediaInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::BMUSC, "BMUSC", FieldMediaInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::CHMPH, "CHMPH", FieldMediaInstruction, 0, "BBB");
+            CASE_OPCODE(OPCODE::PMVIE, "PMVIE", FieldMediaInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::MOVIE, "MOVIE", FieldMediaInstruction, 0, "");
+            CASE_OPCODE(OPCODE::MVIEF, "MVIEF", FieldMediaInstruction, 0, "NB");
+            CASE_OPCODE(OPCODE::FMUSC, "FMUSC", FieldMediaInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::CMUSC, "CMUSC", FieldMediaInstruction, 0, "BBBBBBB");
+            CASE_OPCODE(OPCODE::CHMST, "CHMST", FieldMediaInstruction, 0, "NB");
 
             // Uncat
-            CASE_OPCODE(OPCODE::MPDSP, "MPDSP", FF7UncategorizedInstruction, 0, "B");
-            CASE_OPCODE(OPCODE::SETX, "SETX", FF7UncategorizedInstruction, 0, "BBBBBB");
-            CASE_OPCODE(OPCODE::GETX, "GETX", FF7UncategorizedInstruction, 0, "BBBBBB");
-            CASE_OPCODE(OPCODE::SEARCHX, "SEARCHX", FF7UncategorizedInstruction, 0, "BBBBBBBBBB");
+            CASE_OPCODE(OPCODE::MPDSP, "MPDSP", FieldUncategorizedInstruction, 0, "B");
+            CASE_OPCODE(OPCODE::SETX, "SETX", FieldUncategorizedInstruction, 0, "BBBBBB");
+            CASE_OPCODE(OPCODE::GETX, "GETX", FieldUncategorizedInstruction, 0, "BBBBBB");
+            CASE_OPCODE(OPCODE::SEARCHX, "SEARCHX", FieldUncategorizedInstruction, 0, "BBBBBBBBBB");
 
             default:
                 throw UnknownOpcodeException(this->address_, opcode);
@@ -696,7 +719,7 @@ bool FieldDisassembler::ReadOpCodesToPositionOrReturn(
 
         // Is it within an "if" statement tracking?
         InstPtr i = this->_insts.back();
-        if (i->isCondJump()) exitAddrs.push_back(i->getDestAddress());
+        if (i->isCondJump()) exitAddrs.push_back(i->GetDestAddress());
         if (!exitAddrs.empty())
             if (i->_address == exitAddrs.back()) exitAddrs.pop_back();
 

+ 309 - 0
V-Gears-Installer/src/decompiler/field/FieldEngine.cpp

@@ -0,0 +1,309 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <iostream>
+#include <sstream>
+#include <boost/format.hpp>
+#include "decompiler/field/FieldEngine.h"
+#include "decompiler/field/FieldCodeGenerator.h"
+#include "decompiler/field/FieldDisassembler.h"
+#include "decompiler/field/instruction/FieldNoOperationInstruction.h"
+
+#define GET(vertex) (boost::get(boost::vertex_name, g, vertex))
+
+/*
+OpCodes which need implementing (already done in DAT dumper)
+
+"BLINK"
+"XYI"
+"CMOVE"
+"MOVA"
+"TURA"
+"ANIMW"
+"FMOVE"
+"ANIME2"
+"ANIM_1"
+"CANIM1" ?
+"CANM_1"
+"TURN"
+"DIRA"
+"GETDIR"
+"GETAXY"
+"JUMP"
+"AXYZI"
+"LADER"
+"OFST"
+"TALKR"
+"ANIMB"
+"TURNW"
+*/
+
+FieldEngine::FieldEngine(SUDM::IScriptFormatter& formatter, std::string script_name) :
+mFormatter(formatter), script_name_(script_name)
+{setOutputStackEffect(false);}
+
+FieldEngine::Entity::Entity(const std::string& name, size_t index):
+  name_(name), index_(index), is_line_(false)
+{}
+
+std::string FieldEngine::Entity::GetName() const{return name_;}
+
+size_t FieldEngine::Entity::GetIndex() const{return index_;}
+
+std::string FieldEngine::Entity::FunctionByIndex(size_t index) const{
+    auto it = functions_.find(index);
+    if (it == std::end(functions_)) throw InternalDecompilerError();
+    return it->second;
+}
+
+void FieldEngine::Entity::AddFunction(const std::string& name, size_t index){
+    functions_[index] = name;
+}
+
+void FieldEngine::Entity::MarkAsLine(
+  bool line, std::vector<float> point_a, std::vector<float> point_b
+){
+    is_line_ = line;
+    point_a_.clear();
+    point_b_.clear();
+    if (line){
+        if (point_a.size() >= 3 && point_b.size() >= 3){
+            point_a_.push_back(point_a[0]);
+            point_a_.push_back(point_a[1]);
+            point_a_.push_back(point_a[2]);
+            point_b_.push_back(point_b[0]);
+            point_b_.push_back(point_b[1]);
+            point_b_.push_back(point_b[2]);
+        }
+        // TODO: Notify on else.
+    }
+    // TODO: These are not getting to the final script.
+    // Maybe this can be removed?
+    AddFunction("on_enter_line", 1);
+    AddFunction("on_move_to_line", 2);
+    AddFunction("on_cross_line", 3);
+    AddFunction("on_leave_line", 4);
+}
+
+bool FieldEngine::Entity::IsLine(){return is_line_;}
+
+std::vector<float> FieldEngine::Entity::GetLinePointA(){return point_a_;}
+
+std::vector<float> FieldEngine::Entity::GetLinePointB(){return point_b_;}
+
+std::unique_ptr<Disassembler> FieldEngine::GetDisassembler(
+  InstVec &insts, const std::vector<unsigned char>& raw_script_data
+){
+    auto ret = std::make_unique<FieldDisassembler>(mFormatter, this, insts, raw_script_data);
+    scale_factor_ = ret->GetScaleFactor();
+    return std::move(ret);
+}
+
+std::unique_ptr<Disassembler> FieldEngine::GetDisassembler(InstVec &insts){
+    auto ret = std::make_unique<FieldDisassembler>(mFormatter, this, insts);
+    scale_factor_ = ret->GetScaleFactor();
+    return std::move(ret);
+}
+
+std::unique_ptr<CodeGenerator> FieldEngine::GetCodeGenerator(
+  const InstVec& insts, std::ostream &output
+){
+    // The broken version:
+    //return std::make_unique<FF7CodeGenerator>(this, insts, output);
+    // The not-as-nice-but-at-least-it-works version:
+    return std::make_unique<FieldCodeGenerator>(this, insts, output, mFormatter);
+}
+
+void FieldEngine::PostCFG(InstVec& insts, Graph graph){
+
+    // In FF7 some scripts ends with an infinite loop to "keep it alive"
+    // in VGears this isn't required so we can remove them
+    //RemoveTrailingInfiniteLoops(insts, graph);
+
+    // This could generate bad code, but it always seems to follow that pattern that if the last
+    // instruction is an uncond jump back into the script then it simply nests all of those blocks
+    // in an infinite loop
+    //MarkInfiniteLoopGroups(insts, graph);
+
+    // Scripts end with a "return" this isn't required so strip them out
+    //RemoveExtraneousReturnStatements(insts, graph);
+}
+
+bool FieldEngine::UsePureGrouping() const{return false;}
+
+std::map<std::string, int> FieldEngine::GetEntities() const{
+    std::map<std::string, int> r;
+    for (auto& f : _functions){
+        const Function& func = f.second;
+        FunctionMetaData meta(func._metadata);
+        auto it = r.find(meta.GetEntityName());
+        if (it != std::end(r)){
+            // Try to find a function in this entity has that has a char id
+            // don't overwrite a valid char id with a "blank" one.
+            if (it->second == -1) it->second = meta.GetCharacterId();
+        }
+        // TODO: Don't add lines here:
+        else r[meta.GetEntityName()] = meta.GetCharacterId();
+    }
+    return r;
+}
+
+std::vector<SUDM::Field::FieldEntity> FieldEngine::GetEntityList() const{
+    std::vector<SUDM::Field::FieldEntity> entities;
+    for (auto entity: entity_index_map_){
+        if (entity.second.IsLine() == false){
+            SUDM::Field::FieldEntity ent;
+            ent.name = entity.second.GetName();
+            ent.index = entity.second.GetIndex();
+
+            // Get character ID.
+            ent.char_id = -1;
+            std::map<std::string, int> r;
+            for (auto& f : _functions){
+                const Function& func = f.second;
+                FunctionMetaData meta(func._metadata);
+                if (meta.GetEntityName() == ent.name){
+                    ent.char_id = meta.GetCharacterId();
+                    break;
+                }
+            }
+            entities.push_back(ent);
+        }
+    }
+    return entities;
+}
+
+std::vector<SUDM::Field::Line> FieldEngine::GetLineList() const{
+    std::vector<SUDM::Field::Line> lines;
+    for (auto entity: entity_index_map_){
+        if (entity.second.IsLine() == true){
+            SUDM::Field::Line line;
+            line.name = entity.second.GetName();
+            line.point_a = entity.second.GetLinePointA();
+            line.point_b = entity.second.GetLinePointB();
+            lines.push_back(line);
+        }
+    }
+    return lines;
+}
+
+void FieldEngine::AddEntityFunction(
+  const std::string& entity_name, size_t entity_index,
+  const std::string& func_name, size_t func_index
+){
+    auto it = entity_index_map_.find(entity_index);
+    if (it != std::end(entity_index_map_)) (*it).second.AddFunction(func_name, func_index);
+    else{
+        Entity e(entity_name, entity_index);
+        e.AddFunction(func_name, func_index);
+        entity_index_map_.insert(std::make_pair(entity_index, e));
+    }
+}
+
+void FieldEngine::MarkEntityAsLine(
+  size_t entity_index, bool line, std::vector<float> point_a, std::vector<float> point_b
+){
+    auto it = entity_index_map_.find(entity_index);
+    if (it != std::end(entity_index_map_)){
+        (*it).second.MarkAsLine(line, point_a, point_b);
+    }
+}
+
+bool FieldEngine::EntityIsLine(size_t entity_index){
+    auto it = entity_index_map_.find(entity_index);
+    if (it != std::end(entity_index_map_)) return (*it).second.IsLine();
+    return false;
+}
+
+const FieldEngine::Entity& FieldEngine::EntityByIndex(size_t index) const{
+    auto it = entity_index_map_.find(index);
+    if (it == std::end(entity_index_map_)) throw InternalDecompilerError();
+    return it->second;
+}
+
+float FieldEngine::GetScaleFactor() const {return scale_factor_;}
+
+const std::string& FieldEngine::ScriptName() const {return script_name_;}
+
+void FieldEngine::RemoveExtraneousReturnStatements(InstVec& insts, Graph g){
+    for (auto& f : _functions){
+        Function& func = f.second;
+        for (auto it = insts.begin(); it != insts.end(); it ++){
+            // Is it the last instruction in the function, and is it a return statement?
+            if ((*it)->_address == func.mEndAddr){
+                if ((*it)->_opcode == OPCODE::RET){
+                    // Set new end address to be before the NOP.
+                    func.mEndAddr = (*(it - 1))->_address;
+                    func.mNumInstructions --;
+                    Instruction* nop = new FieldNoOperationInstruction();
+                    nop->_opcode = OPCODE::NOP;
+                    nop->_address = (*it)->_address;
+                    (*it).reset(nop);
+                    break;
+                }
+            }
+        }
+    }
+}
+
+void FieldEngine::RemoveTrailingInfiniteLoops(InstVec& insts, Graph g){
+    for (auto& f : _functions){
+        Function& func = f.second;
+        for (auto it = insts.begin(); it != insts.end(); it ++){
+            // Is it the last instruction in the function, a jump, and a jumping to itself?
+            if ((*it)->_address == func.mEndAddr){
+                if ((*it)->isJump() && (*it)->GetDestAddress() == (*it)->_address){
+                    // Set new end address to be before the NOP
+                    func.mEndAddr = (*(it - 1))->_address;
+                    func.mNumInstructions--;
+                    Instruction* nop = new FieldNoOperationInstruction();
+                    nop->_opcode = OPCODE::NOP;
+                    nop->_address = (*it)->_address;
+                    (*it).reset(nop);
+                    break;
+                }
+            }
+        }
+    }
+}
+
+void FieldEngine::MarkInfiniteLoopGroups(InstVec& insts, Graph g){
+    for (auto& f : _functions){
+        Function& func = f.second;
+        for (auto it = insts.begin(); it != insts.end(); it ++){
+            if ((*it)->_address == func.mEndAddr){
+                // Note: This is a "best effort heuristic", so quite a few loops will
+                // still end up as goto's. This could potentially generate invalid code too.
+                if ((*it)->IsUncondJump()){
+                    // Then assume its an infinite do { } while(true)
+                    // loop that wraps part of the script.
+                    VertexRange vr = boost::vertices(g);
+                    for (VertexIterator v = vr.first; v != vr.second; ++ v){
+                        GroupPtr gr = GET(*v);
+                        if ((*gr->_start)->_address == func.mEndAddr){
+                            // Then assume its an infinite do { } while(true) loop
+                            // that wraps part of the script.
+                            gr->_type = kDoWhileCondGroupType;
+                        }
+                    }
+                }
+                break;
+            }
+        }
+    }
+}

+ 0 - 1969
V-Gears-Installer/src/decompiler/field/ff7_field_engine.cpp

@@ -1,1969 +0,0 @@
-#include "decompiler/field/ff7_field_engine.h"
-#include <iostream>
-#include <sstream>
-#include <boost/format.hpp>
-#include "../../../include/decompiler/field/FieldCodeGenerator.h"
-#include "../../../include/decompiler/field/FieldDisassembler.h"
-
-#define GET(vertex) (boost::get(boost::vertex_name, g, vertex))
-
-/*
-OpCodes which need implementing (already done in DAT dumper)
-
-"BLINK"
-"XYI"
-"CMOVE"
-"MOVA"
-"TURA"
-"ANIMW"
-"FMOVE"
-"ANIME2"
-"ANIM_1"
-"CANIM1" ?
-"CANM_1"
-"TURN"
-"DIRA"
-"GETDIR"
-"GETAXY"
-"JUMP"
-"AXYZI"
-"LADER"
-"OFST"
-"TALKR"
-"ANIMB"
-"TURNW"
-*/
-
-std::unique_ptr<Disassembler> FF7FieldEngine::getDisassembler(
-  InstVec &insts, const std::vector<unsigned char>& raw_script_data
-){
-    auto ret = std::make_unique<FieldDisassembler>(mFormatter, this, insts, raw_script_data);
-    scale_factor_ = ret->GetScaleFactor();
-    return std::move(ret);
-}
-
-std::unique_ptr<Disassembler> FF7FieldEngine::getDisassembler(InstVec &insts){
-    auto ret = std::make_unique<FieldDisassembler>(mFormatter, this, insts);
-    scale_factor_ = ret->GetScaleFactor();
-    return std::move(ret);
-}
-
-std::unique_ptr<CodeGenerator> FF7FieldEngine::getCodeGenerator(
-  const InstVec& insts, std::ostream &output
-){
-    // The broken version:
-    //return std::make_unique<FF7CodeGenerator>(this, insts, output);
-    // The not-as-nice-but-at-least-it-works version:
-    return std::make_unique<FieldCodeGenerator>(this, insts, output, mFormatter);
-}
-
-void FF7FieldEngine::postCFG(InstVec& insts, Graph g){
-    /*
-    // In FF7 some scripts ends with an infinite loop to "keep it alive"
-    // in VGears this isn't required so we can remove them
-    RemoveTrailingInfiniteLoops(insts, g);
-
-    // This could generate bad code, but it always seems to follow that pattern that if the last
-    // instruction is an uncond jump back into the script then it simply nests all of those blocks
-    // in an infinite loop
-    MarkInfiniteLoopGroups(insts, g);
-
-    // Scripts end with a "return" this isn't required so strip them out
-    RemoveExtraneousReturnStatements(insts, g);
-    */
-}
-
-std::map<std::string, int> FF7FieldEngine::GetEntities() const{
-    std::map<std::string, int> r;
-    for (auto& f : _functions){
-        const Function& func = f.second;
-        FunctionMetaData meta(func._metadata);
-        auto it = r.find(meta.GetEntityName());
-        if (it != std::end(r)){
-            // Try to find a function in this entity has that has a char id
-            // don't overwrite a valid char id with a "blank" one
-            if (it->second == -1) it->second = meta.GetCharacterId();
-        }
-        // TODO: Don't add lines here:
-        else r[meta.GetEntityName()] = meta.GetCharacterId();
-    }
-    return r;
-}
-
-std::vector<SUDM::Field::FieldEntity> FF7FieldEngine::GetEntityList() const{
-    std::vector<SUDM::Field::FieldEntity> entities;
-    for (auto entity: mEntityIndexMap){
-        if (entity.second.IsLine() == false){
-            SUDM::Field::FieldEntity ent;
-            ent.name = entity.second.Name();
-            ent.index = entity.second.GetIndex();
-
-            // Get character ID.
-            ent.char_id = -1;
-            std::map<std::string, int> r;
-            //if (ent.name == "Cloud") std::cout << "CHAR_ID FOR CLOUD" << std::endl;
-            for (auto& f : _functions){
-
-                const Function& func = f.second;
-                FunctionMetaData meta(func._metadata);
-                if (meta.GetEntityName() == ent.name){
-                    ent.char_id = meta.GetCharacterId();
-                    break;
-                }
-            }
-            entities.push_back(ent);
-        }
-    }
-    return entities;
-}
-
-std::vector<SUDM::Field::Line> FF7FieldEngine::GetLineList() const{
-    std::vector<SUDM::Field::Line> lines;
-    for (auto entity: mEntityIndexMap){
-        if (entity.second.IsLine() == true){
-            SUDM::Field::Line line;
-            line.name = entity.second.Name();
-            line.point_a = entity.second.GetLinePointA();
-            line.point_b = entity.second.GetLinePointB();
-            lines.push_back(line);
-        }
-    }
-    return lines;
-}
-
-void FF7FieldEngine::AddEntityFunction(
-  const std::string& entity_name, size_t entity_index,
-  const std::string& func_name, size_t func_index
-){
-    auto it = mEntityIndexMap.find(entity_index);
-    if (it != std::end(mEntityIndexMap)) (*it).second.AddFunction(func_name, func_index);
-    else{
-        Entity e(entity_name, entity_index);
-        e.AddFunction(func_name, func_index);
-        mEntityIndexMap.insert(std::make_pair(entity_index, e));
-    }
-}
-
-void FF7FieldEngine::MarkEntityAsLine(
-  size_t entity_index, bool line, std::vector<float> point_a, std::vector<float> point_b
-){
-    auto it = mEntityIndexMap.find(entity_index);
-    if (it != std::end(mEntityIndexMap)){
-        (*it).second.MarkAsLine(line, point_a, point_b);
-    }
-}
-
-bool FF7FieldEngine::EntityIsLine(size_t entity_index){
-    auto it = mEntityIndexMap.find(entity_index);
-    if (it != std::end(mEntityIndexMap)) return (*it).second.IsLine();
-    return false;
-}
-
-void FF7FieldEngine::RemoveExtraneousReturnStatements(InstVec& insts, Graph g){
-    for (auto& f : _functions){
-        Function& func = f.second;
-        for (auto it = insts.begin(); it != insts.end(); it ++){
-            // Is it the last instruction in the function, and is it a return statement?
-            if ((*it)->_address == func.mEndAddr){
-                if ((*it)->_opcode == OPCODE::RET){
-                    // Set new end address to be before the NOP.
-                    func.mEndAddr = (*(it - 1))->_address;
-                    func.mNumInstructions --;
-                    Instruction* nop = new FF7NoOperationInstruction();
-                    nop->_opcode = OPCODE::NOP;
-                    nop->_address = (*it)->_address;
-                    (*it).reset(nop);
-                    break;
-                }
-            }
-        }
-    }
-}
-
-void FF7FieldEngine::RemoveTrailingInfiniteLoops(InstVec& insts, Graph g){
-    for (auto& f : _functions){
-        Function& func = f.second;
-        for (auto it = insts.begin(); it != insts.end(); it ++){
-            // Is it the last instruction in the function, a jump, and a jumping to itself?
-            if ((*it)->_address == func.mEndAddr){
-                if ((*it)->isJump() && (*it)->getDestAddress() == (*it)->_address){
-                    // Set new end address to be before the NOP
-                    func.mEndAddr = (*(it - 1))->_address;
-                    func.mNumInstructions--;
-                    Instruction* nop = new FF7NoOperationInstruction();
-                    nop->_opcode = OPCODE::NOP;
-                    nop->_address = (*it)->_address;
-                    (*it).reset(nop);
-                    break;
-                }
-            }
-        }
-    }
-}
-
-void FF7FieldEngine::MarkInfiniteLoopGroups(InstVec& insts, Graph g){
-    for (auto& f : _functions){
-        Function& func = f.second;
-        for (auto it = insts.begin(); it != insts.end(); it ++){
-            if ((*it)->_address == func.mEndAddr){
-                // Note: This is a "best effort heuristic", so quite a few loops will
-                // still end up as goto's. This could potentially generate invalid code too.
-                if ((*it)->isUncondJump()){
-                    // Then assume its an infinite do { } while(true)
-                    // loop that wraps part of the script.
-                    VertexRange vr = boost::vertices(g);
-                    for (VertexIterator v = vr.first; v != vr.second; ++ v){
-                        GroupPtr gr = GET(*v);
-                        if ((*gr->_start)->_address == func.mEndAddr){
-                            // Then assume its an infinite do { } while(true) loop
-                            // that wraps part of the script.
-                            gr->_type = kDoWhileCondGroupType;
-                        }
-                    }
-                }
-                break;
-            }
-        }
-    }
-}
-
-void FF7CondJumpInstruction::processInst(
-  Function& function, ValueStack &stack, Engine* engine, CodeGenerator* code_gen
-){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-
-    std::string funcName;
-    if (_opcode == OPCODE::IFKEYON) funcName = "entity_manager:is_key_on";
-    else if (_opcode == OPCODE::IFKEYOFF) funcName = "entity_manager:is_key_off";
-    else if (_opcode == OPCODE::IFKEY) funcName = "Key";
-    else if (_opcode == OPCODE::IFMEMBQ) funcName = "IFMEMBQ";
-    else if (_opcode == OPCODE::IFPRTYQ) funcName = "IFPRTYQ";
-
-    // If condition is a function, add and stop.
-    if (!funcName.empty()){
-
-        uint32 param = _params[0]->getUnsigned();
-
-        // Special cases. The first parameter of IFKEY, IFKEYON and IFKEYOFF
-        // can be ORed to get the individual keys, but there are two invalid
-        // ones: 512 and 1024. They must be XORed.
-        if (
-          _opcode == OPCODE::IFKEY
-          || _opcode == OPCODE::IFKEYON
-          || _opcode == OPCODE::IFKEYOFF
-        ){
-            if (param >= 1024) param = param ^ 1024;
-            if (param >= 512) param = param ^ 512;
-        }
-
-        ValuePtr v = new UnqotedStringValue(funcName + "(" + std::to_string(param) + ")");
-        stack.push(v);
-        return;
-    }
-
-    std::string op;
-    uint32 type = _params[4]->getUnsigned();
-    const auto& source = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
-    );
-    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
-    );
-
-    switch (type){
-        case 0: op = "=="; break;
-        case 1: op = "~="; break;
-        case 2: op = ">"; break;
-        case 3: op = "<"; break;
-        case 4: op = ">="; break;
-        case 5: op = "<="; break;
-        case 6: op = "&"; break;
-        case 7: op = "^"; break;
-        case 8: op = "|"; break;
-        case 9:
-            {
-                op = "bit(" + _params[0]->getString() + ", " + _params[2]->getString()
-                  + ", " + destination + ") == 1";
-                ValuePtr v = new UnqotedStringValue(op);
-                stack.push(v);
-            }
-            return;
-        case 0xA:
-            {
-                op = "bit(" + _params[0]->getString() + ", " + _params[2]->getString()
-                  + ", " + destination + ") == 0";
-                ValuePtr v = new UnqotedStringValue(op);
-                stack.push(v);
-            }
-            return;
-        default: throw UnknownConditionalOperatorException(_address, type);
-    }
-
-    ValuePtr v = new BinaryOpValue(new VarValue(source), new VarValue(destination), op);
-    stack.push(v); 
-}
-
-uint32 FF7CondJumpInstruction::getDestAddress() const{
-    uint32 params_size = 0;
-    uint32 jump_param_index = 5;
-    switch (_opcode){
-        case OPCODE::IFUB: params_size = 5; break;
-        case OPCODE::IFUBL: params_size = 5; break;
-        case OPCODE::IFSW: params_size = 7; break;
-        case OPCODE::IFSWL: params_size = 7; break;
-        case OPCODE::IFUW: params_size = 7; break;
-        case OPCODE::IFUWL: params_size = 7; break;
-        case OPCODE::IFKEYON:
-        case OPCODE::IFKEYOFF:
-        case OPCODE::IFKEY:
-            params_size = 3;
-            jump_param_index = 1;
-            break;
-        case OPCODE::IFPRTYQ:
-        case OPCODE::IFMEMBQ:
-            params_size = 2;
-            jump_param_index = 1;
-            break;
-        default: throw UnknownJumpTypeException(_address, _opcode);
-    }
-    return _address + _params[jump_param_index]->getUnsigned() + params_size;
-}
-
-std::ostream& FF7CondJumpInstruction::print(std::ostream &output) const{
-    Instruction::print(output);
-    output << " (False target address: 0x" << std::hex << getDestAddress() << std::dec << ")";
-    return output;
-}
-
-bool FF7UncondJumpInstruction::isFuncCall() const{return _isCall;}
-
-bool FF7UncondJumpInstruction::isUncondJump() const{return !_isCall;}
-
-uint32 FF7UncondJumpInstruction::getDestAddress() const{
-    if (
-      static_cast<OPCODE>(_opcode) == OPCODE::JMPF
-      || static_cast<OPCODE>(_opcode) == OPCODE::JMPFL){
-        // Short or long forward jump.
-        return _address + _params[0]->getUnsigned() + 1;
-    }
-    // Backwards jump,  OPCODE::JMPB/L.
-    return _address - _params[0]->getUnsigned();
-}
-
-std::ostream& FF7UncondJumpInstruction::print(std::ostream &output) const{
-    Instruction::print(output);
-    output << " (Jump target address: 0x" << std::hex << getDestAddress() << std::dec << ")";
-    return output;
-}
-
-
-void FF7UncondJumpInstruction::processInst(
-  Function& func, ValueStack&, Engine* engine, CodeGenerator* code_gen
-){
-    switch (_opcode){
-        case OPCODE::JMPB:
-        case OPCODE::JMPBL:
-            // HACK: Hard loop will hang the game, insert a wait to yield control
-            code_gen->AddOutputLine("-- Hack, yield control for possible inf loop");
-            code_gen->AddOutputLine("script:wait(0)");
-            break;
-    }
-}
-
-static void WriteTodo(CodeGenerator *code_gen, std::string entity_name, std::string opCode){
-    code_gen->AddOutputLine("-- Todo(\"" + opCode + "\")");
-}
-
-void FF7ControlFlowInstruction::processInst(
-  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
-){
-    FF7FieldEngine& eng = static_cast<FF7FieldEngine&>(*engine);
-    FunctionMetaData md(func._metadata);
-    switch (_opcode){
-        case OPCODE::RET:
-            // A few notes in RET.
-            // - Lua requires all functions to end with a return.
-            // - Lua doesn's like returns if not followed by an end.
-            // - Don't add a return statement to on_start functions.
-            //     Game 'init' and 'main' code is concatenated in V-Gears. If the
-            //     'main' return is kept, the code of 'main' is never executed.
-            //     There are safeguards forfunctions without a return in the end,
-            //     so it's OK not to include it here.
-            if (func._name != "on_start") code_gen->AddOutputLine("do return 0 end");
-            break;
-        case OPCODE::REQ: processREQ(code_gen, eng); break;
-        case OPCODE::REQSW: processREQSW(code_gen, eng); break;
-        case OPCODE::REQEW: processREQEW(code_gen, eng); break;
-        case OPCODE::PREQ: WriteTodo(code_gen, md.GetEntityName(), "PREQ"); break;
-        case OPCODE::PRQSW: WriteTodo(code_gen, md.GetEntityName(), "PRQSW"); break;
-        case OPCODE::PRQEW: WriteTodo(code_gen, md.GetEntityName(), "PRQEW"); break;
-        case OPCODE::RETTO: processRETTO(code_gen); break;
-        case OPCODE::WAIT: processWAIT(code_gen); break;
-        default:
-            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
-              md.GetEntityName(), _address, _opcode
-            ));
-    }
-}
-
-void FF7ControlFlowInstruction::processREQ(
-  CodeGenerator* code_gen, const FF7FieldEngine& engine
-){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& entity = engine.EntityByIndex(_params[0]->getSigned());
-    const auto& script_name = cg->GetFormatter().FunctionName(
-      entity.Name(), entity.FunctionByIndex(_params[2]->getUnsigned())
-    );
-    auto priority = _params[1]->getUnsigned();
-    code_gen->AddOutputLine((
-      boost::format("script:request(Script.ENTITY, \"%1%\", \"%2%\", %3%)")
-      % entity.Name() % script_name % priority
-    ).str());
-}
-
-void FF7ControlFlowInstruction::processREQSW(
-  CodeGenerator* code_gen, const FF7FieldEngine& engine
-){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& entity = engine.EntityByIndex(_params[0]->getSigned());
-    const auto& script_name = cg->GetFormatter().FunctionName(
-      entity.Name(), entity.FunctionByIndex(_params[2]->getUnsigned())
-    );
-    auto priority = _params[1]->getUnsigned();
-    code_gen->AddOutputLine((
-      boost::format("script:request_start_sync(Script.ENTITY, \"%1%\", \"%2%\", %3%)")
-      % entity.Name() % script_name % priority
-    ).str());
-}
-
-void FF7ControlFlowInstruction::processREQEW(
-  CodeGenerator* code_gen, const FF7FieldEngine& engine
-){
-    try{
-        FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-        const auto& entity = engine.EntityByIndex(_params[0]->getSigned());
-        const auto& script_name = cg->GetFormatter().FunctionName(
-          entity.Name(), entity.FunctionByIndex(_params[2]->getUnsigned())
-        );
-        auto priority = _params[1]->getUnsigned();
-        code_gen->AddOutputLine((
-          boost::format("script:request_end_sync(Script.ENTITY, \"%1%\", \"%2%\", %3%)")
-          % entity.Name() % script_name % priority
-        ).str());
-    }
-    catch (const InternalDecompilerError&){
-        code_gen->AddOutputLine((
-          boost::format("-- ERROR call to non existing function index %1%")
-          % _params[2]->getUnsigned()
-        ).str());
-    }
-}
-
-void FF7ControlFlowInstruction::processRETTO(CodeGenerator* code_gen){
-    auto entity_index = _params[0]->getUnsigned();
-    auto priority = _params[1]->getUnsigned();
-    code_gen->AddOutputLine((
-      boost::format("-- return_to(script_id_in_current_entity=%2%, priority=%1%)")
-      % entity_index % priority
-    ).str());
-}
-
-void FF7ControlFlowInstruction::processWAIT(CodeGenerator* code_gen){
-    code_gen->AddOutputLine((
-      boost::format("script:wait(%1%)") % (_params[0]->getUnsigned() / 30.0f)
-    ).str());
-}
-
-void FF7ModuleInstruction::processInst(
-  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
-){
-    FunctionMetaData md(func._metadata);
-    switch (_opcode){
-        case OPCODE::DSKCG: WriteTodo(code_gen, md.GetEntityName(), "DSKCG"); break;
-        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::ARROW:
-            code_gen->AddOutputLine((
-              boost::format("game:pointer_enable(%1%)")
-              % (_params[0]->getUnsigned() ? "true" : "false")
-            ).str());
-            break;
-        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::PNAME:
-            WriteTodo(code_gen, md.GetEntityName(), "PNAME");
-            break;
-        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::GMSPD:
-            WriteTodo(code_gen, md.GetEntityName(), "GMSPD");
-            break;
-        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::SMSPD:
-            WriteTodo(code_gen, md.GetEntityName(), "SMSPD");
-            break;
-        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::FLMAT:
-            code_gen->AddOutputLine("game:fill_materia()");
-            break;
-        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::FLITM:
-            WriteTodo(code_gen, md.GetEntityName(), "FLITM");
-            break;
-        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::BTLCK:
-            code_gen->AddOutputLine((
-              boost::format("game:battle_enable(%1%)")
-              % (_params[0]->getUnsigned() ? "true" : "false")
-            ).str());
-            break;
-        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::MVLCK:
-            code_gen->AddOutputLine((
-              boost::format("game:movie_enable(%1%)")
-              % (_params[0]->getUnsigned() ? "true" : "false")
-            ).str());
-            break;
-        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::SPCNM:
-            WriteTodo(code_gen, md.GetEntityName(), "SPCNM");
-            break;
-        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::RSGLB:
-            code_gen->AddOutputLine("game:global_reset()");
-            break;
-        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::CLITM:
-            WriteTodo(code_gen, md.GetEntityName(), "CLITM");
-            break;
-        case OPCODE::MINIGAME: WriteTodo(code_gen, md.GetEntityName(), "MINIGAME"); break;
-        case OPCODE::BTMD2: WriteTodo(code_gen, md.GetEntityName(), "BTMD2"); break;
-        case OPCODE::BTRLD: WriteTodo(code_gen, md.GetEntityName(), "BTRLD"); break;
-        case OPCODE::BTLTB: WriteTodo(code_gen, md.GetEntityName(), "BTLTB"); break;
-        case OPCODE::MAPJUMP: processMAPJUMP(code_gen, func); break;
-        case OPCODE::LSTMP: WriteTodo(code_gen, md.GetEntityName(), "LSTMP"); break;
-        case OPCODE::BATTLE: processBATTLE(code_gen); break;
-        case OPCODE::BTLON: processBTLON(code_gen); break;
-        case OPCODE::BTLMD: WriteTodo(code_gen, md.GetEntityName(), "BTLMD"); break;
-        case OPCODE::MPJPO:
-            // Gateway function will do nothing if this is set to true
-            code_gen->AddOutputLine(
-              std::string("FFVII.Data.DisableGateways=")
-              + (_params[0]->getUnsigned() ? "true" : "false")
-            );
-            break;
-        // Prepare to change map, don't need to output anything for this.
-        case OPCODE::PMJMP: code_gen->AddOutputLine("-- Prepare map change"); break;
-        // Prepare to change map, don't need to output anything for this,
-        // seems to be the same thing as PMJMP
-        case OPCODE::PMJMP2: code_gen->AddOutputLine("-- Prepare map change 2"); break;
-        case OPCODE::GAMEOVER: WriteTodo(code_gen, md.GetEntityName(), "GAMEOVER"); break;
-        default:
-            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
-              md.GetEntityName(), _address, _opcode
-            ));
-    }
-}
-
-void FF7ModuleInstruction::processBATTLE(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& battle_id = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[1]->getUnsigned()
-    );
-    code_gen->AddOutputLine((boost::format("entity_manager:battle_run(%1%)") % battle_id).str());
-}
-
-void FF7ModuleInstruction::processBTLON(CodeGenerator* code_gen){
-    code_gen->AddOutputLine((
-      boost::format("entity_manager:random_encounters_on(%1%)")
-      % FieldCodeGenerator::FormatInvertedBool(_params[0]->getUnsigned())
-    ).str());
-}
-
-void FF7ModuleInstruction::processMAPJUMP(CodeGenerator* code_gen, Function& func){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto target_map_id = _params[0]->getUnsigned();
-    FunctionMetaData md(func._metadata);
-    const std::string source_spawn_point_name
-      = cg->GetFormatter().SpawnPointName(target_map_id, md.GetEntityName(), func._name, _address);
-
-    cg->GetFormatter().AddSpawnPoint(
-      target_map_id, md.GetEntityName(), func._name, _address,
-      _params[1]->getSigned(), // X
-      _params[2]->getSigned(), // Y
-      _params[3]->getSigned(), // Walk mesh triangle ID
-      _params[4]->getSigned()  // Angle
-    );
-
-    const std::string target_map_name = cg->GetFormatter().MapName(target_map_id);
-    code_gen->AddOutputLine(
-      "load_field_map_request(\"" + target_map_name + "\", \"" + source_spawn_point_name + "\")"
-    );
-}
-
-void FF7MathInstruction::processInst(
-  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
-){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    FunctionMetaData md(func._metadata);
-    switch (_opcode){
-        case OPCODE::PLUS_: processSaturatedPLUS(code_gen); break;
-        case OPCODE::PLUS2_: processSaturatedPLUS2(code_gen); break;
-        case OPCODE::MINUS_: processSaturatedMINUS(code_gen); break;
-        case OPCODE::MINUS2_: processSaturatedMINUS2(code_gen); break;
-        case OPCODE::INC_: processSaturatedINC(code_gen); break;
-        case OPCODE::INC2_: processSaturatedINC2(code_gen); break;
-        case OPCODE::DEC_: processSaturatedDEC(code_gen); break;
-        case OPCODE::DEC2_: processSaturatedDEC2(code_gen); break;
-        case OPCODE::RDMSD: processRDMSD(code_gen); break;
-        case OPCODE::SETBYTE:
-        case OPCODE::SETWORD:
-            processSETBYTE_SETWORD(code_gen);
-            break;
-        case OPCODE::BITON: processBITON(code_gen); break;
-        case OPCODE::BITOFF: processBITOFF(code_gen); break;
-        case OPCODE::BITXOR: WriteTodo(code_gen, md.GetEntityName(), "BITXOR"); break;
-        case OPCODE::PLUS:
-        case OPCODE::PLUS2:
-            processPLUSx_MINUSx(code_gen, "+");
-            break;
-        case OPCODE::MINUS:
-        case OPCODE::MINUS2:
-            processPLUSx_MINUSx(code_gen, "-");
-            break;
-        case OPCODE::MUL: WriteTodo(code_gen, md.GetEntityName(), "MUL"); break;
-        case OPCODE::MUL2: WriteTodo(code_gen, md.GetEntityName(), "MUL2"); break;
-        case OPCODE::DIV: WriteTodo(code_gen, md.GetEntityName(), "DIV"); break;
-        case OPCODE::DIV2: WriteTodo(code_gen, md.GetEntityName(), "DIV2"); break;
-        case OPCODE::MOD:
-            {
-                const uint32 source_bank = _params[0]->getUnsigned();
-                const uint32 source_address_or_value = _params[2]->getUnsigned();
-                auto source = FieldCodeGenerator::FormatValueOrVariable(
-                  cg->GetFormatter(), source_bank, source_address_or_value
-                );
-                const uint32 dest_bank = _params[1]->getUnsigned();
-                const uint32 dest_address = _params[3]->getUnsigned();
-                auto dest = FieldCodeGenerator::FormatValueOrVariable(
-                  cg->GetFormatter(), dest_bank, dest_address
-                );
-                code_gen->AddOutputLine(
-                  source + " = " + source + " % " + dest + code_gen->TargetLang().LineTerminator()
-                );
-            }
-        break;
-        case OPCODE::MOD2: WriteTodo(code_gen, md.GetEntityName(), "MOD2"); break;
-        case OPCODE::AND: WriteTodo(code_gen, md.GetEntityName(), "AND"); break;
-        case OPCODE::AND2: WriteTodo(code_gen, md.GetEntityName(), "AND2"); break;
-        case OPCODE::OR: WriteTodo(code_gen, md.GetEntityName(), "OR"); break;
-        case OPCODE::OR2: WriteTodo(code_gen, md.GetEntityName(), "OR2"); break;
-        case OPCODE::XOR: WriteTodo(code_gen, md.GetEntityName(), "XOR"); break;
-        case OPCODE::XOR2: WriteTodo(code_gen, md.GetEntityName(), "XOR2"); break;
-        case OPCODE::INC:
-        case OPCODE::INC2:
-            processINCx_DECx(code_gen, "+");
-            break;
-        case OPCODE::DEC:
-        case OPCODE::DEC2:
-            processINCx_DECx(code_gen, "-");
-            break;
-        case OPCODE::RANDOM: processRANDOM(code_gen); break;
-        case OPCODE::LBYTE: WriteTodo(code_gen, md.GetEntityName(), "LBYTE"); break;
-        case OPCODE::HBYTE: WriteTodo(code_gen, md.GetEntityName(), "HBYTE"); break;
-        case OPCODE::TWOBYTE: WriteTodo(code_gen, md.GetEntityName(), "2BYTE"); break;
-        case OPCODE::SIN: WriteTodo(code_gen, md.GetEntityName(), "SIN"); break;
-        case OPCODE::COS: WriteTodo(code_gen, md.GetEntityName(), "COS"); break;
-        default:
-            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
-              md.GetEntityName(), _address, _opcode
-            ));
-    }
-}
-
-void FF7MathInstruction::processSaturatedPLUS(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    // TODO: Check for assignment to value.
-    const auto& lhs = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
-    );
-    const auto& rhs = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
-    );
-    // TODO: Respect destination bank sizes and negative wrap-around.
-    code_gen->AddOutputLine((boost::format("%1% = %1% + %2%") % lhs % rhs).str());
-    code_gen->AddOutputLine((boost::format("--if (%1% > 255); %1% = 255; end") % lhs).str());
-}
-
-void FF7MathInstruction::processSaturatedPLUS2(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    // TODO: Check for assignment to value.
-    const auto& lhs = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
-    );
-    const auto& rhs = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
-    );
-    // TODO: Respect destination bank sizes and negative wrap-around.
-    code_gen->AddOutputLine((boost::format("%1% = %1% + %2%") % lhs % rhs).str());
-    code_gen->AddOutputLine((boost::format("--if (%1% > 32767); %1% = 32767; end") % lhs).str());
-}
-
-void FF7MathInstruction::processSaturatedMINUS(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    // TODO: Check for assignment to value.
-    const auto& lhs = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
-    );
-    const auto& rhs = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
-    );
-    // TODO: Respect destination bank sizes and positive wrap-around.
-    code_gen->AddOutputLine((boost::format("%1% = %1% - %2%") % lhs % rhs).str());
-    code_gen->AddOutputLine((boost::format("--if (%1% < 0); %1% = 0; end") % lhs).str());
-}
-
-void FF7MathInstruction::processSaturatedMINUS2(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    // TODO: Check for assignment to value.
-    const auto& lhs = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
-    );
-    const auto& rhs = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
-    );
-    // TODO: Respect destination bank sizes and positive wrap-around.
-    code_gen->AddOutputLine((boost::format("%1% = %1% - %2%") % lhs % rhs).str());
-    code_gen->AddOutputLine((boost::format("--if (%1% < 0); %1% = 0; end") % lhs).str());
-}
-
-void FF7MathInstruction::processSaturatedINC(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    // TODO: Check for assignment to value.
-    const auto& dest = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[1]->getUnsigned()
-    );
-    // TODO: Respect destination bank sizes and negative wrap-around.
-    code_gen->AddOutputLine((boost::format("%1% = %1% + 1") % dest).str());
-    code_gen->AddOutputLine((boost::format("--if (%1% > 255); %1% = 255; end") % dest).str());
-}
-
-void FF7MathInstruction::processSaturatedINC2(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    // TODO: Check for assignment to value.
-    const auto& dest = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[1]->getUnsigned()
-    );
-    // TODO: Respect destination bank sizes and negative wrap-around.
-    code_gen->AddOutputLine((boost::format("%1% = %1% + 1") % dest).str());
-    code_gen->AddOutputLine((boost::format("--if (%1% > 32767); %1% = 32767; end") % dest).str());
-}
-
-void FF7MathInstruction::processSaturatedDEC(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    // TODO: Check for assignment to value.
-    const auto& dest = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[1]->getUnsigned()
-    );
-    // TODO: Respect destination bank sizes and positive wrap-around.
-    code_gen->AddOutputLine((boost::format("%1% = %1% - 1") % dest).str());
-    code_gen->AddOutputLine((boost::format("--if (%1% < 0); %1% = 0; end") % dest).str());
-}
-
-void FF7MathInstruction::processSaturatedDEC2(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    // TODO: Check for assignment to value.
-    const auto& dest = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[1]->getUnsigned()
-    );
-    // TODO: Respect destination bank sizes and positive wrap-around.
-    code_gen->AddOutputLine((boost::format("%1% = %1% - 1") % dest).str());
-    code_gen->AddOutputLine((boost::format("--if (%1% < 0); %1% = 0; end") % dest).str());
-}
-
-void FF7MathInstruction::processRDMSD(CodeGenerator* code_gen){
-    // TODO: we don't have os.time...
-    // TODO: RNG emulation?
-    code_gen->AddOutputLine("math.randomseed(os.time())");
-}
-
-void FF7MathInstruction::processSETBYTE_SETWORD(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    // TODO: Check for assignment to value.
-    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
-    );
-    const auto& source = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
-    );
-    // TODO: respect destination bank sizes (16-bit writes only affect low byte)
-    code_gen->AddOutputLine((boost::format("%1% = %2%") % destination % source).str());
-}
-
-void FF7MathInstruction::processBITON(CodeGenerator* code_gen){
-    code_gen->AddOutputLine((boost::format("bit_on(%1%, %2%, %3%)")
-      % _params[0]->getUnsigned() % _params[2]->getUnsigned() % _params[3]->getUnsigned()
-    ).str());
-}
-
-void FF7MathInstruction::processBITOFF(CodeGenerator* code_gen){
-    code_gen->AddOutputLine((boost::format("bit_off(%1%, %2%, %3%)")
-      % _params[0]->getUnsigned() % _params[2]->getUnsigned() % _params[3]->getUnsigned()
-    ).str());
-}
-
-void FF7MathInstruction::processPLUSx_MINUSx(CodeGenerator* code_gen, const std::string& op){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    // TODO: Check for assignment to value.
-    const auto& lhs = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
-    );
-    const auto& rhs = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
-    );
-    // TODO: repect destination bank sizes and wraparound
-    code_gen->AddOutputLine((boost::format("%1% = %1% %2% %3%") % lhs % op % rhs).str());
-}
-
-void FF7MathInstruction::processINCx_DECx(CodeGenerator* code_gen, const std::string& op){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    // TODO: Check for assignment to value.
-    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[1]->getUnsigned()
-    );
-    // TODO: repect destination bank sizes and wraparound
-    code_gen->AddOutputLine((boost::format("%1% = %1% %2% 1") % destination % op).str());
-}
-
-void FF7MathInstruction::processRANDOM(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    // TODO: Check for assignment to value.
-    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[1]->getUnsigned()
-    );
-    // TODO: Respect destination bank sizes (16-bit writes only affect low byte).
-    // TODO: RNG emulation?
-    code_gen->AddOutputLine((boost::format("%1% = math.random(0, 255)") % destination).str());
-}
-
-void FF7WindowInstruction::processInst(
-  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
-){
-    FF7FieldEngine& eng = static_cast<FF7FieldEngine&>(*engine);
-    FunctionMetaData md(func._metadata);
-    switch (_opcode){
-        case OPCODE::TUTOR: WriteTodo(code_gen, md.GetEntityName(), "TUTOR"); break;
-        case OPCODE::WCLS: WriteTodo(code_gen, md.GetEntityName(), "WCLS"); break;
-        case OPCODE::WSIZW: WriteTodo(code_gen, md.GetEntityName(), "WSIZW"); break;
-        case OPCODE::WSPCL: WriteTodo(code_gen, md.GetEntityName(), "WSPCL"); break;
-        case OPCODE::WNUMB: WriteTodo(code_gen, md.GetEntityName(), "WNUMB"); break;
-        case OPCODE::STTIM: WriteTodo(code_gen, md.GetEntityName(), "STTIM"); break;
-        case OPCODE::MESSAGE: processMESSAGE(code_gen, eng.ScriptName()); break;
-        case OPCODE::MPARA: WriteTodo(code_gen, md.GetEntityName(), "MPARA"); break;
-        case OPCODE::MPRA2: WriteTodo(code_gen, md.GetEntityName(), "MPRA2"); break;
-        case OPCODE::MPNAM: processMPNAM(code_gen); break;
-        case OPCODE::ASK: WriteTodo(code_gen, md.GetEntityName(), "ASK"); break;
-        case OPCODE::MENU: WriteTodo(code_gen, md.GetEntityName(), "MENU"); break;
-        case OPCODE::MENU2: processMENU2(code_gen); break;
-        case OPCODE::WINDOW: processWINDOW(code_gen); break;
-        case OPCODE::WMOVE: WriteTodo(code_gen, md.GetEntityName(), "WMOVE"); break;
-        case OPCODE::WMODE: WriteTodo(code_gen, md.GetEntityName(), "WMODE"); break;
-        case OPCODE::WREST: WriteTodo(code_gen, md.GetEntityName(), "WREST"); break;
-        case OPCODE::WCLSE: processWCLSE(code_gen); break;
-        case OPCODE::WROW: WriteTodo(code_gen, md.GetEntityName(), "WROW"); break;
-        case OPCODE::GWCOL: WriteTodo(code_gen, md.GetEntityName(), "GWCOL"); break;
-        case OPCODE::SWCOL: WriteTodo(code_gen, md.GetEntityName(), "SWCOL"); break;
-        default:
-            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
-              md.GetEntityName(), _address, _opcode
-            ));
-    }
-}
-
-void FF7WindowInstruction::processWINDOW(CodeGenerator* code_gen){
-    // Init a new window. It won't be displayed until MESSAGE is used.
-    auto windowId = _params[0]->getUnsigned();
-    auto x = _params[1]->getUnsigned();
-    auto y = _params[2]->getUnsigned();
-    auto width = _params[3]->getUnsigned();
-    auto height = _params[4]->getUnsigned();
-    code_gen->AddOutputLine((
-      boost::format("dialog:dialog_open(\"%1%\", %2%, %3%, %4%, %5%)")
-      % windowId % x % y % width % height
-    ).str());
-}
-
-void FF7WindowInstruction::processMESSAGE(
-  CodeGenerator* code_gen, const std::string& script_name
-){
-    // Displays a dialog in the WINDOW that has previously been initialized to display this dialog.
-    auto window_id = _params[0]->getUnsigned();
-    auto dialog_id = _params[1]->getUnsigned();
-    code_gen->AddOutputLine((
-      boost::format("dialog:dialog_set_text(\"%1%\", \"%2%_%3%\")")
-      % window_id % script_name % dialog_id
-    ).str());
-    code_gen->AddOutputLine(
-      (boost::format("dialog:dialog_wait_for_close(\"%1%\")") % window_id).str()
-    );
-
-}
-
-void FF7WindowInstruction::processWCLSE(CodeGenerator* code_gen){
-    // Close a dialog.
-    auto windowId = _params[0]->getUnsigned();
-    code_gen->AddOutputLine((boost::format("dialog:dialog_close(\"%1%\")") % windowId).str());
-}
-
-void FF7WindowInstruction::processMPNAM(CodeGenerator* code_gen){
-    code_gen->AddOutputLine(
-      (boost::format("-- field:map_name(%1%)") % _params[0]->getUnsigned()).str()
-    );
-}
-
-void FF7WindowInstruction::processMENU2(CodeGenerator* code_gen){
-    code_gen->AddOutputLine((
-      boost::format("-- field:menu_lock(%1%)")
-      % FieldCodeGenerator::FormatBool(_params[0]->getUnsigned())
-    ).str());
-}
-
-void FF7PartyInstruction::processInst(
-  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
-){
-    FunctionMetaData md(func._metadata);
-    switch (_opcode){
-        case OPCODE::SPTYE: WriteTodo(code_gen, md.GetEntityName(), "SPTYE"); break;
-        case OPCODE::GTPYE: WriteTodo(code_gen, md.GetEntityName(), "GTPYE"); break;
-        case OPCODE::GOLDU: WriteTodo(code_gen, md.GetEntityName(), "GOLDU"); break;
-        case OPCODE::GOLDD: WriteTodo(code_gen, md.GetEntityName(), "GOLDD"); break;
-        case OPCODE::HMPMAX1: WriteTodo(code_gen, md.GetEntityName(), "HMPMAX1"); break;
-        case OPCODE::HMPMAX2: WriteTodo(code_gen, md.GetEntityName(), "HMPMAX2"); break;
-        case OPCODE::MHMMX: WriteTodo(code_gen, md.GetEntityName(), "MHMMX"); break;
-        case OPCODE::HMPMAX3: WriteTodo(code_gen, md.GetEntityName(), "HMPMAX3"); break;
-        case OPCODE::MPU: WriteTodo(code_gen, md.GetEntityName(), "MPU"); break;
-        case OPCODE::MPD: WriteTodo(code_gen, md.GetEntityName(), "MPD"); break;
-        case OPCODE::HPU: WriteTodo(code_gen, md.GetEntityName(), "HPU"); break;
-        case OPCODE::HPD: WriteTodo(code_gen, md.GetEntityName(), "HPD"); break;
-        case OPCODE::STITM: processSTITM(code_gen); break;
-        case OPCODE::DLITM: WriteTodo(code_gen, md.GetEntityName(), "DLITM"); break;
-        case OPCODE::CKITM: WriteTodo(code_gen, md.GetEntityName(), "CKITM"); break;
-        case OPCODE::SMTRA: WriteTodo(code_gen, md.GetEntityName(), "SMTRA"); break;
-        case OPCODE::DMTRA: WriteTodo(code_gen, md.GetEntityName(), "DMTRA"); break;
-        case OPCODE::CMTRA: WriteTodo(code_gen, md.GetEntityName(), "CMTRA"); break;
-        case OPCODE::GETPC: WriteTodo(code_gen, md.GetEntityName(), "GETPC"); break;
-        case OPCODE::PRTYP: WriteTodo(code_gen, md.GetEntityName(), "PRTYP"); break;
-        case OPCODE::PRTYM: WriteTodo(code_gen, md.GetEntityName(), "PRTYM"); break;
-        case OPCODE::PRTYE: processPRTYE(code_gen); break;
-        case OPCODE::MMBUD: WriteTodo(code_gen, md.GetEntityName(), "MMBUD"); break;
-        case OPCODE::MMBLK: WriteTodo(code_gen, md.GetEntityName(), "MMBLK"); break;
-        case OPCODE::MMBUK: WriteTodo(code_gen, md.GetEntityName(), "MMBUK"); break;
-        case OPCODE::CHGLD: WriteTodo(code_gen, md.GetEntityName(), "CHGLD"); break;
-        default:
-            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
-              md.GetEntityName(), _address, _opcode
-            ));
-    }
-}
-
-void FF7PartyInstruction::processSTITM(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& item_id = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
-    );
-    const auto& amount = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
-    );
-    code_gen->AddOutputLine((boost::format("FFVII.add_item(%1%, %2%)") % item_id % amount).str());
-}
-
-void FF7PartyInstruction::processPRTYE(CodeGenerator* code_gen){
-    FieldCodeGenerator* gc = static_cast<FieldCodeGenerator*>(code_gen);
-    auto char_id_1 = gc->GetFormatter().CharName(_params[0]->getUnsigned());
-    char_id_1 = (char_id_1 == "") ? "nil" : ("\"" + char_id_1 + "\"");
-    auto char_id_2 = gc->GetFormatter().CharName(_params[1]->getUnsigned());
-    char_id_2 = (char_id_2 == "") ? "nil" : ("\"" + char_id_2 + "\"");
-    auto char_id_3 = gc->GetFormatter().CharName(_params[2]->getUnsigned());
-    char_id_3 = (char_id_3 == "") ? "nil" : ("\"" + char_id_3 + "\"");
-    code_gen->AddOutputLine((
-      boost::format("FFVII.set_party(%1%, %2%, %3%)") % char_id_1 % char_id_2 % char_id_3
-    ).str());
-}
-
-void FF7ModelInstruction::processInst(
-  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
-){
-    FF7FieldEngine& eng = static_cast<FF7FieldEngine&>(*engine);
-    FunctionMetaData md(func._metadata);
-    switch (_opcode){
-        case OPCODE::JOIN: processJOIN(code_gen); break;
-        case OPCODE::SPLIT: processSPLIT(code_gen); break;
-        case OPCODE::BLINK: WriteTodo(code_gen, md.GetEntityName(), "BLINK"); break;
-        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::EYETX:
-            WriteTodo(code_gen, md.GetEntityName(), "EYETX");
-            break;
-        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::TRNSP:
-            WriteTodo(code_gen, md.GetEntityName(), "TRNSP");
-            break;
-        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::AMBNT:
-            WriteTodo(code_gen, md.GetEntityName(), "AMBNT");
-            break;
-        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::Unknown03:
-            WriteTodo(code_gen, md.GetEntityName(), "Unknown03");
-            break;
-        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::Unknown04:
-            WriteTodo(code_gen, md.GetEntityName(), "Unknown04");
-            break;
-        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::Unknown05:
-            WriteTodo(code_gen, md.GetEntityName(), "Unknown05");
-            break;
-        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::LIGHT:
-            WriteTodo(code_gen, md.GetEntityName(), "LIGHT");
-            break;
-        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::Unknown07:
-            WriteTodo(code_gen, md.GetEntityName(), "Unknown07");
-            break;
-        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::Unknown08:
-            WriteTodo(code_gen, md.GetEntityName(), "Unknown08");
-            break;
-        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::Unknown09:
-            WriteTodo(code_gen, md.GetEntityName(), "Unknown09");
-            break;
-        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::SBOBJ:
-            WriteTodo(code_gen, md.GetEntityName(), "SBOBJ");
-            break;
-        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::Unknown0B:
-            WriteTodo(code_gen, md.GetEntityName(), "Unknown0B");
-            break;
-        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::Unknown0C:
-            WriteTodo(code_gen, md.GetEntityName(), "Unknown0C");
-            break;
-        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::SHINE:
-            WriteTodo(code_gen, md.GetEntityName(), "SHINE");
-            break;
-        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::RESET:
-            WriteTodo(code_gen, md.GetEntityName(), "RESET");
-            break;
-        case OPCODE::KAWIW: WriteTodo(code_gen, md.GetEntityName(), "KAWIW"); break;
-        case OPCODE::PMOVA: WriteTodo(code_gen, md.GetEntityName(), "PMOVA"); break;
-        case OPCODE::PDIRA: WriteTodo(code_gen, md.GetEntityName(), "PDIRA"); break;
-        case OPCODE::PTURA: WriteTodo(code_gen, md.GetEntityName(), "PTURA"); break;
-        case OPCODE::PGTDR: WriteTodo(code_gen, md.GetEntityName(), "PGTDR"); break;
-        case OPCODE::PXYZI: WriteTodo(code_gen, md.GetEntityName(), "PXYZI"); break;
-        case OPCODE::TLKON: processTLKON(code_gen, md.GetEntityName()); break;
-        case OPCODE::PC: processPC(code_gen, md.GetEntityName()); break;
-        case OPCODE::opCodeCHAR: processCHAR(code_gen, md.GetEntityName()); break;
-        case OPCODE::DFANM: processDFANM(code_gen, md.GetEntityName(), md.GetCharacterId()); break;
-        case OPCODE::ANIME1: processANIME1(code_gen, md.GetEntityName(), md.GetCharacterId()); break;
-        case OPCODE::VISI: processVISI(code_gen, md.GetEntityName()); break;
-        case OPCODE::XYZI: processXYZI(code_gen, md.GetEntityName()); break;
-        case OPCODE::XYI: WriteTodo(code_gen, md.GetEntityName(), "XYI"); break;
-        case OPCODE::XYZ: WriteTodo(code_gen, md.GetEntityName(), "XYZ"); break;
-        case OPCODE::MOVE: processMOVE(code_gen, md.GetEntityName()); break;
-        case OPCODE::CMOVE: WriteTodo(code_gen, md.GetEntityName(), "CMOVE"); break;
-        case OPCODE::MOVA: WriteTodo(code_gen, md.GetEntityName(), "MOVA"); break;
-        case OPCODE::TURA: WriteTodo(code_gen, md.GetEntityName(), "TURA"); break;
-        case OPCODE::ANIMW: WriteTodo(code_gen, md.GetEntityName(), "ANIMW"); break;
-        case OPCODE::FMOVE: WriteTodo(code_gen, md.GetEntityName(), "FMOVE"); break;
-        case OPCODE::ANIME2: WriteTodo(code_gen, md.GetEntityName(), "ANIME2"); break;
-        case OPCODE::ANIM_1: WriteTodo(code_gen, md.GetEntityName(), "ANIM_1"); break;
-        case OPCODE::CANIM1: WriteTodo(code_gen, md.GetEntityName(), "CANIM1"); break;
-        case OPCODE::CANM_1: WriteTodo(code_gen, md.GetEntityName(), "CANM_1"); break;
-        case OPCODE::MSPED: processMSPED(code_gen, md.GetEntityName()); break;
-        case OPCODE::DIR: processDIR(code_gen, md.GetEntityName()); break;
-        case OPCODE::TURNGEN: processTURNGEN(code_gen, md.GetEntityName()); break;
-        case OPCODE::TURN: WriteTodo(code_gen, md.GetEntityName(), "TURN"); break;
-        case OPCODE::DIRA: WriteTodo(code_gen, md.GetEntityName(), "DIRA"); break;
-        case OPCODE::GETDIR: WriteTodo(code_gen, md.GetEntityName(), "GETDIR"); break;
-        case OPCODE::GETAXY: WriteTodo(code_gen, md.GetEntityName(), "GETAXY"); break;
-        case OPCODE::GETAI: processGETAI(code_gen, eng); break;
-        case OPCODE::ANIM_2: processANIM_2(code_gen, md.GetEntityName(), md.GetCharacterId()); break;
-        case OPCODE::CANIM2: processCANIM2(code_gen, md.GetEntityName(), md.GetCharacterId()); break;
-        case OPCODE::CANM_2: processCANM_2(code_gen, md.GetEntityName(), md.GetCharacterId()); break;
-        case OPCODE::ASPED: WriteTodo(code_gen, md.GetEntityName(), "ASPED"); break;
-        case OPCODE::CC: processCC(code_gen, eng); break;
-        case OPCODE::JUMP: processJUMP(code_gen, md.GetEntityName()); break;
-        case OPCODE::AXYZI: processAXYZI(code_gen); break;
-        case OPCODE::LADER: processLADER(code_gen, md.GetEntityName()); break;
-        case OPCODE::OFST: processOFST(code_gen, md.GetEntityName()); break;
-        case OPCODE::OFSTW:
-            code_gen->AddOutputLine("self." + md.GetEntityName() + ":offset_sync()");
-            break;
-        case OPCODE::TALKR: WriteTodo(code_gen, md.GetEntityName(), "TALKR"); break;
-        case OPCODE::SLIDR: WriteTodo(code_gen, md.GetEntityName(), "SLIDR"); break;
-        case OPCODE::SOLID: processSOLID(code_gen, md.GetEntityName()); break;
-        case OPCODE::TLKR2: WriteTodo(code_gen, md.GetEntityName(), "TLKR2"); break;
-        case OPCODE::SLDR2: WriteTodo(code_gen, md.GetEntityName(), "SLDR2"); break;
-        case OPCODE::CCANM: WriteTodo(code_gen, md.GetEntityName(), "CCANM"); break;
-        case OPCODE::FCFIX: WriteTodo(code_gen, md.GetEntityName(), "FCFIX"); break;
-        case OPCODE::ANIMB: WriteTodo(code_gen, md.GetEntityName(), "ANIMB"); break;
-        case OPCODE::TURNW: WriteTodo(code_gen, md.GetEntityName(), "TURNW"); break;
-        default:
-            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
-              md.GetEntityName(), _address, _opcode
-            ));
-    }
-}
-
-void FF7ModelInstruction::processJOIN(CodeGenerator* code_gen){
-    code_gen->AddOutputLine("join_party(" + std::to_string(_params[0]->getUnsigned()) + ")");
-}
-
-void FF7ModelInstruction::processSPLIT(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const float scale = 128.0f * cg->GetScaleFactor();
-    const auto& ax = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[6]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, scale
-    );
-    const auto& ay = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[7]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, scale
-    );
-    const auto& ar = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[2]->getUnsigned(), _params[8]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, scale
-    );
-    const auto& bx = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[3]->getUnsigned(), _params[9]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, scale
-    );
-    const auto& by = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[4]->getUnsigned(), _params[10]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, scale
-    );
-    const auto& br = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[5]->getUnsigned(), _params[11]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, scale
-    );
-    const auto& speed = _params[12]->getUnsigned();
-    code_gen->AddOutputLine((
-      boost::format("split_party(%1%, %2%, %3%, %4%, %5%, %6%, %7%)")
-      % ax % ay % ar % bx % by % br % speed
-    ).str());
-}
-
-void FF7ModelInstruction::processTLKON(CodeGenerator* code_gen, const std::string& entity){
-    code_gen->AddOutputLine((
-      boost::format("self.%1%:set_talkable(%2%)")
-      % entity % FieldCodeGenerator::FormatInvertedBool(_params[0]->getUnsigned())
-    ).str());
-}
-
-void FF7ModelInstruction::processPC(CodeGenerator* code_gen, const std::string& entity){
-    code_gen->AddOutputLine(
-      (boost::format("set_entity_to_character(\"%1%\", \"%1%\")") % entity).str()
-    );
-}
-
-void FF7ModelInstruction::processCHAR(CodeGenerator* code_gen, const std::string& entity){
-    code_gen->AddOutputLine(
-      (boost::format("self.%1% = entity_manager:get_entity(\"%1%\")") % entity).str()
-    );
-}
-
-void FF7ModelInstruction::processDFANM(
-  CodeGenerator* code_gen, const std::string& entity, int char_id
-){
-    // ID will be fixed-up downstream.
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    auto animation_id = _params[0]->getUnsigned();
-    // TODO: check for zero.
-    auto speed = 1.0f / _params[1]->getUnsigned();
-    code_gen->AddOutputLine((
-      boost::format("self.%1%:set_default_animation(\"%2%\") -- speed %3%")
-      % entity % cg->GetFormatter().AnimationName(char_id, animation_id) % speed
-    ).str());
-    code_gen->AddOutputLine((
-      boost::format("self.%1%:play_animation(\"%2%\")")
-      % entity % cg->GetFormatter().AnimationName(char_id, animation_id)
-    ).str());
-}
-
-void FF7ModelInstruction::processANIME1(
-  CodeGenerator* code_gen, const std::string& entity, int char_id
-){
-    // ID will be fixed-up downstream.
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    auto animation_id = _params[0]->getUnsigned();
-    // TODO: check for zero.
-    auto speed = 1.0f / _params[1]->getUnsigned();
-    code_gen->AddOutputLine((
-      boost::format("self.%1%:play_animation(\"%2%\") -- speed %3%")
-      % entity % cg->GetFormatter().AnimationName(char_id, animation_id) % speed
-    ).str());
-    code_gen->AddOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
-}
-
-void FF7ModelInstruction::processVISI(CodeGenerator* code_gen, const std::string& entity){
-    code_gen->AddOutputLine((
-      boost::format("self.%1%:set_visible(%2%)")
-      % entity % FieldCodeGenerator::FormatBool(_params[0]->getUnsigned())
-    ).str());
-}
-
-void FF7ModelInstruction::processXYZI(CodeGenerator* code_gen, const std::string& entity){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const float scale = 128.0f * cg->GetScaleFactor();
-    const auto& x = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[4]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, scale
-    );
-    const auto& y = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[5]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, scale
-    );
-    const auto& z = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[2]->getUnsigned(), _params[6]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, scale
-    );
-    const auto& triangle_id = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[3]->getUnsigned(), _params[7]->getUnsigned()
-    );
-    code_gen->AddOutputLine((
-      boost::format("self.%1%:set_position(%2%, %3%, %4%) -- triangle ID %5%")
-      % entity % x % y % z % triangle_id
-    ).str());
-}
-
-void FF7ModelInstruction::processMOVE(CodeGenerator* code_gen, const std::string& entity){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const float scale = 128.0f * cg->GetScaleFactor();
-    const auto& x = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, scale
-    );
-    const auto& y = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, scale
-    );
-    code_gen->AddOutputLine(
-      (boost::format("self.%1%:move_to_position(%2%, %3%)") % entity % x % y).str()
-    );
-    code_gen->AddOutputLine((boost::format("self.%1%:move_sync()") % entity).str());
-}
-
-void FF7ModelInstruction::processMSPED(CodeGenerator* code_gen, const std::string& entity){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const float scale = 128.0f * cg->GetScaleFactor();
-    const auto& speed = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[2]->getUnsigned(),
-      FieldCodeGenerator::ValueType::Float, 256.0f * scale / 30.0f
-    );
-    code_gen->AddOutputLine(
-      (boost::format("self.%1%:set_move_auto_speed(%2%)") % entity % speed).str()
-    );
-}
-
-void FF7ModelInstruction::processDIR(CodeGenerator* code_gen, const std::string& entity){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& degrees = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[1]->getUnsigned(),
-      FieldCodeGenerator::ValueType::Float, 256.0f / 360.0f
-    );
-    code_gen->AddOutputLine((boost::format("self.%1%:set_rotation(%2%)") % entity % degrees).str());
-}
-
-void FF7ModelInstruction::processTURNGEN(CodeGenerator* code_gen, const std::string& entity){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& degrees = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[2]->getUnsigned(),
-      FieldCodeGenerator::ValueType::Float, 256.0f / 360.0f
-    );
-    std::string direction;
-    switch (_params[3]->getUnsigned()){
-        case 0: direction = "Entity.CLOCKWISE"; break;
-        case 1: direction = "Entity.ANTICLOCKWISE"; break;
-        case 2: direction = "Entity.CLOSEST"; break;
-        // Default to closest:
-        default: direction = "Entity.CLOSEST"; break;
-    }
-    auto steps = _params[4]->getUnsigned();
-    std::string step_type;
-    switch (_params[5]->getUnsigned()){
-        case 1: step_type = "Entity.LINEAR"; break;
-        case 2: step_type = "Entity.SMOOTH"; break;
-        // Default to smooth
-        default: step_type = "Entity.SMOOTH"; break;
-    }
-    const float scaled_steps = static_cast<float>(steps) / 30.0f;
-    code_gen->AddOutputLine((
-      boost::format("self.%1%:turn_to_direction(%2%, %3%, %4%, %5%)")
-      % entity % degrees % direction % step_type % scaled_steps
-    ).str());
-    code_gen->AddOutputLine((boost::format("self.%1%:turn_sync()") % entity).str());
-}
-
-void FF7ModelInstruction::processGETAI(CodeGenerator* code_gen, const FF7FieldEngine& engine){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    // TODO: check for assignment to literal.
-    const auto& variable = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
-    );
-    const auto& entity = engine.EntityByIndex(_params[2]->getUnsigned());
-    code_gen->AddOutputLine(
-      (boost::format("%1% = entity_manager:get_entity(\"%2%\"):get_move_triangle_id()")
-      % variable % entity.Name()
-    ).str());
-}
-
-void FF7ModelInstruction::processANIM_2(
-  CodeGenerator* code_gen, const std::string& entity, int char_id
-){
-    // ID will be fixed-up downstream.
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    auto animation_id = _params[0]->getUnsigned();
-    // TODO: check for zero.
-    auto speed = 1.0f / _params[1]->getUnsigned();
-    code_gen->AddOutputLine((
-      boost::format("self.%1%:play_animation_stop(\"%2%\") -- speed %3%")
-      % entity % cg->GetFormatter().AnimationName(char_id, animation_id) % speed
-    ).str());
-    code_gen->AddOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
-}
-
-void FF7ModelInstruction::processCANIM2(
-  CodeGenerator* code_gen, const std::string& entity, int char_id
-){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    auto animation_id = _params[0]->getUnsigned();
-    auto start_frame = _params[1]->getUnsigned() / 30.0f;
-    auto end_frame = _params[2]->getUnsigned() / 30.0f;
-    // TODO: check for zero.
-    auto speed = 1.0f / _params[3]->getUnsigned();
-    code_gen->AddOutputLine((
-      boost::format("self.%1%:play_animation(\"%2%\", %3%, %4%) -- speed %5%")
-      % entity % cg->GetFormatter().AnimationName(char_id, animation_id)
-      % start_frame % end_frame % speed
-    ).str());
-    code_gen->AddOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
-}
-
-void FF7ModelInstruction::processCANM_2(
-  CodeGenerator* code_gen, const std::string& entity, int char_id
-){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    // ID will be fixed-up downstream.
-    auto animation_id = _params[0]->getUnsigned();
-    auto start_frame = _params[1]->getUnsigned() / 30.0f;
-    auto end_frame = _params[2]->getUnsigned() / 30.0f;
-    // TODO: check for zero.
-    auto speed = 1.0f / _params[3]->getUnsigned();
-    code_gen->AddOutputLine((
-      boost::format("self.%1%:play_animation_stop(\"%2%\", %3%, %4%) -- speed %5%")
-      % entity % cg->GetFormatter().AnimationName(char_id, animation_id)
-      % start_frame % end_frame % speed
-    ).str());
-    code_gen->AddOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
-}
-
-void FF7ModelInstruction::processCC(CodeGenerator* code_gen, const FF7FieldEngine& engine){
-    const auto& entity = engine.EntityByIndex(_params[0]->getUnsigned());
-    code_gen->AddOutputLine(
-      (boost::format("entity_manager:set_player_entity(\"%1%\")") % entity.Name()).str()
-    );
-}
-
-void FF7ModelInstruction::processJUMP(CodeGenerator* code_gen, const std::string& entity){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const float scale = 128.0f * cg->GetScaleFactor();
-    float x = std::stof(FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[4]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, scale
-    ));
-    float y = std::stof(FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[5]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, scale
-    ));
-    int i = atoi(FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[2]->getUnsigned(), _params[6]->getSigned()
-    ).c_str());
-    int steps = atoi(FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[3]->getUnsigned(), _params[7]->getSigned()
-    ).c_str());
-    //x *= 0.00781250273224;
-    //y *= 0.00781250273224;
-    // Always force reduce steps and bound it between 1 and 5.
-    steps /= 6;
-    if (steps < 1) steps = 1;
-    if (steps > 5) steps = 5;
-    // TODO: Z hardcoded as -1, handled in Entity::ScriptJumpToPosition.
-    // TODO: Hardcoded 0.5 in seconds. Calculate using distance.
-    code_gen->AddOutputLine((
-      boost::format("self.%1%:jump_to_position(%2%, %3%, -1, 0.5, %4%) -- %5% steps.")
-      % entity % x % y % i % steps
-    ).str());
-    code_gen->AddOutputLine((boost::format("self.%1%:jump_sync()") % entity).str());
-}
-
-void FF7ModelInstruction::processAXYZI(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const float scale = 128.0f * cg->GetScaleFactor();
-    code_gen->AddOutputLine((
-      boost::format("axyzi(%1%, %2%, %3%, %4%, %5%, %6%, %7%, %8%, %9%, %10%)")
-      % _params[0]->getSigned() % _params[1]->getSigned() % _params[2]->getSigned()
-      % _params[3]->getSigned() % _params[4]->getSigned() % _params[5]->getSigned()
-      % _params[6]->getSigned() % _params[7]->getSigned() % _params[8]->getSigned()
-      % scale
-    ).str());
-}
-
-void FF7ModelInstruction::processLADER(CodeGenerator* code_gen, const std::string& entity){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const float scale = 128.0f * cg->GetScaleFactor();
-    const auto& x = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[4]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, scale
-    );
-    const auto& y = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[5]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, scale
-    );
-    const auto& z = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[2]->getUnsigned(), _params[6]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, scale
-    );
-    uint end_triangle = atoi(FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[3]->getUnsigned(), _params[7]->getUnsigned()
-    ).c_str());
-    uint keys = _params[8]->getUnsigned();
-    uint animation = _params[9]->getUnsigned();
-    //float orientation = _params[10]->getUnsigned() / (256.0f / 360.0f);
-    const auto& orientation = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), 0, _params[10]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, 256.0f / 360.0f
-    );
-    uint speed = _params[11]->getUnsigned();
-    // TODO: Animation hardcoded as "btce".
-    // TODO: Orientation and speed not set.
-    code_gen->AddOutputLine((
-      boost::format(
-        "self.%1%:linear_to_position(%2%, %3%, %4%, %5%, \"Climb\", %6%, %7%) "
-        "-- Animation %8% -- Speed %9%"
-      ) % entity % x % y % z % keys % orientation % end_triangle % animation % speed
-    ).str());
-    code_gen->AddOutputLine((boost::format("self.%1%:linear_sync()") % entity).str());
-}
-
-void FF7ModelInstruction::processSOLID(CodeGenerator* code_gen, const std::string& entity){
-    code_gen->AddOutputLine((
-      boost::format("self.%1%:set_solid(%2%)")
-      % entity % FieldCodeGenerator::FormatInvertedBool(_params[0]->getUnsigned())
-    ).str());
-}
-
-void FF7ModelInstruction::processOFST(CodeGenerator* code_gen, const std::string& entity){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const float scale = 128.0f * cg->GetScaleFactor();
-    float x = std::stof(FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[5]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, scale
-    ));
-    float y = std::stof(FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(),_params[6]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, scale
-    ));
-    float z = std::stof(FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[2]->getUnsigned(), _params[7]->getSigned(),
-      FieldCodeGenerator::ValueType::Float, scale
-    ));
-    float speed = std::stof(FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[3]->getUnsigned(), _params[8]->getUnsigned()
-    ));
-    // Spatial coordinates need to be scaled down.
-    // TODO: This number is empirically deducted. Why this number?
-    //x *= 0.00390f;
-    //y *= 0.00390f;
-    //z *= 0.00390f;
-    // Speed needs to be scaled down by the frame rate.
-    speed /= 30.0f;
-    code_gen->AddOutputLine((
-      boost::format("self.%1%:offset_to_position(%2%, %3%, %4%, %5%, %6%)")
-      % entity % x % y % z
-      % (_params[4]->getUnsigned() ? "Entity.SMOOTH" : "Entity.LINEAR")% speed
-    ).str());
-}
-
-void FF7WalkmeshInstruction::processInst(
-  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
-){
-    FunctionMetaData md(func._metadata);
-    switch (_opcode){
-        case OPCODE::SLIP: WriteTodo(code_gen, md.GetEntityName(), "SLIP"); break;
-        case OPCODE::UC: processUC(code_gen); break;
-        case OPCODE::IDLCK:
-            // Triangle id, on or off
-            code_gen->AddOutputLine(
-                (boost::format("walkmesh:lock_walkmesh(%1%, %2%)")
-                % _params[0]->getUnsigned()
-                % FieldCodeGenerator::FormatBool(_params[1]->getUnsigned())).str());
-            break;
-        case OPCODE::LINE: processLINE(code_gen, md.GetEntityName()); break;
-        case OPCODE::LINON: WriteTodo(code_gen, md.GetEntityName(), "LINON"); break;
-        case OPCODE::SLINE: WriteTodo(code_gen, md.GetEntityName(), "SLINE"); break;
-        default:
-            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
-              md.GetEntityName(), _address, _opcode
-            ));
-    }
-}
-
-void FF7WalkmeshInstruction::processUC(CodeGenerator* code_gen){
-    code_gen->AddOutputLine((
-      boost::format("entity_manager:player_lock(%1%)")
-      % FieldCodeGenerator::FormatBool(_params[0]->getUnsigned())
-    ).str());
-}
-
-void FF7WalkmeshInstruction::processLINE(CodeGenerator* code_gen, const std::string& entity){
-    float xa = _params[0]->getSigned();
-    float ya = _params[1]->getSigned();
-    float za = _params[2]->getSigned();
-    float xb = _params[3]->getSigned();
-    float yb = _params[4]->getSigned();
-    float zb = _params[5]->getSigned();
-    // Scale down. TODO: Why this number?
-    xa *= 0.00781249709639;
-    ya *= 0.00781249709639;
-    za *= 0.00781249709639;
-    xb *= 0.00781249709639;
-    yb *= 0.00781249709639;
-    zb *= 0.00781249709639;
-    // Just print as a comment.
-    code_gen->AddOutputLine(
-      "-- LINE (" + std::to_string(xa) + ", " + std::to_string(ya) + ", " + std::to_string(za)
-      + ")-(" + std::to_string(xb) + ", " +std::to_string(yb) + ", " + std::to_string(zb) + ")"
-    );
-}
-
-void FF7BackgroundInstruction::processInst(
-  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
-){
-    FunctionMetaData md(func._metadata);
-    switch (_opcode){
-        case OPCODE::BGPDH: WriteTodo(code_gen, md.GetEntityName(), "BGPDH");break;
-        case OPCODE::BGSCR: WriteTodo(code_gen, md.GetEntityName(), "BGSCR"); break;
-        case OPCODE::MPPAL: WriteTodo(code_gen, md.GetEntityName(), "MPPAL"); break;
-        case OPCODE::BGON: processBGON(code_gen); break;
-        case OPCODE::BGOFF: processBGOFF(code_gen); break;
-        case OPCODE::BGROL: WriteTodo(code_gen, md.GetEntityName(), "BGROL"); break;
-        case OPCODE::BGROL2: WriteTodo(code_gen, md.GetEntityName(), "BGROL2"); break;
-        case OPCODE::BGCLR: processBGCLR(code_gen); break;
-        case OPCODE::STPAL: processSTPAL(code_gen); break;
-        case OPCODE::LDPAL: processLDPAL(code_gen); break;
-        case OPCODE::CPPAL: processCPPAL(code_gen); break;
-        case OPCODE::RTPAL: WriteTodo(code_gen, md.GetEntityName(), "RTPAL"); break;
-        case OPCODE::ADPAL: processADPAL(code_gen); break;
-        case OPCODE::MPPAL2: processMPPAL2(code_gen); break;
-        case OPCODE::STPLS: processSTPLS(code_gen); break;
-        case OPCODE::LDPLS: processLDPLS(code_gen); break;
-        case OPCODE::CPPAL2: WriteTodo(code_gen, md.GetEntityName(), "CPPAL2"); break;
-        case OPCODE::ADPAL2: WriteTodo(code_gen, md.GetEntityName(), "ADPAL2"); break;
-        case OPCODE::RTPAL2: WriteTodo(code_gen, md.GetEntityName(), "RTPAL2"); break;
-        default:
-            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
-              md.GetEntityName(), _address, _opcode
-            ));
-    }
-}
-
-void FF7BackgroundInstruction::processBGON(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& background_id = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
-    );
-    const auto& layer_id = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
-    );
-    code_gen->AddOutputLine(
-      (boost::format("-- field:background_on(%1%, %2%)") % background_id % layer_id).str()
-    );
-}
-
-void FF7BackgroundInstruction::processBGOFF(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& background_id = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
-    );
-    const auto& layer_id = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
-    );
-    code_gen->AddOutputLine(
-      (boost::format("-- field:background_off(%1%, %2%)") % background_id % layer_id).str()
-    );
-}
-
-void FF7BackgroundInstruction::processBGCLR(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& background_id = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[2]->getUnsigned()
-    );
-    code_gen->AddOutputLine(
-      (boost::format("-- field:background_clear(%1%)") % background_id).str()
-    );
-}
-
-void FF7BackgroundInstruction::processSTPAL(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& source = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
-    );
-    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
-    );
-    auto num_entries = _params[4]->getUnsigned() + 1;
-    code_gen->AddOutputLine((
-      boost::format("-- store palette %1% to position %2%, start CLUT index 0, %3% entries")
-      % source % destination % num_entries
-    ).str());
-}
-
-void FF7BackgroundInstruction::processLDPAL(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& source = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
-    );
-    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
-    );
-    auto num_entries = _params[4]->getUnsigned() + 1;
-    code_gen->AddOutputLine((
-      boost::format("-- load palette %2% from position %1%, start CLUT index 0, %3% entries")
-      % source % destination % num_entries
-    ).str());
-}
-
-void FF7BackgroundInstruction::processCPPAL(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& source = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
-    );
-    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
-    );
-    auto num_entries = _params[4]->getUnsigned() + 1;
-    code_gen->AddOutputLine((
-      boost::format("-- copy palette %1% to palette %2%, %3% entries")
-      % source % destination % num_entries
-    ).str());
-}
-
-void FF7BackgroundInstruction::processADPAL(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& source = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[6]->getUnsigned()
-    );
-    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[7]->getUnsigned()
-    );
-    const auto& r = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[4]->getUnsigned(), _params[10]->getUnsigned()
-    );
-    const auto& g = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[3]->getUnsigned(), _params[9]->getUnsigned()
-    );
-    const auto& b = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[2]->getUnsigned(), _params[8]->getUnsigned()
-    );
-    auto num_entries = _params[11]->getUnsigned() + 1;
-    code_gen->AddOutputLine((
-      boost::format(
-        "-- add RGB(%3%, %4%, %5%) to %6% entries of palette stored at position %1%, "
-        "storing result in position %2%"
-      ) % source % destination % r % g % b % num_entries
-    ).str());
-}
-
-void FF7BackgroundInstruction::processMPPAL2(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& source = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[6]->getUnsigned()
-    );
-    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[7]->getUnsigned()
-    );
-    const auto& r = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[4]->getUnsigned(), _params[10]->getUnsigned()
-    );
-    const auto& g = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[3]->getUnsigned(), _params[9]->getUnsigned()
-    );
-    const auto& b = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[2]->getUnsigned(), _params[8]->getUnsigned()
-    );
-    auto num_entries = _params[11]->getUnsigned() + 1;
-    code_gen->AddOutputLine((
-      boost::format(
-        "-- multiply RGB(%3%, %4%, %5%) by %6% entries of palette stored at position %1%, "
-        "storing result in position %2%"
-      ) % source % destination % r % g % b % num_entries).str());
-}
-
-void FF7BackgroundInstruction::processSTPLS(CodeGenerator* code_gen){
-    auto source = _params[0]->getUnsigned();
-    auto destination = _params[1]->getUnsigned();
-    auto start_clut = _params[2]->getUnsigned();
-    auto num_entries = _params[3]->getUnsigned() + 1;
-    code_gen->AddOutputLine((
-      boost::format("-- store palette %1% to position %2%, start CLUT index %3%, %4% entries")
-      % source % destination % start_clut % num_entries
-    ).str());
-}
-
-void FF7BackgroundInstruction::processLDPLS(CodeGenerator* code_gen){
-    auto source = _params[0]->getUnsigned();
-    auto destination = _params[1]->getUnsigned();
-    auto startClut = _params[2]->getUnsigned();
-    auto num_entries = _params[3]->getUnsigned() + 1;
-    code_gen->AddOutputLine((
-      boost::format("-- load palette %2% from position %1%, start CLUT index %3%, %4% entries")
-      % source % destination % startClut % num_entries
-    ).str());
-}
-
-void FF7CameraInstruction::processInst(
-  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
-){
-    FunctionMetaData md(func._metadata);
-    switch (_opcode){
-    case OPCODE::NFADE: processNFADE(code_gen); break;
-    case OPCODE::SHAKE: WriteTodo(code_gen, md.GetEntityName(), "SHAKE"); break;
-    case OPCODE::SCRLO: WriteTodo(code_gen, md.GetEntityName(), "SCRLO"); break;
-    case OPCODE::SCRLC: WriteTodo(code_gen, md.GetEntityName(), "SCRLC"); break;
-    case OPCODE::SCR2D: processSCR2D(code_gen); break;
-    case OPCODE::SCRCC: WriteTodo(code_gen, md.GetEntityName(), "SCRCC"); break;
-    case OPCODE::SCR2DC: processSCR2DC(code_gen); break;
-    case OPCODE::SCRLW: WriteTodo(code_gen, md.GetEntityName(), "SCRLW"); break;
-    case OPCODE::SCR2DL: WriteTodo(code_gen, md.GetEntityName(), "SCR2DL"); break;
-    case OPCODE::VWOFT: WriteTodo(code_gen, md.GetEntityName(), "VWOFT"); break;
-    case OPCODE::FADE: processFADE(code_gen); break;
-    case OPCODE::FADEW: WriteTodo(code_gen, md.GetEntityName(), "FADEW"); break;
-    case OPCODE::SCRLP: WriteTodo(code_gen, md.GetEntityName(), "SCRLP"); break;
-    case OPCODE::MVCAM: WriteTodo(code_gen, md.GetEntityName(), "MVCAM"); break;
-    case OPCODE::SCRLA: WriteTodo(code_gen, md.GetEntityName(), "SCRLA"); break;
-    default:
-        code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
-          md.GetEntityName(), _address, _opcode
-        ));
-    }
-}
-
-void FF7CameraInstruction::processNFADE(CodeGenerator* code_gen){
-    // TODO: Not fully reversed.
-    auto raw_type = _params[4]->getUnsigned();
-    if (raw_type == 0){
-        code_gen->AddOutputLine("-- fade:clear()");
-        return;
-    }
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const std::string type = raw_type == 12 ? "Fade.SUBTRACT" : "Fade.ADD";
-    const auto& r = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[5]->getUnsigned()
-    );
-    const auto& g = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[6]->getUnsigned()
-    );
-    const auto& b = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[2]->getUnsigned(), _params[7]->getUnsigned()
-    );
-    const auto& unknown = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[3]->getUnsigned(), _params[8]->getUnsigned()
-    );
-    code_gen->AddOutputLine(
-      (boost::format("-- fade:fade(%2%, %3%, %4%, %1%, %5%)") % type % r % g % b % unknown).str()
-    );
-}
-
-void FF7CameraInstruction::processSCR2D(CodeGenerator* code_gen){
-    // kUpScaler.
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& x = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getSigned()
-    );
-    const auto& y = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getSigned()
-    );
-    code_gen->AddOutputLine((
-      boost::format("background2d:scroll_to_position(%1% * 3, %2% * 3, Background2D.NONE, 0)")
-      % x % y
-    ).str());
-}
-
-void FF7CameraInstruction::processSCR2DC(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& x = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[4]->getSigned()
-    );
-    const auto& y = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[5]->getSigned()
-    );
-    const auto& speed = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[3]->getUnsigned(), _params[6]->getUnsigned(),
-      FieldCodeGenerator::ValueType::Float, 30.0f
-    );
-    code_gen->AddOutputLine((
-      boost::format("background2d:scroll_to_position(%1% * 3, %2% * 3, Background2D.SMOOTH, %3%)")
-      % x % y % speed
-    ).str());
-}
-
-void FF7CameraInstruction::processFADE(CodeGenerator* code_gen){
-    // TODO: not fully reversed
-    auto raw_type = _params[8]->getUnsigned();
-    std::string type;
-    switch (raw_type) {
-        case 1:
-        case 2:
-        case 7:
-        case 8:
-            type = "Fade.SUBTRACT";
-            break;
-        case 4: code_gen->AddOutputLine("-- fade:black()"); return;
-        default: type = "Fade.ADD"; break;
-    }
-
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& r = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[4]->getUnsigned()
-    );
-    const auto& g = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[5]->getUnsigned()
-    );
-    const auto& b = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[2]->getUnsigned(), _params[6]->getUnsigned()
-    );
-    // TODO: needs to be divided by 30.0f?
-    auto speed = _params[7]->getUnsigned();
-    auto start = _params[9]->getUnsigned();
-    code_gen->AddOutputLine((
-      boost::format("-- fade:fade(%2%, %3%, %4%, %1%, %5%, %6%)") % type % r % g % b % speed % start
-    ).str());
-}
-
-void FF7AudioVideoInstruction::processInst(
-  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
-){
-    FunctionMetaData md(func._metadata);
-    switch (_opcode){
-        case OPCODE::BGMOVIE: WriteTodo(code_gen, md.GetEntityName(), "BGMOVIE"); break;
-        case OPCODE::AKAO2: processAKAO2(code_gen); break;
-        case OPCODE::MUSIC: processMUSIC(code_gen); break;
-        case OPCODE::SOUND: processSOUND(code_gen); break;
-        case OPCODE::AKAO: processAKAO(code_gen); break;
-        case OPCODE::MUSVT: WriteTodo(code_gen, md.GetEntityName(), "MUSVT"); break;
-        case OPCODE::MUSVM: WriteTodo(code_gen, md.GetEntityName(), "MUSVM"); break;
-        case OPCODE::MULCK: processMULCK(code_gen); break;
-        case OPCODE::BMUSC: WriteTodo(code_gen, md.GetEntityName(), "BMUSC"); break;
-        case OPCODE::CHMPH: WriteTodo(code_gen, md.GetEntityName(), "CHMPH"); break;
-        case OPCODE::PMVIE: processPMVIE(code_gen); break;
-        case OPCODE::MOVIE: processMOVIE(code_gen); break;
-        case OPCODE::MVIEF: processMVIEF(code_gen); break;
-        case OPCODE::FMUSC: WriteTodo(code_gen, md.GetEntityName(), "FMUSC"); break;
-        case OPCODE::CMUSC: WriteTodo(code_gen, md.GetEntityName(), "CMUSC"); break;
-        case OPCODE::CHMST: WriteTodo(code_gen, md.GetEntityName(), "CHMST"); break;
-        default:
-            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
-              md.GetEntityName(), _address, _opcode
-            ));
-    }
-}
-
-void FF7AudioVideoInstruction::processAKAO2(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& param1 = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[7]->getUnsigned()
-    );
-    const auto& param2 = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[8]->getUnsigned()
-    );
-    const auto& param3 = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[2]->getUnsigned(), _params[9]->getUnsigned()
-    );
-    const auto& param4 = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[3]->getUnsigned(), _params[10]->getUnsigned()
-    );
-    const auto& param5 = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[5]->getUnsigned(), _params[11]->getUnsigned()
-    );
-    auto op = _params[6]->getUnsigned();
-    code_gen->AddOutputLine((
-      boost::format("-- music:execute_akao(0x%6$02x, %1%, %2%, %3%, %4%, %5%)")
-      % param1 % param2 % param3 % param4 % param5 % op
-    ).str());
-}
-
-void FF7AudioVideoInstruction::processMUSIC(CodeGenerator* code_gen){
-    code_gen->AddOutputLine((
-      boost::format("-- music:execute_akao(0x10, pointer_to_field_AKAO_%1%)")
-      % _params[0]->getUnsigned()
-    ).str());
-}
-
-void FF7AudioVideoInstruction::processSOUND(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& soundId = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
-    );
-    const auto& panning = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
-    );
-    code_gen->AddOutputLine(
-      (boost::format("-- music:execute_akao(0x20, %1%, %2%)") % soundId % panning).str()
-    );
-}
-
-void FF7AudioVideoInstruction::processAKAO(CodeGenerator* code_gen){
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& param1 = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[0]->getUnsigned(), _params[7]->getUnsigned()
-    );
-    const auto& param2 = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[8]->getUnsigned()
-    );
-    const auto& param3 = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[2]->getUnsigned(), _params[9]->getUnsigned()
-    );
-    const auto& param4 = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[3]->getUnsigned(), _params[10]->getUnsigned()
-    );
-    const auto& param5 = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[5]->getUnsigned(), _params[11]->getUnsigned()
-    );
-    auto op = _params[6]->getUnsigned();
-    code_gen->AddOutputLine((
-      boost::format("-- music:execute_akao(0x%6$02x, %1%, %2%, %3%, %4%, %5%)")
-      % param1 % param2 % param3 % param4 % param5 % op
-    ).str());
-}
-
-void FF7AudioVideoInstruction::processMULCK(CodeGenerator* code_gen){
-    code_gen->AddOutputLine((
-      boost::format("-- music:lock(%1%)")
-      % FieldCodeGenerator::FormatBool(_params[0]->getUnsigned())
-    ).str());
-}
-
-void FF7AudioVideoInstruction::processPMVIE(CodeGenerator* code_gen){
-    code_gen->AddOutputLine(
-      (boost::format("-- field:movie_set(%1%)") % _params[0]->getUnsigned()
-    ).str());
-}
-
-void FF7AudioVideoInstruction::processMOVIE(CodeGenerator* code_gen){
-    code_gen->AddOutputLine("-- field:play_movie()");
-}
-
-void FF7AudioVideoInstruction::processMVIEF(CodeGenerator* code_gen){
-    // TODO: Check for assignment to value.
-    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
-    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
-      cg->GetFormatter(), _params[1]->getUnsigned(), _params[2]->getUnsigned());
-    code_gen->AddOutputLine(
-      (boost::format("-- %1% = field:get_movie_frame()") % destination).str()
-    );
-}
-
-void FF7UncategorizedInstruction::processInst(
-  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
-){
-    FunctionMetaData md(func._metadata);
-    switch (_opcode){
-        case OPCODE::MPDSP: WriteTodo(code_gen, md.GetEntityName(), "MPDSP"); break;
-        case OPCODE::SETX: WriteTodo(code_gen, md.GetEntityName(), "SETX"); break;
-        case OPCODE::GETX: WriteTodo(code_gen, md.GetEntityName(), "GETX"); break;
-        case OPCODE::SEARCHX: WriteTodo(code_gen, md.GetEntityName(), "SEARCHX"); break;
-        default:
-            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
-              md.GetEntityName(), _address, _opcode)
-            );
-    }
-}
-
-void FF7NoOperationInstruction::processInst(
-  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
-){}

+ 207 - 0
V-Gears-Installer/src/decompiler/field/instruction/FieldBackgroundInstruction.cpp

@@ -0,0 +1,207 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "decompiler/field/instruction/FieldBackgroundInstruction.h"
+#include "decompiler/field/FieldEngine.h"
+#include "decompiler/field/FieldCodeGenerator.h"
+#include "decompiler/field/FieldDisassembler.h"
+
+void FieldBackgroundInstruction::ProcessInst(
+  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
+){
+    FunctionMetaData md(func._metadata);
+    switch (_opcode){
+        case OPCODE::BGPDH: WriteTodo(code_gen, md.GetEntityName(), "BGPDH");break;
+        case OPCODE::BGSCR: WriteTodo(code_gen, md.GetEntityName(), "BGSCR"); break;
+        case OPCODE::MPPAL: WriteTodo(code_gen, md.GetEntityName(), "MPPAL"); break;
+        case OPCODE::BGON: ProcessBGON(code_gen); break;
+        case OPCODE::BGOFF: ProcessBGOFF(code_gen); break;
+        case OPCODE::BGROL: WriteTodo(code_gen, md.GetEntityName(), "BGROL"); break;
+        case OPCODE::BGROL2: WriteTodo(code_gen, md.GetEntityName(), "BGROL2"); break;
+        case OPCODE::BGCLR: ProcessBGCLR(code_gen); break;
+        case OPCODE::STPAL: ProcessSTPAL(code_gen); break;
+        case OPCODE::LDPAL: ProcessLDPAL(code_gen); break;
+        case OPCODE::CPPAL: ProcessCPPAL(code_gen); break;
+        case OPCODE::RTPAL: WriteTodo(code_gen, md.GetEntityName(), "RTPAL"); break;
+        case OPCODE::ADPAL: ProcessADPAL(code_gen); break;
+        case OPCODE::MPPAL2: ProcessMPPAL2(code_gen); break;
+        case OPCODE::STPLS: ProcessSTPLS(code_gen); break;
+        case OPCODE::LDPLS: ProcessLDPLS(code_gen); break;
+        case OPCODE::CPPAL2: WriteTodo(code_gen, md.GetEntityName(), "CPPAL2"); break;
+        case OPCODE::ADPAL2: WriteTodo(code_gen, md.GetEntityName(), "ADPAL2"); break;
+        case OPCODE::RTPAL2: WriteTodo(code_gen, md.GetEntityName(), "RTPAL2"); break;
+        default:
+            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
+              md.GetEntityName(), _address, _opcode
+            ));
+    }
+}
+
+void FieldBackgroundInstruction::ProcessBGON(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& background_id = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
+    );
+    const auto& layer_id = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
+    );
+    code_gen->AddOutputLine(
+      (boost::format("-- field:background_on(%1%, %2%)") % background_id % layer_id).str()
+    );
+}
+
+void FieldBackgroundInstruction::ProcessBGOFF(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& background_id = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
+    );
+    const auto& layer_id = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
+    );
+    code_gen->AddOutputLine(
+      (boost::format("-- field:background_off(%1%, %2%)") % background_id % layer_id).str()
+    );
+}
+
+void FieldBackgroundInstruction::ProcessBGCLR(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& background_id = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[2]->getUnsigned()
+    );
+    code_gen->AddOutputLine(
+      (boost::format("-- field:background_clear(%1%)") % background_id).str()
+    );
+}
+
+void FieldBackgroundInstruction::ProcessSTPAL(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& source = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
+    );
+    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
+    );
+    auto num_entries = _params[4]->getUnsigned() + 1;
+    code_gen->AddOutputLine((
+      boost::format("-- store palette %1% to position %2%, start CLUT index 0, %3% entries")
+      % source % destination % num_entries
+    ).str());
+}
+
+void FieldBackgroundInstruction::ProcessLDPAL(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& source = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
+    );
+    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
+    );
+    auto num_entries = _params[4]->getUnsigned() + 1;
+    code_gen->AddOutputLine((
+      boost::format("-- load palette %2% from position %1%, start CLUT index 0, %3% entries")
+      % source % destination % num_entries
+    ).str());
+}
+
+void FieldBackgroundInstruction::ProcessCPPAL(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& source = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
+    );
+    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
+    );
+    auto num_entries = _params[4]->getUnsigned() + 1;
+    code_gen->AddOutputLine((
+      boost::format("-- copy palette %1% to palette %2%, %3% entries")
+      % source % destination % num_entries
+    ).str());
+}
+
+void FieldBackgroundInstruction::ProcessADPAL(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& source = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[6]->getUnsigned()
+    );
+    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[7]->getUnsigned()
+    );
+    const auto& r = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[4]->getUnsigned(), _params[10]->getUnsigned()
+    );
+    const auto& g = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[3]->getUnsigned(), _params[9]->getUnsigned()
+    );
+    const auto& b = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[2]->getUnsigned(), _params[8]->getUnsigned()
+    );
+    auto num_entries = _params[11]->getUnsigned() + 1;
+    code_gen->AddOutputLine((
+      boost::format(
+        "-- add RGB(%3%, %4%, %5%) to %6% entries of palette stored at position %1%, "
+        "storing result in position %2%"
+      ) % source % destination % r % g % b % num_entries
+    ).str());
+}
+
+void FieldBackgroundInstruction::ProcessMPPAL2(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& source = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[6]->getUnsigned()
+    );
+    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[7]->getUnsigned()
+    );
+    const auto& r = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[4]->getUnsigned(), _params[10]->getUnsigned()
+    );
+    const auto& g = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[3]->getUnsigned(), _params[9]->getUnsigned()
+    );
+    const auto& b = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[2]->getUnsigned(), _params[8]->getUnsigned()
+    );
+    auto num_entries = _params[11]->getUnsigned() + 1;
+    code_gen->AddOutputLine((
+      boost::format(
+        "-- multiply RGB(%3%, %4%, %5%) by %6% entries of palette stored at position %1%, "
+        "storing result in position %2%"
+      ) % source % destination % r % g % b % num_entries).str());
+}
+
+void FieldBackgroundInstruction::ProcessSTPLS(CodeGenerator* code_gen){
+    auto source = _params[0]->getUnsigned();
+    auto destination = _params[1]->getUnsigned();
+    auto start_clut = _params[2]->getUnsigned();
+    auto num_entries = _params[3]->getUnsigned() + 1;
+    code_gen->AddOutputLine((
+      boost::format("-- store palette %1% to position %2%, start CLUT index %3%, %4% entries")
+      % source % destination % start_clut % num_entries
+    ).str());
+}
+
+void FieldBackgroundInstruction::ProcessLDPLS(CodeGenerator* code_gen){
+    auto source = _params[0]->getUnsigned();
+    auto destination = _params[1]->getUnsigned();
+    auto startClut = _params[2]->getUnsigned();
+    auto num_entries = _params[3]->getUnsigned() + 1;
+    code_gen->AddOutputLine((
+      boost::format("-- load palette %2% from position %1%, start CLUT index %3%, %4% entries")
+      % source % destination % startClut % num_entries
+    ).str());
+}

+ 141 - 0
V-Gears-Installer/src/decompiler/field/instruction/FieldCameraInstruction.cpp

@@ -0,0 +1,141 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "decompiler/field/instruction/FieldCameraInstruction.h"
+#include "decompiler/field/FieldEngine.h"
+#include "decompiler/field/FieldCodeGenerator.h"
+#include "decompiler/field/FieldDisassembler.h"
+
+void FieldCameraInstruction::ProcessInst(
+  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
+){
+    FunctionMetaData md(func._metadata);
+    switch (_opcode){
+    case OPCODE::NFADE: ProcessNFADE(code_gen); break;
+    case OPCODE::SHAKE: WriteTodo(code_gen, md.GetEntityName(), "SHAKE"); break;
+    case OPCODE::SCRLO: WriteTodo(code_gen, md.GetEntityName(), "SCRLO"); break;
+    case OPCODE::SCRLC: WriteTodo(code_gen, md.GetEntityName(), "SCRLC"); break;
+    case OPCODE::SCR2D: ProcessSCR2D(code_gen); break;
+    case OPCODE::SCRCC: WriteTodo(code_gen, md.GetEntityName(), "SCRCC"); break;
+    case OPCODE::SCR2DC: ProcessSCR2DC(code_gen); break;
+    case OPCODE::SCRLW: WriteTodo(code_gen, md.GetEntityName(), "SCRLW"); break;
+    case OPCODE::SCR2DL: WriteTodo(code_gen, md.GetEntityName(), "SCR2DL"); break;
+    case OPCODE::VWOFT: WriteTodo(code_gen, md.GetEntityName(), "VWOFT"); break;
+    case OPCODE::FADE: ProcessFADE(code_gen); break;
+    case OPCODE::FADEW: WriteTodo(code_gen, md.GetEntityName(), "FADEW"); break;
+    case OPCODE::SCRLP: WriteTodo(code_gen, md.GetEntityName(), "SCRLP"); break;
+    case OPCODE::MVCAM: WriteTodo(code_gen, md.GetEntityName(), "MVCAM"); break;
+    case OPCODE::SCRLA: WriteTodo(code_gen, md.GetEntityName(), "SCRLA"); break;
+    default:
+        code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
+          md.GetEntityName(), _address, _opcode
+        ));
+    }
+}
+
+void FieldCameraInstruction::ProcessNFADE(CodeGenerator* code_gen){
+    // TODO: Not fully reversed.
+    auto raw_type = _params[4]->getUnsigned();
+    if (raw_type == 0){
+        code_gen->AddOutputLine("-- fade:clear()");
+        return;
+    }
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const std::string type = raw_type == 12 ? "Fade.SUBTRACT" : "Fade.ADD";
+    const auto& r = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[5]->getUnsigned()
+    );
+    const auto& g = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[6]->getUnsigned()
+    );
+    const auto& b = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[2]->getUnsigned(), _params[7]->getUnsigned()
+    );
+    const auto& unknown = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[3]->getUnsigned(), _params[8]->getUnsigned()
+    );
+    code_gen->AddOutputLine(
+      (boost::format("-- fade:fade(%2%, %3%, %4%, %1%, %5%)") % type % r % g % b % unknown).str()
+    );
+}
+
+void FieldCameraInstruction::ProcessSCR2D(CodeGenerator* code_gen){
+    // kUpScaler.
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& x = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getSigned()
+    );
+    const auto& y = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getSigned()
+    );
+    code_gen->AddOutputLine((
+      boost::format("background2d:scroll_to_position(%1% * 3, %2% * 3, Background2D.NONE, 0)")
+      % x % y
+    ).str());
+}
+
+void FieldCameraInstruction::ProcessSCR2DC(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& x = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[4]->getSigned()
+    );
+    const auto& y = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[5]->getSigned()
+    );
+    const auto& speed = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[3]->getUnsigned(), _params[6]->getUnsigned(),
+      FieldCodeGenerator::ValueType::Float, 30.0f
+    );
+    code_gen->AddOutputLine((
+      boost::format("background2d:scroll_to_position(%1% * 3, %2% * 3, Background2D.SMOOTH, %3%)")
+      % x % y % speed
+    ).str());
+}
+
+void FieldCameraInstruction::ProcessFADE(CodeGenerator* code_gen){
+    // TODO: not fully reversed
+    auto raw_type = _params[8]->getUnsigned();
+    std::string type;
+    switch (raw_type) {
+        case 1:
+        case 2:
+        case 7:
+        case 8:
+            type = "Fade.SUBTRACT";
+            break;
+        case 4: code_gen->AddOutputLine("-- fade:black()"); return;
+        default: type = "Fade.ADD"; break;
+    }
+
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& r = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[4]->getUnsigned()
+    );
+    const auto& g = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[5]->getUnsigned()
+    );
+    const auto& b = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[2]->getUnsigned(), _params[6]->getUnsigned()
+    );
+    // TODO: needs to be divided by 30.0f?
+    auto speed = _params[7]->getUnsigned();
+    auto start = _params[9]->getUnsigned();
+    code_gen->AddOutputLine((
+      boost::format("-- fade:fade(%2%, %3%, %4%, %1%, %5%, %6%)") % type % r % g % b % speed % start
+    ).str());
+}

+ 124 - 0
V-Gears-Installer/src/decompiler/field/instruction/FieldCondJumpInstruction.cpp

@@ -0,0 +1,124 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "decompiler/field/instruction/FieldCondJumpInstruction.h"
+#include "decompiler/field/FieldEngine.h"
+#include "decompiler/field/FieldCodeGenerator.h"
+#include "decompiler/field/FieldDisassembler.h"
+
+void FieldCondJumpInstruction::ProcessInst(
+  Function& function, ValueStack &stack, Engine* engine, CodeGenerator* code_gen
+){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    std::string func_name;
+    if (_opcode == OPCODE::IFKEYON) func_name = "entity_manager:is_key_on";
+    else if (_opcode == OPCODE::IFKEYOFF) func_name = "entity_manager:is_key_off";
+    else if (_opcode == OPCODE::IFKEY) func_name = "Key";
+    else if (_opcode == OPCODE::IFMEMBQ) func_name = "IFMEMBQ";
+    else if (_opcode == OPCODE::IFPRTYQ) func_name = "IFPRTYQ";
+    // If condition is a function, add and stop.
+    if (!func_name.empty()){
+        uint32 param = _params[0]->getUnsigned();
+        // Special cases. The first parameter of IFKEY, IFKEYON and IFKEYOFF
+        // can be ORed to get the individual keys, but there are two invalid
+        // ones: 512 and 1024. They must be XORed.
+        if (
+          _opcode == OPCODE::IFKEY
+          || _opcode == OPCODE::IFKEYON
+          || _opcode == OPCODE::IFKEYOFF
+        ){
+            if (param >= 1024) param = param ^ 1024;
+            if (param >= 512) param = param ^ 512;
+        }
+        ValuePtr v = new UnqotedStringValue(func_name + "(" + std::to_string(param) + ")");
+        stack.push(v);
+        return;
+    }
+    std::string op;
+    uint32 type = _params[4]->getUnsigned();
+    const auto& source = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
+    );
+    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
+    );
+    switch (type){
+        case 0: op = "=="; break;
+        case 1: op = "~="; break;
+        case 2: op = ">"; break;
+        case 3: op = "<"; break;
+        case 4: op = ">="; break;
+        case 5: op = "<="; break;
+        case 6: op = "&"; break;
+        case 7: op = "^"; break;
+        case 8: op = "|"; break;
+        case 9:
+            {
+                // TODO: Use FormatValueOrVariable
+                op = "bit(" + _params[0]->getString() + ", " + _params[2]->getString()
+                  + ", " + destination + ") == 1";
+                ValuePtr v = new UnqotedStringValue(op);
+                stack.push(v);
+            }
+            return;
+        case 0xA:
+            {
+                // TODO: Use FormatValueOrVariable
+                op = "bit(" + _params[0]->getString() + ", " + _params[2]->getString()
+                  + ", " + destination + ") == 0";
+                ValuePtr v = new UnqotedStringValue(op);
+                stack.push(v);
+            }
+            return;
+        default: throw UnknownConditionalOperatorException(_address, type);
+    }
+    ValuePtr v = new BinaryOpValue(new VarValue(source), new VarValue(destination), op);
+    stack.push(v);
+}
+
+uint32 FieldCondJumpInstruction::GetDestAddress() const{
+    uint32 params_size = 0;
+    uint32 jump_param_index = 5;
+    switch (_opcode){
+        case OPCODE::IFUB: params_size = 5; break;
+        case OPCODE::IFUBL: params_size = 5; break;
+        case OPCODE::IFSW: params_size = 7; break;
+        case OPCODE::IFSWL: params_size = 7; break;
+        case OPCODE::IFUW: params_size = 7; break;
+        case OPCODE::IFUWL: params_size = 7; break;
+        case OPCODE::IFKEYON:
+        case OPCODE::IFKEYOFF:
+        case OPCODE::IFKEY:
+            params_size = 3;
+            jump_param_index = 1;
+            break;
+        case OPCODE::IFPRTYQ:
+        case OPCODE::IFMEMBQ:
+            params_size = 2;
+            jump_param_index = 1;
+            break;
+        default: throw UnknownJumpTypeException(_address, _opcode);
+    }
+    return _address + _params[jump_param_index]->getUnsigned() + params_size;
+}
+
+std::ostream& FieldCondJumpInstruction::Print(std::ostream &output) const{
+    Instruction::Print(output);
+    output << " (False target address: 0x" << std::hex << GetDestAddress() << std::dec << ")";
+    return output;
+}

+ 123 - 0
V-Gears-Installer/src/decompiler/field/instruction/FieldControlFlowInstruction.cpp

@@ -0,0 +1,123 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "decompiler/field/instruction/FieldControlFlowInstruction.h"
+#include "decompiler/field/FieldEngine.h"
+#include "decompiler/field/FieldCodeGenerator.h"
+#include "decompiler/field/FieldDisassembler.h"
+
+void FieldControlFlowInstruction::ProcessInst(
+  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
+){
+    FieldEngine& eng = static_cast<FieldEngine&>(*engine);
+    FunctionMetaData md(func._metadata);
+    switch (_opcode){
+        case OPCODE::RET:
+            // A few notes in RET.
+            // - Lua requires all functions to end with a return.
+            // - Lua doesn's like returns if not followed by an end.
+            // - Don't add a return statement to on_start functions.
+            //     Game 'init' and 'main' code is concatenated in V-Gears. If the
+            //     'main' return is kept, the code of 'main' is never executed.
+            //     There are safeguards forfunctions without a return in the end,
+            //     so it's OK not to include it here.
+            if (func._name != "on_start") code_gen->AddOutputLine("do return 0 end");
+            break;
+        case OPCODE::REQ: ProcessREQ(code_gen, eng); break;
+        case OPCODE::REQSW: ProcessREQSW(code_gen, eng); break;
+        case OPCODE::REQEW: ProcessREQEW(code_gen, eng); break;
+        case OPCODE::PREQ: WriteTodo(code_gen, md.GetEntityName(), "PREQ"); break;
+        case OPCODE::PRQSW: WriteTodo(code_gen, md.GetEntityName(), "PRQSW"); break;
+        case OPCODE::PRQEW: WriteTodo(code_gen, md.GetEntityName(), "PRQEW"); break;
+        case OPCODE::RETTO: ProcessRETTO(code_gen); break;
+        case OPCODE::WAIT: ProcessWAIT(code_gen); break;
+        default:
+            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
+              md.GetEntityName(), _address, _opcode
+            ));
+    }
+}
+
+void FieldControlFlowInstruction::ProcessREQ(
+  CodeGenerator* code_gen, const FieldEngine& engine
+){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& entity = engine.EntityByIndex(_params[0]->getSigned());
+    const auto& script_name = cg->GetFormatter().FunctionName(
+      entity.GetName(), entity.FunctionByIndex(_params[2]->getUnsigned())
+    );
+    auto priority = _params[1]->getUnsigned();
+    code_gen->AddOutputLine((
+      boost::format("script:request(Script.ENTITY, \"%1%\", \"%2%\", %3%)")
+      % entity.GetName() % script_name % priority
+    ).str());
+}
+
+void FieldControlFlowInstruction::ProcessREQSW(
+  CodeGenerator* code_gen, const FieldEngine& engine
+){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& entity = engine.EntityByIndex(_params[0]->getSigned());
+    const auto& script_name = cg->GetFormatter().FunctionName(
+      entity.GetName(), entity.FunctionByIndex(_params[2]->getUnsigned())
+    );
+    auto priority = _params[1]->getUnsigned();
+    code_gen->AddOutputLine((
+      boost::format("script:request_start_sync(Script.ENTITY, \"%1%\", \"%2%\", %3%)")
+      % entity.GetName() % script_name % priority
+    ).str());
+}
+
+void FieldControlFlowInstruction::ProcessREQEW(
+  CodeGenerator* code_gen, const FieldEngine& engine
+){
+    try{
+        FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+        const auto& entity = engine.EntityByIndex(_params[0]->getSigned());
+        const auto& script_name = cg->GetFormatter().FunctionName(
+          entity.GetName(), entity.FunctionByIndex(_params[2]->getUnsigned())
+        );
+        auto priority = _params[1]->getUnsigned();
+        code_gen->AddOutputLine((
+          boost::format("script:request_end_sync(Script.ENTITY, \"%1%\", \"%2%\", %3%)")
+          % entity.GetName() % script_name % priority
+        ).str());
+    }
+    catch (const InternalDecompilerError&){
+        code_gen->AddOutputLine((
+          boost::format("-- ERROR call to non existing function index %1%")
+          % _params[2]->getUnsigned()
+        ).str());
+    }
+}
+
+void FieldControlFlowInstruction::ProcessRETTO(CodeGenerator* code_gen){
+    auto entity_index = _params[0]->getUnsigned();
+    auto priority = _params[1]->getUnsigned();
+    code_gen->AddOutputLine((
+      boost::format("-- return_to(script_id_in_current_entity=%2%, priority=%1%)")
+      % entity_index % priority
+    ).str());
+}
+
+void FieldControlFlowInstruction::ProcessWAIT(CodeGenerator* code_gen){
+    code_gen->AddOutputLine((
+      boost::format("script:wait(%1%)") % (_params[0]->getUnsigned() / 30.0f)
+    ).str());
+}
+

+ 266 - 0
V-Gears-Installer/src/decompiler/field/instruction/FieldMathInstruction.cpp

@@ -0,0 +1,266 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "decompiler/field/instruction/FieldMathInstruction.h"
+#include "decompiler/field/FieldEngine.h"
+#include "decompiler/field/FieldCodeGenerator.h"
+#include "decompiler/field/FieldDisassembler.h"
+
+void FieldMathInstruction::ProcessInst(
+  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
+){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    FunctionMetaData md(func._metadata);
+    switch (_opcode){
+        case OPCODE::PLUS_: ProcessSaturatedPLUS(code_gen); break;
+        case OPCODE::PLUS2_: ProcessSaturatedPLUS2(code_gen); break;
+        case OPCODE::MINUS_: ProcessSaturatedMINUS(code_gen); break;
+        case OPCODE::MINUS2_: ProcessSaturatedMINUS2(code_gen); break;
+        case OPCODE::INC_: ProcessSaturatedINC(code_gen); break;
+        case OPCODE::INC2_: ProcessSaturatedINC2(code_gen); break;
+        case OPCODE::DEC_: ProcessSaturatedDEC(code_gen); break;
+        case OPCODE::DEC2_: ProcessSaturatedDEC2(code_gen); break;
+        case OPCODE::RDMSD: ProcessRDMSD(code_gen); break;
+        case OPCODE::SETBYTE:
+        case OPCODE::SETWORD:
+            ProcessSETBYTE_SETWORD(code_gen);
+            break;
+        case OPCODE::BITON: ProcessBITON(code_gen); break;
+        case OPCODE::BITOFF: ProcessBITOFF(code_gen); break;
+        case OPCODE::BITXOR: WriteTodo(code_gen, md.GetEntityName(), "BITXOR"); break;
+        case OPCODE::PLUS:
+        case OPCODE::PLUS2:
+            ProcessPLUSx_MINUSx(code_gen, "+");
+            break;
+        case OPCODE::MINUS:
+        case OPCODE::MINUS2:
+            ProcessPLUSx_MINUSx(code_gen, "-");
+            break;
+        case OPCODE::MUL: WriteTodo(code_gen, md.GetEntityName(), "MUL"); break;
+        case OPCODE::MUL2: WriteTodo(code_gen, md.GetEntityName(), "MUL2"); break;
+        case OPCODE::DIV: WriteTodo(code_gen, md.GetEntityName(), "DIV"); break;
+        case OPCODE::DIV2: WriteTodo(code_gen, md.GetEntityName(), "DIV2"); break;
+        case OPCODE::MOD:
+            {
+                const uint32 source_bank = _params[0]->getUnsigned();
+                const uint32 source_address_or_value = _params[2]->getUnsigned();
+                auto source = FieldCodeGenerator::FormatValueOrVariable(
+                  cg->GetFormatter(), source_bank, source_address_or_value
+                );
+                const uint32 dest_bank = _params[1]->getUnsigned();
+                const uint32 dest_address = _params[3]->getUnsigned();
+                auto dest = FieldCodeGenerator::FormatValueOrVariable(
+                  cg->GetFormatter(), dest_bank, dest_address
+                );
+                code_gen->AddOutputLine(
+                  source + " = " + source + " % " + dest + code_gen->TargetLang().LineTerminator()
+                );
+            }
+        break;
+        case OPCODE::MOD2: WriteTodo(code_gen, md.GetEntityName(), "MOD2"); break;
+        case OPCODE::AND: WriteTodo(code_gen, md.GetEntityName(), "AND"); break;
+        case OPCODE::AND2: WriteTodo(code_gen, md.GetEntityName(), "AND2"); break;
+        case OPCODE::OR: WriteTodo(code_gen, md.GetEntityName(), "OR"); break;
+        case OPCODE::OR2: WriteTodo(code_gen, md.GetEntityName(), "OR2"); break;
+        case OPCODE::XOR: WriteTodo(code_gen, md.GetEntityName(), "XOR"); break;
+        case OPCODE::XOR2: WriteTodo(code_gen, md.GetEntityName(), "XOR2"); break;
+        case OPCODE::INC:
+        case OPCODE::INC2:
+            ProcessINCx_DECx(code_gen, "+");
+            break;
+        case OPCODE::DEC:
+        case OPCODE::DEC2:
+            ProcessINCx_DECx(code_gen, "-");
+            break;
+        case OPCODE::RANDOM: ProcessRANDOM(code_gen); break;
+        case OPCODE::LBYTE: WriteTodo(code_gen, md.GetEntityName(), "LBYTE"); break;
+        case OPCODE::HBYTE: WriteTodo(code_gen, md.GetEntityName(), "HBYTE"); break;
+        case OPCODE::TWOBYTE: WriteTodo(code_gen, md.GetEntityName(), "2BYTE"); break;
+        case OPCODE::SIN: WriteTodo(code_gen, md.GetEntityName(), "SIN"); break;
+        case OPCODE::COS: WriteTodo(code_gen, md.GetEntityName(), "COS"); break;
+        default:
+            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
+              md.GetEntityName(), _address, _opcode
+            ));
+    }
+}
+
+void FieldMathInstruction::ProcessSaturatedPLUS(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    // TODO: Check for assignment to value.
+    const auto& lhs = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
+    );
+    const auto& rhs = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
+    );
+    // TODO: Respect destination bank sizes and negative wrap-around.
+    code_gen->AddOutputLine((boost::format("%1% = %1% + %2%") % lhs % rhs).str());
+    code_gen->AddOutputLine((boost::format("--if (%1% > 255); %1% = 255; end") % lhs).str());
+}
+
+void FieldMathInstruction::ProcessSaturatedPLUS2(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    // TODO: Check for assignment to value.
+    const auto& lhs = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
+    );
+    const auto& rhs = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
+    );
+    // TODO: Respect destination bank sizes and negative wrap-around.
+    code_gen->AddOutputLine((boost::format("%1% = %1% + %2%") % lhs % rhs).str());
+    code_gen->AddOutputLine((boost::format("--if (%1% > 32767); %1% = 32767; end") % lhs).str());
+}
+
+void FieldMathInstruction::ProcessSaturatedMINUS(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    // TODO: Check for assignment to value.
+    const auto& lhs = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
+    );
+    const auto& rhs = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
+    );
+    // TODO: Respect destination bank sizes and positive wrap-around.
+    code_gen->AddOutputLine((boost::format("%1% = %1% - %2%") % lhs % rhs).str());
+    code_gen->AddOutputLine((boost::format("--if (%1% < 0); %1% = 0; end") % lhs).str());
+}
+
+void FieldMathInstruction::ProcessSaturatedMINUS2(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    // TODO: Check for assignment to value.
+    const auto& lhs = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
+    );
+    const auto& rhs = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
+    );
+    // TODO: Respect destination bank sizes and positive wrap-around.
+    code_gen->AddOutputLine((boost::format("%1% = %1% - %2%") % lhs % rhs).str());
+    code_gen->AddOutputLine((boost::format("--if (%1% < 0); %1% = 0; end") % lhs).str());
+}
+
+void FieldMathInstruction::ProcessSaturatedINC(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    // TODO: Check for assignment to value.
+    const auto& dest = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[1]->getUnsigned()
+    );
+    // TODO: Respect destination bank sizes and negative wrap-around.
+    code_gen->AddOutputLine((boost::format("%1% = %1% + 1") % dest).str());
+    code_gen->AddOutputLine((boost::format("--if (%1% > 255); %1% = 255; end") % dest).str());
+}
+
+void FieldMathInstruction::ProcessSaturatedINC2(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    // TODO: Check for assignment to value.
+    const auto& dest = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[1]->getUnsigned()
+    );
+    // TODO: Respect destination bank sizes and negative wrap-around.
+    code_gen->AddOutputLine((boost::format("%1% = %1% + 1") % dest).str());
+    code_gen->AddOutputLine((boost::format("--if (%1% > 32767); %1% = 32767; end") % dest).str());
+}
+
+void FieldMathInstruction::ProcessSaturatedDEC(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    // TODO: Check for assignment to value.
+    const auto& dest = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[1]->getUnsigned()
+    );
+    // TODO: Respect destination bank sizes and positive wrap-around.
+    code_gen->AddOutputLine((boost::format("%1% = %1% - 1") % dest).str());
+    code_gen->AddOutputLine((boost::format("--if (%1% < 0); %1% = 0; end") % dest).str());
+}
+
+void FieldMathInstruction::ProcessSaturatedDEC2(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    // TODO: Check for assignment to value.
+    const auto& dest = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[1]->getUnsigned()
+    );
+    // TODO: Respect destination bank sizes and positive wrap-around.
+    code_gen->AddOutputLine((boost::format("%1% = %1% - 1") % dest).str());
+    code_gen->AddOutputLine((boost::format("--if (%1% < 0); %1% = 0; end") % dest).str());
+}
+
+void FieldMathInstruction::ProcessRDMSD(CodeGenerator* code_gen){
+    // TODO: we don't have os.time...
+    // TODO: RNG emulation?
+    code_gen->AddOutputLine("math.randomseed(os.time())");
+}
+
+void FieldMathInstruction::ProcessSETBYTE_SETWORD(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    // TODO: Check for assignment to value.
+    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
+    );
+    const auto& source = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
+    );
+    // TODO: respect destination bank sizes (16-bit writes only affect low byte)
+    code_gen->AddOutputLine((boost::format("%1% = %2%") % destination % source).str());
+}
+
+void FieldMathInstruction::ProcessBITON(CodeGenerator* code_gen){
+    code_gen->AddOutputLine((boost::format("bit_on(%1%, %2%, %3%)")
+      % _params[0]->getUnsigned() % _params[2]->getUnsigned() % _params[3]->getUnsigned()
+    ).str());
+}
+
+void FieldMathInstruction::ProcessBITOFF(CodeGenerator* code_gen){
+    code_gen->AddOutputLine((boost::format("bit_off(%1%, %2%, %3%)")
+      % _params[0]->getUnsigned() % _params[2]->getUnsigned() % _params[3]->getUnsigned()
+    ).str());
+}
+
+void FieldMathInstruction::ProcessPLUSx_MINUSx(CodeGenerator* code_gen, const std::string& op){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    // TODO: Check for assignment to value.
+    const auto& lhs = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
+    );
+    const auto& rhs = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
+    );
+    // TODO: repect destination bank sizes and wraparound
+    code_gen->AddOutputLine((boost::format("%1% = %1% %2% %3%") % lhs % op % rhs).str());
+}
+
+void FieldMathInstruction::ProcessINCx_DECx(CodeGenerator* code_gen, const std::string& op){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    // TODO: Check for assignment to value.
+    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[1]->getUnsigned()
+    );
+    // TODO: repect destination bank sizes and wraparound
+    code_gen->AddOutputLine((boost::format("%1% = %1% %2% 1") % destination % op).str());
+}
+
+void FieldMathInstruction::ProcessRANDOM(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    // TODO: Check for assignment to value.
+    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[1]->getUnsigned()
+    );
+    // TODO: Respect destination bank sizes (16-bit writes only affect low byte).
+    // TODO: RNG emulation?
+    code_gen->AddOutputLine((boost::format("%1% = math.random(0, 255)") % destination).str());
+}

+ 145 - 0
V-Gears-Installer/src/decompiler/field/instruction/FieldMediaInstruction.cpp

@@ -0,0 +1,145 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "decompiler/field/instruction/FieldMediaInstruction.h"
+#include "decompiler/field/FieldEngine.h"
+#include "decompiler/field/FieldCodeGenerator.h"
+#include "decompiler/field/FieldDisassembler.h"
+
+void FieldMediaInstruction::ProcessInst(
+  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
+){
+    FunctionMetaData md(func._metadata);
+    switch (_opcode){
+        case OPCODE::BGMOVIE: WriteTodo(code_gen, md.GetEntityName(), "BGMOVIE"); break;
+        case OPCODE::AKAO2: ProcessAKAO2(code_gen); break;
+        case OPCODE::MUSIC: ProcessMUSIC(code_gen); break;
+        case OPCODE::SOUND: ProcessSOUND(code_gen); break;
+        case OPCODE::AKAO: ProcessAKAO(code_gen); break;
+        case OPCODE::MUSVT: WriteTodo(code_gen, md.GetEntityName(), "MUSVT"); break;
+        case OPCODE::MUSVM: WriteTodo(code_gen, md.GetEntityName(), "MUSVM"); break;
+        case OPCODE::MULCK: ProcessMULCK(code_gen); break;
+        case OPCODE::BMUSC: WriteTodo(code_gen, md.GetEntityName(), "BMUSC"); break;
+        case OPCODE::CHMPH: WriteTodo(code_gen, md.GetEntityName(), "CHMPH"); break;
+        case OPCODE::PMVIE: ProcessPMVIE(code_gen); break;
+        case OPCODE::MOVIE: ProcessMOVIE(code_gen); break;
+        case OPCODE::MVIEF: ProcessMVIEF(code_gen); break;
+        case OPCODE::FMUSC: WriteTodo(code_gen, md.GetEntityName(), "FMUSC"); break;
+        case OPCODE::CMUSC: WriteTodo(code_gen, md.GetEntityName(), "CMUSC"); break;
+        case OPCODE::CHMST: WriteTodo(code_gen, md.GetEntityName(), "CHMST"); break;
+        default:
+            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
+              md.GetEntityName(), _address, _opcode
+            ));
+    }
+}
+
+void FieldMediaInstruction::ProcessAKAO2(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& param1 = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[7]->getUnsigned()
+    );
+    const auto& param2 = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[8]->getUnsigned()
+    );
+    const auto& param3 = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[2]->getUnsigned(), _params[9]->getUnsigned()
+    );
+    const auto& param4 = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[3]->getUnsigned(), _params[10]->getUnsigned()
+    );
+    const auto& param5 = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[5]->getUnsigned(), _params[11]->getUnsigned()
+    );
+    auto op = _params[6]->getUnsigned();
+    code_gen->AddOutputLine((
+      boost::format("-- music:execute_akao(0x%6$02x, %1%, %2%, %3%, %4%, %5%)")
+      % param1 % param2 % param3 % param4 % param5 % op
+    ).str());
+}
+
+void FieldMediaInstruction::ProcessMUSIC(CodeGenerator* code_gen){
+    code_gen->AddOutputLine((
+      boost::format("-- music:execute_akao(0x10, pointer_to_field_AKAO_%1%)")
+      % _params[0]->getUnsigned()
+    ).str());
+}
+
+void FieldMediaInstruction::ProcessSOUND(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& soundId = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
+    );
+    const auto& panning = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
+    );
+    code_gen->AddOutputLine(
+      (boost::format("-- music:execute_akao(0x20, %1%, %2%)") % soundId % panning).str()
+    );
+}
+
+void FieldMediaInstruction::ProcessAKAO(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& param1 = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[7]->getUnsigned()
+    );
+    const auto& param2 = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[8]->getUnsigned()
+    );
+    const auto& param3 = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[2]->getUnsigned(), _params[9]->getUnsigned()
+    );
+    const auto& param4 = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[3]->getUnsigned(), _params[10]->getUnsigned()
+    );
+    const auto& param5 = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[5]->getUnsigned(), _params[11]->getUnsigned()
+    );
+    auto op = _params[6]->getUnsigned();
+    code_gen->AddOutputLine((
+      boost::format("-- music:execute_akao(0x%6$02x, %1%, %2%, %3%, %4%, %5%)")
+      % param1 % param2 % param3 % param4 % param5 % op
+    ).str());
+}
+
+void FieldMediaInstruction::ProcessMULCK(CodeGenerator* code_gen){
+    code_gen->AddOutputLine((
+      boost::format("-- music:lock(%1%)")
+      % FieldCodeGenerator::FormatBool(_params[0]->getUnsigned())
+    ).str());
+}
+
+void FieldMediaInstruction::ProcessPMVIE(CodeGenerator* code_gen){
+    code_gen->AddOutputLine(
+      (boost::format("-- field:movie_set(%1%)") % _params[0]->getUnsigned()
+    ).str());
+}
+
+void FieldMediaInstruction::ProcessMOVIE(CodeGenerator* code_gen){
+    code_gen->AddOutputLine("-- field:play_movie()");
+}
+
+void FieldMediaInstruction::ProcessMVIEF(CodeGenerator* code_gen){
+    // TODO: Check for assignment to value.
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& destination = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[2]->getUnsigned());
+    code_gen->AddOutputLine(
+      (boost::format("-- %1% = field:get_movie_frame()") % destination).str()
+    );
+}

+ 516 - 0
V-Gears-Installer/src/decompiler/field/instruction/FieldModelInstruction.cpp

@@ -0,0 +1,516 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "decompiler/field/instruction/FieldModelInstruction.h"
+#include "decompiler/field/FieldEngine.h"
+#include "decompiler/field/FieldCodeGenerator.h"
+#include "decompiler/field/FieldDisassembler.h"
+
+void FieldModelInstruction::ProcessInst(
+  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
+){
+    FieldEngine& eng = static_cast<FieldEngine&>(*engine);
+    FunctionMetaData md(func._metadata);
+    switch (_opcode){
+        case OPCODE::JOIN: ProcessJOIN(code_gen); break;
+        case OPCODE::SPLIT: ProcessSPLIT(code_gen); break;
+        case OPCODE::BLINK: WriteTodo(code_gen, md.GetEntityName(), "BLINK"); break;
+        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::EYETX:
+            WriteTodo(code_gen, md.GetEntityName(), "EYETX");
+            break;
+        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::TRNSP:
+            WriteTodo(code_gen, md.GetEntityName(), "TRNSP");
+            break;
+        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::AMBNT:
+            WriteTodo(code_gen, md.GetEntityName(), "AMBNT");
+            break;
+        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::Unknown03:
+            WriteTodo(code_gen, md.GetEntityName(), "Unknown03");
+            break;
+        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::Unknown04:
+            WriteTodo(code_gen, md.GetEntityName(), "Unknown04");
+            break;
+        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::Unknown05:
+            WriteTodo(code_gen, md.GetEntityName(), "Unknown05");
+            break;
+        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::LIGHT:
+            WriteTodo(code_gen, md.GetEntityName(), "LIGHT");
+            break;
+        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::Unknown07:
+            WriteTodo(code_gen, md.GetEntityName(), "Unknown07");
+            break;
+        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::Unknown08:
+            WriteTodo(code_gen, md.GetEntityName(), "Unknown08");
+            break;
+        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::Unknown09:
+            WriteTodo(code_gen, md.GetEntityName(), "Unknown09");
+            break;
+        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::SBOBJ:
+            WriteTodo(code_gen, md.GetEntityName(), "SBOBJ");
+            break;
+        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::Unknown0B:
+            WriteTodo(code_gen, md.GetEntityName(), "Unknown0B");
+            break;
+        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::Unknown0C:
+            WriteTodo(code_gen, md.GetEntityName(), "Unknown0C");
+            break;
+        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::SHINE:
+            WriteTodo(code_gen, md.GetEntityName(), "SHINE");
+            break;
+        case (OPCODE::KAWAI << 8) | OPCODE_KAWAI::RESET:
+            WriteTodo(code_gen, md.GetEntityName(), "RESET");
+            break;
+        case OPCODE::KAWIW: WriteTodo(code_gen, md.GetEntityName(), "KAWIW"); break;
+        case OPCODE::PMOVA: WriteTodo(code_gen, md.GetEntityName(), "PMOVA"); break;
+        case OPCODE::PDIRA: WriteTodo(code_gen, md.GetEntityName(), "PDIRA"); break;
+        case OPCODE::PTURA: WriteTodo(code_gen, md.GetEntityName(), "PTURA"); break;
+        case OPCODE::PGTDR: WriteTodo(code_gen, md.GetEntityName(), "PGTDR"); break;
+        case OPCODE::PXYZI: WriteTodo(code_gen, md.GetEntityName(), "PXYZI"); break;
+        case OPCODE::TLKON: ProcessTLKON(code_gen, md.GetEntityName()); break;
+        case OPCODE::PC: ProcessPC(code_gen, md.GetEntityName()); break;
+        case OPCODE::opCodeCHAR: ProcessCHAR(code_gen, md.GetEntityName()); break;
+        case OPCODE::DFANM: ProcessDFANM(code_gen, md.GetEntityName(), md.GetCharacterId()); break;
+        case OPCODE::ANIME1: ProcessANIME1(code_gen, md.GetEntityName(), md.GetCharacterId()); break;
+        case OPCODE::VISI: ProcessVISI(code_gen, md.GetEntityName()); break;
+        case OPCODE::XYZI: ProcessXYZI(code_gen, md.GetEntityName()); break;
+        case OPCODE::XYI: WriteTodo(code_gen, md.GetEntityName(), "XYI"); break;
+        case OPCODE::XYZ: WriteTodo(code_gen, md.GetEntityName(), "XYZ"); break;
+        case OPCODE::MOVE: ProcessMOVE(code_gen, md.GetEntityName()); break;
+        case OPCODE::CMOVE: WriteTodo(code_gen, md.GetEntityName(), "CMOVE"); break;
+        case OPCODE::MOVA: WriteTodo(code_gen, md.GetEntityName(), "MOVA"); break;
+        case OPCODE::TURA: WriteTodo(code_gen, md.GetEntityName(), "TURA"); break;
+        case OPCODE::ANIMW: WriteTodo(code_gen, md.GetEntityName(), "ANIMW"); break;
+        case OPCODE::FMOVE: WriteTodo(code_gen, md.GetEntityName(), "FMOVE"); break;
+        case OPCODE::ANIME2: WriteTodo(code_gen, md.GetEntityName(), "ANIME2"); break;
+        case OPCODE::ANIM_1: WriteTodo(code_gen, md.GetEntityName(), "ANIM_1"); break;
+        case OPCODE::CANIM1: WriteTodo(code_gen, md.GetEntityName(), "CANIM1"); break;
+        case OPCODE::CANM_1: WriteTodo(code_gen, md.GetEntityName(), "CANM_1"); break;
+        case OPCODE::MSPED: ProcessMSPED(code_gen, md.GetEntityName()); break;
+        case OPCODE::DIR: ProcessDIR(code_gen, md.GetEntityName()); break;
+        case OPCODE::TURNGEN: ProcessTURNGEN(code_gen, md.GetEntityName()); break;
+        case OPCODE::TURN: WriteTodo(code_gen, md.GetEntityName(), "TURN"); break;
+        case OPCODE::DIRA: WriteTodo(code_gen, md.GetEntityName(), "DIRA"); break;
+        case OPCODE::GETDIR: WriteTodo(code_gen, md.GetEntityName(), "GETDIR"); break;
+        case OPCODE::GETAXY: WriteTodo(code_gen, md.GetEntityName(), "GETAXY"); break;
+        case OPCODE::GETAI: ProcessGETAI(code_gen, eng); break;
+        case OPCODE::ANIM_2: ProcessANIM_2(code_gen, md.GetEntityName(), md.GetCharacterId()); break;
+        case OPCODE::CANIM2: ProcessCANIM2(code_gen, md.GetEntityName(), md.GetCharacterId()); break;
+        case OPCODE::CANM_2: ProcessCANM_2(code_gen, md.GetEntityName(), md.GetCharacterId()); break;
+        case OPCODE::ASPED: WriteTodo(code_gen, md.GetEntityName(), "ASPED"); break;
+        case OPCODE::CC: ProcessCC(code_gen, eng); break;
+        case OPCODE::JUMP: ProcessJUMP(code_gen, md.GetEntityName()); break;
+        case OPCODE::AXYZI: ProcessAXYZI(code_gen); break;
+        case OPCODE::LADER: ProcessLADER(code_gen, md.GetEntityName()); break;
+        case OPCODE::OFST: ProcessOFST(code_gen, md.GetEntityName()); break;
+        case OPCODE::OFSTW:
+            code_gen->AddOutputLine("self." + md.GetEntityName() + ":offset_sync()");
+            break;
+        case OPCODE::TALKR: WriteTodo(code_gen, md.GetEntityName(), "TALKR"); break;
+        case OPCODE::SLIDR: WriteTodo(code_gen, md.GetEntityName(), "SLIDR"); break;
+        case OPCODE::SOLID: ProcessSOLID(code_gen, md.GetEntityName()); break;
+        case OPCODE::TLKR2: WriteTodo(code_gen, md.GetEntityName(), "TLKR2"); break;
+        case OPCODE::SLDR2: WriteTodo(code_gen, md.GetEntityName(), "SLDR2"); break;
+        case OPCODE::CCANM: WriteTodo(code_gen, md.GetEntityName(), "CCANM"); break;
+        case OPCODE::FCFIX: WriteTodo(code_gen, md.GetEntityName(), "FCFIX"); break;
+        case OPCODE::ANIMB: WriteTodo(code_gen, md.GetEntityName(), "ANIMB"); break;
+        case OPCODE::TURNW: WriteTodo(code_gen, md.GetEntityName(), "TURNW"); break;
+        default:
+            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
+              md.GetEntityName(), _address, _opcode
+            ));
+    }
+}
+
+void FieldModelInstruction::ProcessJOIN(CodeGenerator* code_gen){
+    code_gen->AddOutputLine("join_party(" + std::to_string(_params[0]->getUnsigned()) + ")");
+}
+
+void FieldModelInstruction::ProcessSPLIT(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const float scale = 128.0f * cg->GetScaleFactor();
+    const auto& ax = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[6]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, scale
+    );
+    const auto& ay = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[7]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, scale
+    );
+    const auto& ar = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[2]->getUnsigned(), _params[8]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, scale
+    );
+    const auto& bx = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[3]->getUnsigned(), _params[9]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, scale
+    );
+    const auto& by = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[4]->getUnsigned(), _params[10]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, scale
+    );
+    const auto& br = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[5]->getUnsigned(), _params[11]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, scale
+    );
+    const auto& speed = _params[12]->getUnsigned();
+    code_gen->AddOutputLine((
+      boost::format("split_party(%1%, %2%, %3%, %4%, %5%, %6%, %7%)")
+      % ax % ay % ar % bx % by % br % speed
+    ).str());
+}
+
+void FieldModelInstruction::ProcessTLKON(CodeGenerator* code_gen, const std::string& entity){
+    code_gen->AddOutputLine((
+      boost::format("self.%1%:set_talkable(%2%)")
+      % entity % FieldCodeGenerator::FormatInvertedBool(_params[0]->getUnsigned())
+    ).str());
+}
+
+void FieldModelInstruction::ProcessPC(CodeGenerator* code_gen, const std::string& entity){
+    code_gen->AddOutputLine(
+      (boost::format("set_entity_to_character(\"%1%\", \"%1%\")") % entity).str()
+    );
+}
+
+void FieldModelInstruction::ProcessCHAR(CodeGenerator* code_gen, const std::string& entity){
+    code_gen->AddOutputLine(
+      (boost::format("self.%1% = entity_manager:get_entity(\"%1%\")") % entity).str()
+    );
+}
+
+void FieldModelInstruction::ProcessDFANM(
+  CodeGenerator* code_gen, const std::string& entity, int char_id
+){
+    // ID will be fixed-up downstream.
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    auto animation_id = _params[0]->getUnsigned();
+    // TODO: check for zero.
+    auto speed = 1.0f / _params[1]->getUnsigned();
+    code_gen->AddOutputLine((
+      boost::format("self.%1%:set_default_animation(\"%2%\") -- speed %3%")
+      % entity % cg->GetFormatter().AnimationName(char_id, animation_id) % speed
+    ).str());
+    code_gen->AddOutputLine((
+      boost::format("self.%1%:play_animation(\"%2%\")")
+      % entity % cg->GetFormatter().AnimationName(char_id, animation_id)
+    ).str());
+}
+
+void FieldModelInstruction::ProcessANIME1(
+  CodeGenerator* code_gen, const std::string& entity, int char_id
+){
+    // ID will be fixed-up downstream.
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    auto animation_id = _params[0]->getUnsigned();
+    // TODO: check for zero.
+    auto speed = 1.0f / _params[1]->getUnsigned();
+    code_gen->AddOutputLine((
+      boost::format("self.%1%:play_animation(\"%2%\") -- speed %3%")
+      % entity % cg->GetFormatter().AnimationName(char_id, animation_id) % speed
+    ).str());
+    code_gen->AddOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
+}
+
+void FieldModelInstruction::ProcessVISI(CodeGenerator* code_gen, const std::string& entity){
+    code_gen->AddOutputLine((
+      boost::format("self.%1%:set_visible(%2%)")
+      % entity % FieldCodeGenerator::FormatBool(_params[0]->getUnsigned())
+    ).str());
+}
+
+void FieldModelInstruction::ProcessXYZI(CodeGenerator* code_gen, const std::string& entity){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const float scale = 128.0f * cg->GetScaleFactor();
+    const auto& x = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[4]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, scale
+    );
+    const auto& y = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[5]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, scale
+    );
+    const auto& z = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[2]->getUnsigned(), _params[6]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, scale
+    );
+    const auto& triangle_id = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[3]->getUnsigned(), _params[7]->getUnsigned()
+    );
+    code_gen->AddOutputLine((
+      boost::format("self.%1%:set_position(%2%, %3%, %4%) -- triangle ID %5%")
+      % entity % x % y % z % triangle_id
+    ).str());
+}
+
+void FieldModelInstruction::ProcessMOVE(CodeGenerator* code_gen, const std::string& entity){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const float scale = 128.0f * cg->GetScaleFactor();
+    const auto& x = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, scale
+    );
+    const auto& y = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, scale
+    );
+    code_gen->AddOutputLine(
+      (boost::format("self.%1%:move_to_position(%2%, %3%)") % entity % x % y).str()
+    );
+    code_gen->AddOutputLine((boost::format("self.%1%:move_sync()") % entity).str());
+}
+
+void FieldModelInstruction::ProcessMSPED(CodeGenerator* code_gen, const std::string& entity){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const float scale = 128.0f * cg->GetScaleFactor();
+    const auto& speed = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[2]->getUnsigned(),
+      FieldCodeGenerator::ValueType::Float, 256.0f * scale / 30.0f
+    );
+    code_gen->AddOutputLine(
+      (boost::format("self.%1%:set_move_auto_speed(%2%)") % entity % speed).str()
+    );
+}
+
+void FieldModelInstruction::ProcessDIR(CodeGenerator* code_gen, const std::string& entity){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& degrees = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[1]->getUnsigned(),
+      FieldCodeGenerator::ValueType::Float, 256.0f / 360.0f
+    );
+    code_gen->AddOutputLine((boost::format("self.%1%:set_rotation(%2%)") % entity % degrees).str());
+}
+
+void FieldModelInstruction::ProcessTURNGEN(CodeGenerator* code_gen, const std::string& entity){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& degrees = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[2]->getUnsigned(),
+      FieldCodeGenerator::ValueType::Float, 256.0f / 360.0f
+    );
+    std::string direction;
+    switch (_params[3]->getUnsigned()){
+        case 0: direction = "Entity.CLOCKWISE"; break;
+        case 1: direction = "Entity.ANTICLOCKWISE"; break;
+        case 2: direction = "Entity.CLOSEST"; break;
+        // Default to closest:
+        default: direction = "Entity.CLOSEST"; break;
+    }
+    auto steps = _params[4]->getUnsigned();
+    std::string step_type;
+    switch (_params[5]->getUnsigned()){
+        case 1: step_type = "Entity.LINEAR"; break;
+        case 2: step_type = "Entity.SMOOTH"; break;
+        // Default to smooth
+        default: step_type = "Entity.SMOOTH"; break;
+    }
+    const float scaled_steps = static_cast<float>(steps) / 30.0f;
+    code_gen->AddOutputLine((
+      boost::format("self.%1%:turn_to_direction(%2%, %3%, %4%, %5%)")
+      % entity % degrees % direction % step_type % scaled_steps
+    ).str());
+    code_gen->AddOutputLine((boost::format("self.%1%:turn_sync()") % entity).str());
+}
+
+void FieldModelInstruction::ProcessGETAI(CodeGenerator* code_gen, const FieldEngine& engine){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    // TODO: check for assignment to literal.
+    const auto& variable = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
+    );
+    const auto& entity = engine.EntityByIndex(_params[2]->getUnsigned());
+    code_gen->AddOutputLine(
+      (boost::format("%1% = entity_manager:get_entity(\"%2%\"):get_move_triangle_id()")
+      % variable % entity.GetName()
+    ).str());
+}
+
+void FieldModelInstruction::ProcessANIM_2(
+  CodeGenerator* code_gen, const std::string& entity, int char_id
+){
+    // ID will be fixed-up downstream.
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    auto animation_id = _params[0]->getUnsigned();
+    // TODO: check for zero.
+    auto speed = 1.0f / _params[1]->getUnsigned();
+    code_gen->AddOutputLine((
+      boost::format("self.%1%:play_animation_stop(\"%2%\") -- speed %3%")
+      % entity % cg->GetFormatter().AnimationName(char_id, animation_id) % speed
+    ).str());
+    code_gen->AddOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
+}
+
+void FieldModelInstruction::ProcessCANIM2(
+  CodeGenerator* code_gen, const std::string& entity, int char_id
+){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    auto animation_id = _params[0]->getUnsigned();
+    auto start_frame = _params[1]->getUnsigned() / 30.0f;
+    auto end_frame = _params[2]->getUnsigned() / 30.0f;
+    // TODO: check for zero.
+    auto speed = 1.0f / _params[3]->getUnsigned();
+    code_gen->AddOutputLine((
+      boost::format("self.%1%:play_animation(\"%2%\", %3%, %4%) -- speed %5%")
+      % entity % cg->GetFormatter().AnimationName(char_id, animation_id)
+      % start_frame % end_frame % speed
+    ).str());
+    code_gen->AddOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
+}
+
+void FieldModelInstruction::ProcessCANM_2(
+  CodeGenerator* code_gen, const std::string& entity, int char_id
+){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    // ID will be fixed-up downstream.
+    auto animation_id = _params[0]->getUnsigned();
+    auto start_frame = _params[1]->getUnsigned() / 30.0f;
+    auto end_frame = _params[2]->getUnsigned() / 30.0f;
+    // TODO: check for zero.
+    auto speed = 1.0f / _params[3]->getUnsigned();
+    code_gen->AddOutputLine((
+      boost::format("self.%1%:play_animation_stop(\"%2%\", %3%, %4%) -- speed %5%")
+      % entity % cg->GetFormatter().AnimationName(char_id, animation_id)
+      % start_frame % end_frame % speed
+    ).str());
+    code_gen->AddOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
+}
+
+void FieldModelInstruction::ProcessCC(CodeGenerator* code_gen, const FieldEngine& engine){
+    const auto& entity = engine.EntityByIndex(_params[0]->getUnsigned());
+    code_gen->AddOutputLine(
+      (boost::format("entity_manager:set_player_entity(\"%1%\")") % entity.GetName()).str()
+    );
+}
+
+void FieldModelInstruction::ProcessJUMP(CodeGenerator* code_gen, const std::string& entity){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const float scale = 128.0f * cg->GetScaleFactor();
+    float x = std::stof(FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[4]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, scale
+    ));
+    float y = std::stof(FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[5]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, scale
+    ));
+    int i = atoi(FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[2]->getUnsigned(), _params[6]->getSigned()
+    ).c_str());
+    int steps = atoi(FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[3]->getUnsigned(), _params[7]->getSigned()
+    ).c_str());
+    //x *= 0.00781250273224;
+    //y *= 0.00781250273224;
+    // Always force reduce steps and bound it between 1 and 5.
+    steps /= 6;
+    if (steps < 1) steps = 1;
+    if (steps > 5) steps = 5;
+    // TODO: Z hardcoded as -1, handled in Entity::ScriptJumpToPosition.
+    // TODO: Hardcoded 0.5 in seconds. Calculate using distance.
+    code_gen->AddOutputLine((
+      boost::format("self.%1%:jump_to_position(%2%, %3%, -1, 0.5, %4%) -- %5% steps.")
+      % entity % x % y % i % steps
+    ).str());
+    code_gen->AddOutputLine((boost::format("self.%1%:jump_sync()") % entity).str());
+}
+
+void FieldModelInstruction::ProcessAXYZI(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const float scale = 128.0f * cg->GetScaleFactor();
+    code_gen->AddOutputLine((
+      boost::format("axyzi(%1%, %2%, %3%, %4%, %5%, %6%, %7%, %8%, %9%, %10%)")
+      % _params[0]->getSigned() % _params[1]->getSigned() % _params[2]->getSigned()
+      % _params[3]->getSigned() % _params[4]->getSigned() % _params[5]->getSigned()
+      % _params[6]->getSigned() % _params[7]->getSigned() % _params[8]->getSigned()
+      % scale
+    ).str());
+}
+
+void FieldModelInstruction::ProcessLADER(CodeGenerator* code_gen, const std::string& entity){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const float scale = 128.0f * cg->GetScaleFactor();
+    const auto& x = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[4]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, scale
+    );
+    const auto& y = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[5]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, scale
+    );
+    const auto& z = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[2]->getUnsigned(), _params[6]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, scale
+    );
+    uint end_triangle = atoi(FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[3]->getUnsigned(), _params[7]->getUnsigned()
+    ).c_str());
+    uint keys = _params[8]->getUnsigned();
+    uint animation = _params[9]->getUnsigned();
+    //float orientation = _params[10]->getUnsigned() / (256.0f / 360.0f);
+    const auto& orientation = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), 0, _params[10]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, 256.0f / 360.0f
+    );
+    uint speed = _params[11]->getUnsigned();
+    // TODO: Animation hardcoded as "btce".
+    // TODO: Orientation and speed not set.
+    code_gen->AddOutputLine((
+      boost::format(
+        "self.%1%:linear_to_position(%2%, %3%, %4%, %5%, \"Climb\", %6%, %7%) "
+        "-- Animation %8% -- Speed %9%"
+      ) % entity % x % y % z % keys % orientation % end_triangle % animation % speed
+    ).str());
+    code_gen->AddOutputLine((boost::format("self.%1%:linear_sync()") % entity).str());
+}
+
+void FieldModelInstruction::ProcessSOLID(CodeGenerator* code_gen, const std::string& entity){
+    code_gen->AddOutputLine((
+      boost::format("self.%1%:set_solid(%2%)")
+      % entity % FieldCodeGenerator::FormatInvertedBool(_params[0]->getUnsigned())
+    ).str());
+}
+
+void FieldModelInstruction::ProcessOFST(CodeGenerator* code_gen, const std::string& entity){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const float scale = 128.0f * cg->GetScaleFactor();
+    float x = std::stof(FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[5]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, scale
+    ));
+    float y = std::stof(FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(),_params[6]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, scale
+    ));
+    float z = std::stof(FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[2]->getUnsigned(), _params[7]->getSigned(),
+      FieldCodeGenerator::ValueType::Float, scale
+    ));
+    float speed = std::stof(FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[3]->getUnsigned(), _params[8]->getUnsigned()
+    ));
+    // Spatial coordinates need to be scaled down.
+    // TODO: This number is empirically deducted. Why this number?
+    //x *= 0.00390f;
+    //y *= 0.00390f;
+    //z *= 0.00390f;
+    // Speed needs to be scaled down by the frame rate.
+    speed /= 30.0f;
+    code_gen->AddOutputLine((
+      boost::format("self.%1%:offset_to_position(%2%, %3%, %4%, %5%, %6%)")
+      % entity % x % y % z
+      % (_params[4]->getUnsigned() ? "Entity.SMOOTH" : "Entity.LINEAR")% speed
+    ).str());
+}

+ 135 - 0
V-Gears-Installer/src/decompiler/field/instruction/FieldModuleInstruction.cpp

@@ -0,0 +1,135 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "decompiler/field/instruction/FieldModuleInstruction.h"
+#include "decompiler/field/FieldEngine.h"
+#include "decompiler/field/FieldCodeGenerator.h"
+#include "decompiler/field/FieldDisassembler.h"
+
+void FieldModuleInstruction::ProcessInst(
+  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
+){
+    FunctionMetaData md(func._metadata);
+    switch (_opcode){
+        case OPCODE::DSKCG: WriteTodo(code_gen, md.GetEntityName(), "DSKCG"); break;
+        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::ARROW:
+            code_gen->AddOutputLine((
+              boost::format("game:pointer_enable(%1%)")
+              % (_params[0]->getUnsigned() ? "true" : "false")
+            ).str());
+            break;
+        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::PNAME:
+            WriteTodo(code_gen, md.GetEntityName(), "PNAME");
+            break;
+        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::GMSPD:
+            WriteTodo(code_gen, md.GetEntityName(), "GMSPD");
+            break;
+        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::SMSPD:
+            WriteTodo(code_gen, md.GetEntityName(), "SMSPD");
+            break;
+        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::FLMAT:
+            code_gen->AddOutputLine("game:fill_materia()");
+            break;
+        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::FLITM:
+            WriteTodo(code_gen, md.GetEntityName(), "FLITM");
+            break;
+        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::BTLCK:
+            code_gen->AddOutputLine((
+              boost::format("game:battle_enable(%1%)")
+              % (_params[0]->getUnsigned() ? "true" : "false")
+            ).str());
+            break;
+        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::MVLCK:
+            code_gen->AddOutputLine((
+              boost::format("game:movie_enable(%1%)")
+              % (_params[0]->getUnsigned() ? "true" : "false")
+            ).str());
+            break;
+        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::SPCNM:
+            WriteTodo(code_gen, md.GetEntityName(), "SPCNM");
+            break;
+        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::RSGLB:
+            code_gen->AddOutputLine("game:global_reset()");
+            break;
+        case (OPCODE::SPECIAL << 8) | OPCODE_SPECIAL::CLITM:
+            WriteTodo(code_gen, md.GetEntityName(), "CLITM");
+            break;
+        case OPCODE::MINIGAME: WriteTodo(code_gen, md.GetEntityName(), "MINIGAME"); break;
+        case OPCODE::BTMD2: WriteTodo(code_gen, md.GetEntityName(), "BTMD2"); break;
+        case OPCODE::BTRLD: WriteTodo(code_gen, md.GetEntityName(), "BTRLD"); break;
+        case OPCODE::BTLTB: WriteTodo(code_gen, md.GetEntityName(), "BTLTB"); break;
+        case OPCODE::MAPJUMP: ProcessMAPJUMP(code_gen, func); break;
+        case OPCODE::LSTMP: WriteTodo(code_gen, md.GetEntityName(), "LSTMP"); break;
+        case OPCODE::BATTLE: ProcessBATTLE(code_gen); break;
+        case OPCODE::BTLON: ProcessBTLON(code_gen); break;
+        case OPCODE::BTLMD: WriteTodo(code_gen, md.GetEntityName(), "BTLMD"); break;
+        case OPCODE::MPJPO:
+            // Gateway function will do nothing if this is set to true
+            code_gen->AddOutputLine(
+              std::string("FFVII.Data.DisableGateways=")
+              + (_params[0]->getUnsigned() ? "true" : "false")
+            );
+            break;
+        // Prepare to change map, don't need to output anything for this.
+        case OPCODE::PMJMP: code_gen->AddOutputLine("-- Prepare map change"); break;
+        // Prepare to change map, don't need to output anything for this,
+        // seems to be the same thing as PMJMP
+        case OPCODE::PMJMP2: code_gen->AddOutputLine("-- Prepare map change 2"); break;
+        case OPCODE::GAMEOVER: WriteTodo(code_gen, md.GetEntityName(), "GAMEOVER"); break;
+        default:
+            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
+              md.GetEntityName(), _address, _opcode
+            ));
+    }
+}
+
+void FieldModuleInstruction::ProcessBATTLE(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& battle_id = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[1]->getUnsigned()
+    );
+    code_gen->AddOutputLine((boost::format("entity_manager:battle_run(%1%)") % battle_id).str());
+}
+
+void FieldModuleInstruction::ProcessBTLON(CodeGenerator* code_gen){
+    code_gen->AddOutputLine((
+      boost::format("entity_manager:random_encounters_on(%1%)")
+      % FieldCodeGenerator::FormatInvertedBool(_params[0]->getUnsigned())
+    ).str());
+}
+
+void FieldModuleInstruction::ProcessMAPJUMP(CodeGenerator* code_gen, Function& func){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto target_map_id = _params[0]->getUnsigned();
+    FunctionMetaData md(func._metadata);
+    const std::string source_spawn_point_name
+      = cg->GetFormatter().SpawnPointName(target_map_id, md.GetEntityName(), func._name, _address);
+
+    cg->GetFormatter().AddSpawnPoint(
+      target_map_id, md.GetEntityName(), func._name, _address,
+      _params[1]->getSigned(), // X
+      _params[2]->getSigned(), // Y
+      _params[3]->getSigned(), // Walk mesh triangle ID
+      _params[4]->getSigned()  // Angle
+    );
+
+    const std::string target_map_name = cg->GetFormatter().MapName(target_map_id);
+    code_gen->AddOutputLine(
+      "load_field_map_request(\"" + target_map_name + "\", \"" + source_spawn_point_name + "\")"
+    );
+}

+ 26 - 0
V-Gears-Installer/src/decompiler/field/instruction/FieldNoOperationInstruction.cpp

@@ -0,0 +1,26 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "decompiler/field/instruction/FieldNoOperationInstruction.h"
+#include "decompiler/field/FieldEngine.h"
+#include "decompiler/field/FieldCodeGenerator.h"
+#include "decompiler/field/FieldDisassembler.h"
+
+void FieldNoOperationInstruction::ProcessInst(
+  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
+){}

+ 84 - 0
V-Gears-Installer/src/decompiler/field/instruction/FieldPartyInstruction.cpp

@@ -0,0 +1,84 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "decompiler/field/instruction/FieldPartyInstruction.h"
+#include "decompiler/field/FieldEngine.h"
+#include "decompiler/field/FieldCodeGenerator.h"
+#include "decompiler/field/FieldDisassembler.h"
+
+void FieldPartyInstruction::ProcessInst(
+  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
+){
+    FunctionMetaData md(func._metadata);
+    switch (_opcode){
+        case OPCODE::SPTYE: WriteTodo(code_gen, md.GetEntityName(), "SPTYE"); break;
+        case OPCODE::GTPYE: WriteTodo(code_gen, md.GetEntityName(), "GTPYE"); break;
+        case OPCODE::GOLDU: WriteTodo(code_gen, md.GetEntityName(), "GOLDU"); break;
+        case OPCODE::GOLDD: WriteTodo(code_gen, md.GetEntityName(), "GOLDD"); break;
+        case OPCODE::HMPMAX1: WriteTodo(code_gen, md.GetEntityName(), "HMPMAX1"); break;
+        case OPCODE::HMPMAX2: WriteTodo(code_gen, md.GetEntityName(), "HMPMAX2"); break;
+        case OPCODE::MHMMX: WriteTodo(code_gen, md.GetEntityName(), "MHMMX"); break;
+        case OPCODE::HMPMAX3: WriteTodo(code_gen, md.GetEntityName(), "HMPMAX3"); break;
+        case OPCODE::MPU: WriteTodo(code_gen, md.GetEntityName(), "MPU"); break;
+        case OPCODE::MPD: WriteTodo(code_gen, md.GetEntityName(), "MPD"); break;
+        case OPCODE::HPU: WriteTodo(code_gen, md.GetEntityName(), "HPU"); break;
+        case OPCODE::HPD: WriteTodo(code_gen, md.GetEntityName(), "HPD"); break;
+        case OPCODE::STITM: ProcessSTITM(code_gen); break;
+        case OPCODE::DLITM: WriteTodo(code_gen, md.GetEntityName(), "DLITM"); break;
+        case OPCODE::CKITM: WriteTodo(code_gen, md.GetEntityName(), "CKITM"); break;
+        case OPCODE::SMTRA: WriteTodo(code_gen, md.GetEntityName(), "SMTRA"); break;
+        case OPCODE::DMTRA: WriteTodo(code_gen, md.GetEntityName(), "DMTRA"); break;
+        case OPCODE::CMTRA: WriteTodo(code_gen, md.GetEntityName(), "CMTRA"); break;
+        case OPCODE::GETPC: WriteTodo(code_gen, md.GetEntityName(), "GETPC"); break;
+        case OPCODE::PRTYP: WriteTodo(code_gen, md.GetEntityName(), "PRTYP"); break;
+        case OPCODE::PRTYM: WriteTodo(code_gen, md.GetEntityName(), "PRTYM"); break;
+        case OPCODE::PRTYE: ProcessPRTYE(code_gen); break;
+        case OPCODE::MMBUD: WriteTodo(code_gen, md.GetEntityName(), "MMBUD"); break;
+        case OPCODE::MMBLK: WriteTodo(code_gen, md.GetEntityName(), "MMBLK"); break;
+        case OPCODE::MMBUK: WriteTodo(code_gen, md.GetEntityName(), "MMBUK"); break;
+        case OPCODE::CHGLD: WriteTodo(code_gen, md.GetEntityName(), "CHGLD"); break;
+        default:
+            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
+              md.GetEntityName(), _address, _opcode
+            ));
+    }
+}
+
+void FieldPartyInstruction::ProcessSTITM(CodeGenerator* code_gen){
+    FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
+    const auto& item_id = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getUnsigned()
+    );
+    const auto& amount = FieldCodeGenerator::FormatValueOrVariable(
+      cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
+    );
+    code_gen->AddOutputLine((boost::format("FFVII.add_item(%1%, %2%)") % item_id % amount).str());
+}
+
+void FieldPartyInstruction::ProcessPRTYE(CodeGenerator* code_gen){
+    FieldCodeGenerator* gc = static_cast<FieldCodeGenerator*>(code_gen);
+    auto char_id_1 = gc->GetFormatter().CharName(_params[0]->getUnsigned());
+    char_id_1 = (char_id_1 == "") ? "nil" : ("\"" + char_id_1 + "\"");
+    auto char_id_2 = gc->GetFormatter().CharName(_params[1]->getUnsigned());
+    char_id_2 = (char_id_2 == "") ? "nil" : ("\"" + char_id_2 + "\"");
+    auto char_id_3 = gc->GetFormatter().CharName(_params[2]->getUnsigned());
+    char_id_3 = (char_id_3 == "") ? "nil" : ("\"" + char_id_3 + "\"");
+    code_gen->AddOutputLine((
+      boost::format("FFVII.set_party(%1%, %2%, %3%)") % char_id_1 % char_id_2 % char_id_3
+    ).str());
+}

+ 38 - 0
V-Gears-Installer/src/decompiler/field/instruction/FieldUncategorizedInstruction.cpp

@@ -0,0 +1,38 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "decompiler/field/instruction/FieldUncategorizedInstruction.h"
+#include "decompiler/field/FieldEngine.h"
+#include "decompiler/field/FieldCodeGenerator.h"
+#include "decompiler/field/FieldDisassembler.h"
+
+void FieldUncategorizedInstruction::ProcessInst(
+  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
+){
+    FunctionMetaData md(func._metadata);
+    switch (_opcode){
+        case OPCODE::MPDSP: WriteTodo(code_gen, md.GetEntityName(), "MPDSP"); break;
+        case OPCODE::SETX: WriteTodo(code_gen, md.GetEntityName(), "SETX"); break;
+        case OPCODE::GETX: WriteTodo(code_gen, md.GetEntityName(), "GETX"); break;
+        case OPCODE::SEARCHX: WriteTodo(code_gen, md.GetEntityName(), "SEARCHX"); break;
+        default:
+            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
+              md.GetEntityName(), _address, _opcode)
+            );
+    }
+}

+ 58 - 0
V-Gears-Installer/src/decompiler/field/instruction/FieldUncondJumpInstruction.cpp

@@ -0,0 +1,58 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "decompiler/field/instruction/FieldUncondJumpInstruction.h"
+#include "decompiler/field/FieldEngine.h"
+#include "decompiler/field/FieldCodeGenerator.h"
+#include "decompiler/field/FieldDisassembler.h"
+
+FieldUncondJumpInstruction::FieldUncondJumpInstruction() : call_(false) {}
+
+bool FieldUncondJumpInstruction::IsFuncCall() const{return call_;}
+
+bool FieldUncondJumpInstruction::IsUncondJump() const{return !call_;}
+
+uint32 FieldUncondJumpInstruction::GetDestAddress() const{
+    if (
+      static_cast<OPCODE>(_opcode) == OPCODE::JMPF
+      || static_cast<OPCODE>(_opcode) == OPCODE::JMPFL){
+        // Short or long forward jump.
+        return _address + _params[0]->getUnsigned() + 1;
+    }
+    // Backwards jump,  OPCODE::JMPB/L.
+    return _address - _params[0]->getUnsigned();
+}
+
+void FieldUncondJumpInstruction::ProcessInst(
+  Function& func, ValueStack&, Engine* engine, CodeGenerator* code_gen
+){
+    switch (_opcode){
+        case OPCODE::JMPB:
+        case OPCODE::JMPBL:
+            // HACK: Hard loop will hang the game, insert a wait to yield control.
+            code_gen->AddOutputLine("-- Hack, yield control for possible inf loop");
+            code_gen->AddOutputLine("script:wait(0)");
+            break;
+    }
+}
+
+std::ostream& FieldUncondJumpInstruction::Print(std::ostream &output) const{
+    Instruction::Print(output);
+    output << " (Jump target address: 0x" << std::hex << GetDestAddress() << std::dec << ")";
+    return output;
+}

+ 74 - 0
V-Gears-Installer/src/decompiler/field/instruction/FieldWalkmeshInstruction.cpp

@@ -0,0 +1,74 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "decompiler/field/instruction/FieldWalkmeshInstruction.h"
+#include "decompiler/field/FieldEngine.h"
+#include "decompiler/field/FieldCodeGenerator.h"
+#include "decompiler/field/FieldDisassembler.h"
+
+void FieldWalkmeshInstruction::ProcessInst(
+  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
+){
+    FunctionMetaData md(func._metadata);
+    switch (_opcode){
+        case OPCODE::SLIP: WriteTodo(code_gen, md.GetEntityName(), "SLIP"); break;
+        case OPCODE::UC: ProcessUC(code_gen); break;
+        case OPCODE::IDLCK:
+            // Triangle id, on or off
+            code_gen->AddOutputLine(
+                (boost::format("walkmesh:lock_walkmesh(%1%, %2%)")
+                % _params[0]->getUnsigned()
+                % FieldCodeGenerator::FormatBool(_params[1]->getUnsigned())).str());
+            break;
+        case OPCODE::LINE: ProcessLINE(code_gen, md.GetEntityName()); break;
+        case OPCODE::LINON: WriteTodo(code_gen, md.GetEntityName(), "LINON"); break;
+        case OPCODE::SLINE: WriteTodo(code_gen, md.GetEntityName(), "SLINE"); break;
+        default:
+            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
+              md.GetEntityName(), _address, _opcode
+            ));
+    }
+}
+
+void FieldWalkmeshInstruction::ProcessUC(CodeGenerator* code_gen){
+    code_gen->AddOutputLine((
+      boost::format("entity_manager:player_lock(%1%)")
+      % FieldCodeGenerator::FormatBool(_params[0]->getUnsigned())
+    ).str());
+}
+
+void FieldWalkmeshInstruction::ProcessLINE(CodeGenerator* code_gen, const std::string& entity){
+    float xa = _params[0]->getSigned();
+    float ya = _params[1]->getSigned();
+    float za = _params[2]->getSigned();
+    float xb = _params[3]->getSigned();
+    float yb = _params[4]->getSigned();
+    float zb = _params[5]->getSigned();
+    // Scale down. TODO: Why this number?
+    xa *= 0.00781249709639;
+    ya *= 0.00781249709639;
+    za *= 0.00781249709639;
+    xb *= 0.00781249709639;
+    yb *= 0.00781249709639;
+    zb *= 0.00781249709639;
+    // Just print as a comment.
+    code_gen->AddOutputLine(
+      "-- LINE (" + std::to_string(xa) + ", " + std::to_string(ya) + ", " + std::to_string(za)
+      + ")-(" + std::to_string(xb) + ", " +std::to_string(yb) + ", " + std::to_string(zb) + ")"
+    );
+}

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

@@ -0,0 +1,103 @@
+/*
+ * V-Gears
+ * Copyright (C) 2022 V-Gears Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "decompiler/field/instruction/FieldWindowInstruction.h"
+#include "decompiler/field/FieldEngine.h"
+#include "decompiler/field/FieldCodeGenerator.h"
+#include "decompiler/field/FieldDisassembler.h"
+
+void FieldWindowInstruction::ProcessInst(
+  Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
+){
+    FieldEngine& eng = static_cast<FieldEngine&>(*engine);
+    FunctionMetaData md(func._metadata);
+    switch (_opcode){
+        case OPCODE::TUTOR: WriteTodo(code_gen, md.GetEntityName(), "TUTOR"); break;
+        case OPCODE::WCLS: WriteTodo(code_gen, md.GetEntityName(), "WCLS"); break;
+        case OPCODE::WSIZW: WriteTodo(code_gen, md.GetEntityName(), "WSIZW"); break;
+        case OPCODE::WSPCL: WriteTodo(code_gen, md.GetEntityName(), "WSPCL"); break;
+        case OPCODE::WNUMB: WriteTodo(code_gen, md.GetEntityName(), "WNUMB"); break;
+        case OPCODE::STTIM: WriteTodo(code_gen, md.GetEntityName(), "STTIM"); break;
+        case OPCODE::MESSAGE: ProcessMESSAGE(code_gen, eng.ScriptName()); break;
+        case OPCODE::MPARA: WriteTodo(code_gen, md.GetEntityName(), "MPARA"); break;
+        case OPCODE::MPRA2: WriteTodo(code_gen, md.GetEntityName(), "MPRA2"); break;
+        case OPCODE::MPNAM: ProcessMPNAM(code_gen); break;
+        case OPCODE::ASK: WriteTodo(code_gen, md.GetEntityName(), "ASK"); break;
+        case OPCODE::MENU: WriteTodo(code_gen, md.GetEntityName(), "MENU"); break;
+        case OPCODE::MENU2: ProcessMENU2(code_gen); break;
+        case OPCODE::WINDOW: ProcessWINDOW(code_gen); break;
+        case OPCODE::WMOVE: WriteTodo(code_gen, md.GetEntityName(), "WMOVE"); break;
+        case OPCODE::WMODE: WriteTodo(code_gen, md.GetEntityName(), "WMODE"); break;
+        case OPCODE::WREST: WriteTodo(code_gen, md.GetEntityName(), "WREST"); break;
+        case OPCODE::WCLSE: ProcessWCLSE(code_gen); break;
+        case OPCODE::WROW: WriteTodo(code_gen, md.GetEntityName(), "WROW"); break;
+        case OPCODE::GWCOL: WriteTodo(code_gen, md.GetEntityName(), "GWCOL"); break;
+        case OPCODE::SWCOL: WriteTodo(code_gen, md.GetEntityName(), "SWCOL"); break;
+        default:
+            code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
+              md.GetEntityName(), _address, _opcode
+            ));
+    }
+}
+
+void FieldWindowInstruction::ProcessWINDOW(CodeGenerator* code_gen){
+    // Init a new window. It won't be displayed until MESSAGE is used.
+    auto windowId = _params[0]->getUnsigned();
+    auto x = _params[1]->getUnsigned();
+    auto y = _params[2]->getUnsigned();
+    auto width = _params[3]->getUnsigned();
+    auto height = _params[4]->getUnsigned();
+    code_gen->AddOutputLine((
+      boost::format("dialog:dialog_open(\"%1%\", %2%, %3%, %4%, %5%)")
+      % windowId % x % y % width % height
+    ).str());
+}
+
+void FieldWindowInstruction::ProcessMESSAGE(
+  CodeGenerator* code_gen, const std::string& script_name
+){
+    // Displays a dialog in the WINDOW that has previously been initialized to display this dialog.
+    auto window_id = _params[0]->getUnsigned();
+    auto dialog_id = _params[1]->getUnsigned();
+    code_gen->AddOutputLine((
+      boost::format("dialog:dialog_set_text(\"%1%\", \"%2%_%3%\")")
+      % window_id % script_name % dialog_id
+    ).str());
+    code_gen->AddOutputLine(
+      (boost::format("dialog:dialog_wait_for_close(\"%1%\")") % window_id).str()
+    );
+}
+
+void FieldWindowInstruction::ProcessWCLSE(CodeGenerator* code_gen){
+    // Close a dialog.
+    auto windowId = _params[0]->getUnsigned();
+    code_gen->AddOutputLine((boost::format("dialog:dialog_close(\"%1%\")") % windowId).str());
+}
+
+void FieldWindowInstruction::ProcessMPNAM(CodeGenerator* code_gen){
+    code_gen->AddOutputLine(
+      (boost::format("-- field:map_name(%1%)") % _params[0]->getUnsigned()).str()
+    );
+}
+
+void FieldWindowInstruction::ProcessMENU2(CodeGenerator* code_gen){
+    code_gen->AddOutputLine((
+      boost::format("-- field:menu_lock(%1%)")
+      % FieldCodeGenerator::FormatBool(_params[0]->getUnsigned())
+    ).str());
+}

+ 19 - 15
V-Gears-Installer/src/decompiler/instruction.cpp

@@ -29,15 +29,19 @@ void setOutputStackEffect(bool value) {
 	outputStackEffect = value;
 }
 
+void Instruction::WriteTodo(CodeGenerator *code_gen, std::string owner, std::string instruction){
+    code_gen->AddOutputLine("-- Todo(\"" + instruction + "\")");
+}
+
 bool Instruction::isJump() const {
-	return isCondJump() || isUncondJump();
+	return isCondJump() || IsUncondJump();
 }
 
 bool Instruction::isCondJump() const {
 	return false;
 }
 
-bool Instruction::isUncondJump() const {
+bool Instruction::IsUncondJump() const {
 	return false;
 }
 
@@ -45,7 +49,7 @@ bool Instruction::isStackOp() const {
 	return false;
 }
 
-bool Instruction::isFuncCall() const {
+bool Instruction::IsFuncCall() const {
 	return false;
 }
 
@@ -65,11 +69,11 @@ bool Instruction::isStore() const {
 	return false;
 }
 
-uint32 Instruction::getDestAddress() const {
+uint32 Instruction::GetDestAddress() const {
 	throw WrongTypeException();
 }
 
-std::ostream &Instruction::print(std::ostream &output) const {
+std::ostream &Instruction::Print(std::ostream &output) const {
 	output << boost::format("%08x: %s") % _address % _name;
 	std::vector<ValuePtr>::const_iterator param;
 	for (param = _params.begin(); param != _params.end(); ++param) {
@@ -86,18 +90,18 @@ bool CondJumpInstruction::isCondJump() const {
 	return true;
 }
 
-bool UncondJumpInstruction::isUncondJump() const {
+bool UncondJumpInstruction::IsUncondJump() const {
 	return true;
 }
 
-void UncondJumpInstruction::processInst(Function&, ValueStack&, Engine*, CodeGenerator*) {
+void UncondJumpInstruction::ProcessInst(Function&, ValueStack&, Engine*, CodeGenerator*) {
 }
 
 bool StackInstruction::isStackOp() const {
 	return true;
 }
 
-bool CallInstruction::isFuncCall() const {
+bool CallInstruction::IsFuncCall() const {
 	return true;
 }
 
@@ -109,7 +113,7 @@ bool StoreInstruction::isStore() const {
 	return true;
 }
 
-void DupStackInstruction::processInst(Function&, ValueStack &stack, Engine*, CodeGenerator *codeGen) {
+void DupStackInstruction::ProcessInst(Function&, ValueStack &stack, Engine*, CodeGenerator *codeGen) {
 	std::stringstream s;
 	ValuePtr p = stack.pop()->dup(s);
 	if (s.str().length() > 0)
@@ -118,11 +122,11 @@ void DupStackInstruction::processInst(Function&, ValueStack &stack, Engine*, Cod
 	stack.push(p);
 }
 
-void BoolNegateStackInstruction::processInst(Function&, ValueStack &stack, Engine*, CodeGenerator*) {
+void BoolNegateStackInstruction::ProcessInst(Function&, ValueStack &stack, Engine*, CodeGenerator*) {
 	stack.push(stack.pop()->negate());
 }
 
-void BinaryOpStackInstruction::processInst(Function&, ValueStack &stack, Engine*, CodeGenerator *codeGen) {
+void BinaryOpStackInstruction::ProcessInst(Function&, ValueStack &stack, Engine*, CodeGenerator *codeGen) {
 	ValuePtr op1 = stack.pop();
 	ValuePtr op2 = stack.pop();
 	if (codeGen->_binOrder == FIFO_ARGUMENT_ORDER)
@@ -135,19 +139,19 @@ bool ReturnInstruction::isReturn() const {
 	return true;
 }
 
-void ReturnInstruction::processInst(Function&, ValueStack&, Engine*, CodeGenerator *codeGen) {
+void ReturnInstruction::ProcessInst(Function&, ValueStack&, Engine*, CodeGenerator *codeGen) {
 	codeGen->AddOutputLine("return;");
 }
 
-void UnaryOpPrefixStackInstruction::processInst(Function&, ValueStack &stack, Engine*, CodeGenerator*) {
+void UnaryOpPrefixStackInstruction::ProcessInst(Function&, ValueStack &stack, Engine*, CodeGenerator*) {
 	stack.push(new UnaryOpValue(stack.pop(), _codeGenData, false));
 }
 
-void UnaryOpPostfixStackInstruction::processInst(Function& , ValueStack &stack, Engine*, CodeGenerator*) {
+void UnaryOpPostfixStackInstruction::ProcessInst(Function& , ValueStack &stack, Engine*, CodeGenerator*) {
 	stack.push(new UnaryOpValue(stack.pop(), _codeGenData, true));
 }
 
-void KernelCallStackInstruction::processInst(Function&, ValueStack &stack, Engine*, CodeGenerator *codeGen) {
+void KernelCallStackInstruction::ProcessInst(Function&, ValueStack &stack, Engine*, CodeGenerator *codeGen) {
 	codeGen->_argList.clear();
 	bool returnsValue = (_codeGenData.find("r") == 0);
 	std::string metadata = (!returnsValue ? _codeGenData : _codeGenData.substr(1));

+ 7 - 7
V-Gears-Installer/src/decompiler/sudm.cpp

@@ -16,8 +16,8 @@
 #include "decompiler/sudm.h"
 
 #include "../../include/decompiler/field/FieldDisassembler.h"
+#include "../../include/decompiler/field/FieldEngine.h"
 #include "decompiler/field/FieldCodeGenerator.h"
-#include "decompiler/field/ff7_field_engine.h"
 #include "decompiler/control_flow.h"
 
 namespace SUDM{
@@ -32,9 +32,9 @@ namespace SUDM{
         float ScaleFactor(const std::vector<unsigned char>& script_bytes){
             // Could be cleaner, but just does enough work to pull out the fields scale.
             IScriptFormatter formatter;
-            FF7FieldEngine engine(formatter, "Unused");
+            FieldEngine engine(formatter, "Unused");
             InstVec insts;
-            engine.getDisassembler(insts, script_bytes);
+            engine.GetDisassembler(insts, script_bytes);
             return engine.GetScaleFactor();
         }
 
@@ -43,21 +43,21 @@ namespace SUDM{
           IScriptFormatter& formatter, std::string text_after, std::string text_before
         ){
             // Disassemble the script.
-            FF7FieldEngine engine(formatter, script_name);
+            FieldEngine engine(formatter, script_name);
             InstVec insts;
-            auto disassembler = engine.getDisassembler(insts, script_bytes);
+            auto disassembler = engine.GetDisassembler(insts, script_bytes);
             disassembler->Disassemble();
             // Create control flow group.
             auto control_flow = std::make_unique<ControlFlow>(insts, engine);
             control_flow->createGroups();
             // Decompile/analyze
             //Graph graph = controlFlow->analyze();
-            //engine.postCFG(insts, graph);
+            //engine.PostCFG(insts, graph);
             Graph graph;
             DecompiledScript ds;
             // Generate code and return it.
             std::stringstream output;
-            auto cg = engine.getCodeGenerator(insts, output);
+            auto cg = engine.GetCodeGenerator(insts, output);
             cg->Generate(insts, graph);
             ds.luaScript = text_before + output.str() + text_after;
             for (auto entity : engine.GetEntityList()) ds.entities.push_back(entity);

+ 2 - 2
V-Gears-Installer/src/decompiler/world/ff7_world_codegen.cpp

@@ -11,7 +11,7 @@ const InstPtr FF7::FF7WorldCodeGenerator::findFirstCall()
     ConstInstIterator it = mCurGroup->_start;
     do
     {
-        if ((*it)->isFuncCall() || (*it)->isKernelCall())
+        if ((*it)->IsFuncCall() || (*it)->isKernelCall())
             return *it;
     } while (it++ != mCurGroup->_end);
 
@@ -22,7 +22,7 @@ const InstPtr FF7::FF7WorldCodeGenerator::findLastCall()
 {
     ConstInstIterator it = mCurGroup->_end;
     do {
-        if ((*it)->isFuncCall() || (*it)->isKernelCall())
+        if ((*it)->IsFuncCall() || (*it)->isKernelCall())
             return *it;
     } while (it-- != mCurGroup->_start);
 

+ 18 - 18
V-Gears-Installer/src/decompiler/world/ff7_world_engine.cpp

@@ -8,17 +8,17 @@
 
 #define GET(vertex) (boost::get(boost::vertex_name, g, vertex))
 
-std::unique_ptr<Disassembler> FF7::FF7WorldEngine::getDisassembler(InstVec &insts)
+std::unique_ptr<Disassembler> FF7::FF7WorldEngine::GetDisassembler(InstVec &insts)
 {
     return std::make_unique<FF7WorldDisassembler>(this, insts, mScriptNumber);
 }
 
-std::unique_ptr<CodeGenerator> FF7::FF7WorldEngine::getCodeGenerator(const InstVec& /*insts*/, std::ostream &output)
+std::unique_ptr<CodeGenerator> FF7::FF7WorldEngine::GetCodeGenerator(const InstVec& /*insts*/, std::ostream &output)
 {
     return std::make_unique<FF7WorldCodeGenerator>(this, output);
 }
 
-void FF7::FF7WorldEngine::postCFG(InstVec&, Graph g)
+void FF7::FF7WorldEngine::PostCFG(InstVec&, Graph g)
 {
     /*
     VertexRange vr = boost::vertices(g);
@@ -27,7 +27,7 @@ void FF7::FF7WorldEngine::postCFG(InstVec&, Graph g)
         GroupPtr gr = GET(*v);
 
         // If this group is the last instruction and its an unconditional jump
-        if ((*gr->_start)->_address == insts.back()->_address && insts.back()->isUncondJump())
+        if ((*gr->_start)->_address == insts.back()->_address && insts.back()->IsUncondJump())
         {
             // Then assume its an infinite do { } while(true) loop that wraps part of the script
             gr->_type = kDoWhileCondGroupType;
@@ -40,17 +40,17 @@ void FF7::FF7WorldEngine::getVariants(std::vector<std::string>&) const
 
 }
 
-void FF7::FF7WorldLoadBankInstruction::processInst(Function&, ValueStack &stack, Engine*, CodeGenerator*)
+void FF7::FF7WorldLoadBankInstruction::ProcessInst(Function&, ValueStack &stack, Engine*, CodeGenerator*)
 {
     stack.push(new BankValue("Read(" + _params[0]->getString() + ")"));
 }
 
-void FF7::FF7WorldLoadInstruction::processInst(Function&, ValueStack &stack, Engine*, CodeGenerator*)
+void FF7::FF7WorldLoadInstruction::ProcessInst(Function&, ValueStack &stack, Engine*, CodeGenerator*)
 {
     stack.push(new VarValue(_params[0]->getString()));
 }
 
-void FF7::FF7SubStackInstruction::processInst(Function&, ValueStack &stack, Engine*, CodeGenerator*)
+void FF7::FF7SubStackInstruction::ProcessInst(Function&, ValueStack &stack, Engine*, CodeGenerator*)
 {
     std::string op;
     switch (_opcode)
@@ -116,7 +116,7 @@ void FF7::FF7SubStackInstruction::processInst(Function&, ValueStack &stack, Engi
     stack.push(new VarValue(strValue));
 }
 
-void FF7::FF7WorldStoreInstruction::processInst(Function&, ValueStack &stack, Engine*, CodeGenerator *codeGen)
+void FF7::FF7WorldStoreInstruction::ProcessInst(Function&, ValueStack &stack, Engine*, CodeGenerator *codeGen)
 {
     std::string strValue = stack.pop()->getString();
 
@@ -127,17 +127,17 @@ void FF7::FF7WorldStoreInstruction::processInst(Function&, ValueStack &stack, En
     codeGen->AddOutputLine("Write(" + bankAddr + ", " + strValue + ");");
 }
 
-void FF7::FF7WorldStackInstruction::processInst(Function&, ValueStack&, Engine*, CodeGenerator*)
+void FF7::FF7WorldStackInstruction::ProcessInst(Function&, ValueStack&, Engine*, CodeGenerator*)
 {
 
 }
 
-void FF7::FF7WorldCondJumpInstruction::processInst(Function&, ValueStack&, Engine*, CodeGenerator*)
+void FF7::FF7WorldCondJumpInstruction::ProcessInst(Function&, ValueStack&, Engine*, CodeGenerator*)
 {
 
 }
 
-uint32 FF7::FF7WorldCondJumpInstruction::getDestAddress() const
+uint32 FF7::FF7WorldCondJumpInstruction::GetDestAddress() const
 {
     return 0x200 + _params[0]->getUnsigned();
 }
@@ -149,17 +149,17 @@ std::ostream& FF7::FF7WorldCondJumpInstruction::print(std::ostream &output) cons
 }
 
 
-bool FF7::FF7WorldUncondJumpInstruction::isFuncCall() const
+bool FF7::FF7WorldUncondJumpInstruction::IsFuncCall() const
 {
 	return _isCall;
 }
 
-bool FF7::FF7WorldUncondJumpInstruction::isUncondJump() const
+bool FF7::FF7WorldUncondJumpInstruction::IsUncondJump() const
 {
 	return !_isCall;
 }
 
-uint32 FF7::FF7WorldUncondJumpInstruction::getDestAddress() const
+uint32 FF7::FF7WorldUncondJumpInstruction::GetDestAddress() const
 {
     // the world map while loops are incorrect without +1'in this, but
     // doing that will break some if elses.. hmm
@@ -169,17 +169,17 @@ uint32 FF7::FF7WorldUncondJumpInstruction::getDestAddress() const
 std::ostream& FF7::FF7WorldUncondJumpInstruction::print(std::ostream &output) const
 {
     Instruction::print(output);
- //   output << " (Jump target address: 0x" << std::hex << getDestAddress() << std::dec << ")";
+ //   output << " (Jump target address: 0x" << std::hex << GetDestAddress() << std::dec << ")";
     return output;
 }
 
 
-void FF7::FF7WorldUncondJumpInstruction::processInst(Function& , ValueStack&, Engine*, CodeGenerator*)
+void FF7::FF7WorldUncondJumpInstruction::ProcessInst(Function& , ValueStack&, Engine*, CodeGenerator*)
 {
 
 }
 
-void FF7::FF7WorldKernelCallInstruction::processInst(Function& , ValueStack &stack, Engine*, CodeGenerator *codeGen)
+void FF7::FF7WorldKernelCallInstruction::ProcessInst(Function& , ValueStack &stack, Engine*, CodeGenerator *codeGen)
 {
     std::string strFunc;
     switch (_opcode)
@@ -463,7 +463,7 @@ void FF7::FF7WorldKernelCallInstruction::processInst(Function& , ValueStack &sta
     codeGen->AddOutputLine(strFunc);
 }
 
-void FF7::FF7WorldNoOutputInstruction::processInst(Function&, ValueStack&, Engine*, CodeGenerator*)
+void FF7::FF7WorldNoOutputInstruction::ProcessInst(Function&, ValueStack&, Engine*, CodeGenerator*)
 {
 
 }

+ 14 - 0
V-Gears-Installer/src/ff7DataInstaller.cpp

@@ -608,6 +608,7 @@ static void FF7PcFieldToVGearsField(
   MapCollection& maps,
   std::function<void(std::string)> write_output_line
 ){
+    std::cout << "[FF7PcFieldToVGearsField] START " << field->getName() << std::endl;
     // Generate triggers script to insert into main
     // decompiled FF7 field -> LUA script.
     std::string gateway_script_data;
@@ -992,6 +993,7 @@ static void FF7PcFieldToVGearsField(
         doc.SaveFile(out_dir + "/" + FieldMapDir() + "/" + field->getName() + "/wm.xml");
     }
     maps.insert(field->getName());
+    std::cout << "[FF7PcFieldToVGearsField] END " << field->getName() << std::endl;
 }
 
 /**
@@ -1097,16 +1099,21 @@ static void CollectSpawnPoints(
     // Decompile the script just so the MAPJUMPs can be collected. This is needed to construct the
     // full list of entries to each field.
     try{
+        std::cerr << "CollectSpawnPoints: 1: " << std::endl;
         // Get the raw script bytes.
         SUDM::Field::DecompiledScript decompiled;
         const std::vector<u8> raw_field_data = field->GetRawScript();
+        std::cerr << "CollectSpawnPoints: 1: " << std::endl;
         // Decompile to LUA.
         FF7FieldScriptGatewayCollector formatter(
           field->getName(), field_id_to_name_lookup, spawn_points, this_field_id
         );
+        std::cerr << "CollectSpawnPoints: 3: " << std::endl;
+        std::cout<< "ABOUT TO DECOMPILE " << field->getName() << std::endl;
         decompiled = SUDM::Field::Decompile(
           field->getName(), raw_field_data, formatter, "", "EntityContainer = {}\n\n"
         );
+        std::cout<< "    DECOMPILED " << field->getName() << std::endl;
     }
     catch (const ::InternalDecompilerError& ex){
         std::cerr << "CollectSpawnPoints: InternalDecompilerError: " << ex.what() << std::endl;
@@ -1262,22 +1269,29 @@ void FF7DataInstaller::CollectionFieldSpawnAndScaleFactors(){
         if (IsAFieldFile(resource_name) && IsTestField(resource_name)){
             conversion_step_ ++;
             if (conversion_step_ == 1){
+                std::cout << "Loading resource file " << resource_name << std::endl;
                 field_ = VGears::LZSFLevelFileManager::GetSingleton().load(
                   resource_name, "FFVIIFields"
                 ).staticCast<VGears::FLevelFile>();
+                std::cout << "    Loaded!" << std::endl;
                 //write_output_line("Load field " + resource_name);
+
                 return;
             }
             if (conversion_step_ == 2){
+                std::cout << "Step 2" << std::endl;
                 //write_output_line("Read spawn points from scripts");
                 CollectSpawnPoints(field_, map_list_, spawn_points_);
+                std::cout << "    Step 2 END" << std::endl;
                 return;
             }
             if (conversion_step_ == 3){
+                std::cout << "Step 3" << std::endl;
                 //write_output_line("Read scale factor");
                 CollectFieldScaleFactors(field_, scale_factors_, map_list_);
                 conversion_step_ = 0;
                 iterator_counter_ ++;
+                std::cout << "    Step 3 END" << std::endl;
                 return;
             }
         }

+ 19 - 0
V-Gears/src/data/VGearsFLevelFileSerializer.cpp

@@ -13,6 +13,7 @@
  * GNU General Public License for more details.
  */
 
+#include <iostream>
 #include <OgreLogManager.h>
 #include <OgreException.h>
 #include "data/VGearsFLevelFileSerializer.h"
@@ -50,6 +51,7 @@ namespace VGears{
     ){
         // Read header.
         const size_t start_position(stream->tell());
+        header_.version = 0;
         ReadFileHeader(stream);
         // Read section offsets.
         std::vector<uint32> section_offsetsVec(header_.section_count);
@@ -97,8 +99,25 @@ namespace VGears{
 
     void FLevelFileSerializer::ReadFileHeader(Ogre::DataStreamPtr &stream){
         // Read version, check if its zero.
+        std::cout << "Stream data: " << std::endl;
+        //std::cout << "    AS string: " << stream->getAsString() << std::endl;
+        std::cout << "    SIZE: " << stream->size() << std::endl;
+        std::cout << "    POS : " << stream->tell() << std::endl;
+        std::cout << "    READ: " << stream->isReadable() << std::endl;
+        std::cout << "    READ: " << stream->isWriteable() << std::endl;
+        std::cout << "    MODE: " << stream->getAccessMode() << " R"<< stream->READ << " W" << stream->WRITE << std::endl;
+        std::cout << "    NAME: " << stream->getName() << std::endl;
+        //std::cout << "    NAME: " << stream->seek(0) << std::endl;
+        // stream->read(*header_.version, 2);
         ReadShort(stream, header_.version);
+        //ReadUInt16(stream, header_.version);
+        //uint8 version = 0;
+        //ReadUInt8(stream, version);
+        //header_.version = version;
+        //std::cout << "    HEADER  8: " << version << std::endl;
+        std::cout << "    HEADER 16: " << header_.version << std::endl;
         if (header_.version != 0){
+            stream->close();
             OGRE_EXCEPT(
               Ogre::Exception::ERR_INVALIDPARAMS,
               "FLevel has unsupported version",

+ 4 - 1
V-Gears/src/data/VGearsLZSFLevelFile.cpp

@@ -13,6 +13,7 @@
  * GNU General Public License for more details.
  */
 
+#include <iostream>
 #include "data/VGearsLZSFLevelFile.h"
 #include "data/VGearsLZSDataStream.h"
 
@@ -25,7 +26,9 @@ namespace VGears{
       Ogre::ResourceManager *creator, const String &name,
       Ogre::ResourceHandle handle, const String &group, bool is_manual,
       Ogre::ManualResourceLoader *loader
-    ) : FLevelFile(creator, name, handle, group, is_manual, loader){}
+    ) : FLevelFile(creator, name, handle, group, is_manual, loader){
+        std::cout << "[LZSFLevelFile] " << name << std::endl;
+    }
 
     LZSFLevelFile::~LZSFLevelFile(){}