Browse Source

Several changes in the installer and field gameplay:
- Entities now carry the same index as in the orginal game field scripts.
- Improved jump and climb actions. The entity positions are set after the action, animations are played, and the entity orientates properly.
- Entities can now be retrieved by index from the field scripts.
- Increased maximum number of tiles per map.
- Improved and simplified trigger interaction checks.
- Some keycodes are translated to game mappings on IsKeyon and IsKeyOff functions.
- Improved reataching entities to walkmesh based on their Z position.
- Fixed opcodes: SPLIT, IFKEYOFF, BITOFF, OFST.
- Implemented opcodes: JUMP, AXYZI, LADER.
- Some code formatiing and documentation.

Iñigo Valentin 3 năm trước cách đây
mục cha
commit
8d2cdb9157

+ 8 - 6
V-Gears-Installer/src/ff7DataInstaller.cpp

@@ -791,15 +791,14 @@ static void FF7PcFieldToQGearsField(
         }
 
         // Get entities.
-        for (const auto& it : decompiled.entities){
+        for (SUDM::FF7::Field::FieldEntity entity : decompiled.entities){
             // If the entity has been added as a line, skip.
             if (line_entities.size() > 0){
-                if (*std::find(line_entities.begin(), line_entities.end(), it.first) == it.first) {
+                if (*std::find(line_entities.begin(), line_entities.end(), entity.name) == entity.name) {
                     continue;
                 }
             }
-
-            const int char_id = it.second;
+            const int char_id = entity.char_id;
             if (char_id != -1){
                 const QGears::ModelListFile::ModelDescription& desc
                   = models->GetModels().at(char_id);
@@ -807,7 +806,7 @@ static void FF7PcFieldToQGearsField(
                 for (auto& anim : desc.animations)
                     animations.insert(model_animation_db.NormalizeAnimationName(anim.name));
                 std::unique_ptr<TiXmlElement> xml_entity_script(new TiXmlElement("entity_model"));
-                xml_entity_script->SetAttribute("name", it.first);
+                xml_entity_script->SetAttribute("name", entity.name);
                 // TODO: Add to list of HRC's to convert, obtain name of converted .mesh file.
                 auto lower_case_hrc_name = desc.hrc_name;
                 QGears::StringUtil::toLowerCase(lower_case_hrc_name);
@@ -815,6 +814,7 @@ static void FF7PcFieldToQGearsField(
                   "file_name",
                   FieldModelDir() + "/" + model_animation_db.ModelMetaDataName(lower_case_hrc_name)
                 );
+                xml_entity_script->SetAttribute("index", entity.index);
                 if (desc.type == QGears::ModelListFile::PLAYER){
                     // For player models the position is set manually in the xml because if a map
                     // is loaded manually this is where the player will end up. Hence we set the
@@ -839,7 +839,7 @@ static void FF7PcFieldToQGearsField(
             }
             else{
                 std::unique_ptr<TiXmlElement> xml_entity_script(new TiXmlElement("entity_script"));
-                xml_entity_script->SetAttribute("name", it.first);
+                xml_entity_script->SetAttribute("name", entity.name);//it.first);
                 element->LinkEndChild(xml_entity_script.release());
             }
         }
@@ -1206,6 +1206,8 @@ static bool IsTestField(Ogre::String& resource_name){
       || resource_name == "nmkin_1"
       || resource_name == "nmkin_2"
       || resource_name == "nmkin_3"
+      || resource_name == "nmkin_4"
+      || resource_name == "nmkin_5"
       || resource_name == "nrthmk"
       || resource_name == "elevtr1"
       || resource_name == "tin_1"

+ 98 - 22
V-Gears/include/core/Entity.h

@@ -154,19 +154,25 @@ class Entity{
             NONE,
 
             /**
-             * The entity is in the walkmesh.
+             * The entity is attached to the walkmesh.
              */
             WALKMESH,
 
             /**
-             * @todo Understand and document.
+             * The entity is in the middle of a linear movement.
              */
             LINEAR,
 
             /**
-             * @todo Understand and document.
+             * The entity is in the middle of a jump.
              */
-            JUMP
+            JUMP,
+
+            /**
+             * The entity has completed an action and needs to be reattached
+             * to the walkmesh before continuing execution.
+             */
+            NEEDS_TO_REATTACH
         };
 
         /**
@@ -283,6 +289,20 @@ class Entity{
          */
         virtual void setScale(const Ogre::Vector3 &scale);
 
+        /**
+         * Sets the entity index in the field.
+         *
+         * @param index[in] Index of the entity.
+         */
+        void SetIndex(const int index);
+
+        /**
+         * Retrieves the entity index in the field.
+         *
+         * @return Index of the entity.
+         */
+        int GetIndex();
+
         /**
          * Sets the entity's absolute orientation.
          *
@@ -554,7 +574,7 @@ class Entity{
         const Ogre::String& GetMoveAnimationRunName() const;
 
         /**
-         * Makes the unit move to a point in the map.
+         * Makes the entity move to a point in the map.
          *
          * @param x[in] X coordinate of the destination point.
          * @param y[in] Y coordinate of the destination point.
@@ -569,13 +589,19 @@ class Entity{
         void ScriptMoveToEntity(Entity* entity);
 
         /**
-         * Adds the entity's movement to the sync queue.
+         * Waits for entity's movement to end.
          *
          * @return Always -1.
-         * @todo Properly describe this.
          */
         int ScriptMoveSync();
 
+        /**
+         * Waits for the jump to finish.
+         *
+         * @return Always -1.
+         */
+        int ScriptJumpSync();
+
         /**
          * Cancels the entity's current movement.
          *
@@ -591,10 +617,13 @@ class Entity{
          * @param z[in] Z coordinate of the destination point.
          * @param movement[in] Movement direction.
          * @param animation[in] Movement animation.
+         * @param orientation[in] Orientation during the animation.
+         * @param dest_triangle[in] Triangle to place the entity after the
+         * linear movement.
          */
         void ScriptLinearToPosition(
-          const float x, const float y, const float z,
-          const LinearMovement movement, const char* animation
+          const float x, const float y, const float z, const LinearMovement movement,
+          const char* animation, const float orientation, const int dest_triangle
         );
 
         /**
@@ -611,10 +640,13 @@ class Entity{
          * @param end[in] Destination point.
          * @param movement[in] Movement direction.
          * @param animation[in] Movement animation.
+         * @param orientation[in] Orientation during the animation.
+         * @param dest_triangle[in] Triangle to place the entity after the
+         * linear movement.
          */
         void SetLinear(
           const Ogre::Vector3& end, const LinearMovement movement,
-          const Ogre::String& animation
+          const Ogre::String& animation, const float orientation, const int dest_triangle
         );
 
         /**
@@ -645,33 +677,34 @@ class Entity{
          */
         const Ogre::Vector3& GetLinearEnd() const;
 
+        /**
+         * Retrieves the ending triangle of the current linear movement.
+         *
+         * @return Ending triangle.
+         */
+        const int GetLinearDestTriangle() const;
+
         /**
          * Makes the unit jump to a point in the field.
          *
          * @param x[in] X coordinate of the jump destination point.
          * @param y[in] Y coordinate of the jump destination point.
-         * @param z[in] Z coordinate of the jump destination point.
+         * @param z[in] Maximum height of the jump.
          * @param seconds[in] Jump duration.
+         * @param dest_triangle Triangle to place the entity after the jump.
          */
         void ScriptJumpToPosition(
-          const float x, const float y, const float z,const float seconds
+          const float x, const float y, const float z, const float seconds, const int dest_triangle
         );
 
-        /**
-         * Adds the entity's jump to the sync queue.
-         *
-         * @return Always -1.
-         * @todo Properly describe this.
-         */
-        int ScriptJumpSync();
-
         /**
          * Makes the unit jump to a point in the field.
          *
          * @param jump_to[in] The jump destination point.
          * @param seconds[in] Jump duration.
+         * @param dest_triangle Triangle to place the entity after the jump.
          */
-        void SetJump(const Ogre::Vector3& jump_to, const float seconds);
+        void SetJump(const Ogre::Vector3& jump_to, const float seconds, const int dest_triangle);
 
         /**
          * Cancels the entity's current jump.
@@ -715,6 +748,13 @@ class Entity{
          */
         float GetJumpCurrentSeconds() const;
 
+        /**
+         * Retrieves the ending triangle of the current jump.
+         *
+         * @return Ending triangle.
+         */
+        const int GetJumpDestTriangle() const;
+
         /**
          * @todo Understand and document.
          *
@@ -827,7 +867,10 @@ class Entity{
          * @param seconds[in] Total turn duration, in seconds.
          * @todo What if the point
          */
-        void SetTurn(const Ogre::Degree& direction_to, Entity* entity, const TurnDirection turn_direction, const ActionType turn_type, const float seconds);
+        void SetTurn(
+          const Ogre::Degree& direction_to, Entity* entity, const TurnDirection turn_direction,
+          const ActionType turn_type, const float seconds
+        );
 
         /**
          * Cancels the entity's current jump.
@@ -1037,6 +1080,13 @@ class Entity{
          */
         std::string GetCharacterName();
 
+        /**
+         * Checks if the entity is a line.
+         *
+         * @return True if the entity is a line, false otherwise.
+         */
+        bool IsLine();
+
     protected:
 
         /**
@@ -1194,6 +1244,11 @@ class Entity{
          */
         Ogre::Vector3 linear_end_;
 
+        /**
+         * Triangle to set the entity on after a linear movement.
+         */
+        int linear_dest_triangle_;
+
         /**
          * The jump starting point.
          */
@@ -1214,6 +1269,16 @@ class Entity{
          */
         float jump_current_seconds_;
 
+        /**
+         * Used to store solidity status before a jump.
+         */
+        bool jump_was_solid_;
+
+        /**
+         * Triangle to set the entity on after a jump.
+         */
+        int jump_dest_triangle_;
+
         /**
          * @todo Understand and document.
          */
@@ -1344,5 +1409,16 @@ class Entity{
         uint character_id_;
 
         std::string character_name_;
+
+        /**
+         * Index of the entity on the field.
+         */
+        int index_;
+
+        /**
+         * Indicates if the entity is a line.
+         */
+        bool is_line_;
+
 };
 

+ 32 - 15
V-Gears/include/core/EntityManager.h

@@ -97,10 +97,11 @@ class EntityManager : public Ogre::Singleton<EntityManager>{
          * @param file_name[in] Path to the entity model file.
          * @param position[in] Entity position in the map.
          * @param direction[in] Entity face direction.
+         * @param index[in] Index of the entity on the map.
          */
         void AddEntity(
           const Ogre::String& name, const Ogre::String& file_name,
-          const Ogre::Vector3& position, const Ogre::Degree& direction
+          const Ogre::Vector3& position, const Ogre::Degree& direction, int index
         );
 
         /**
@@ -112,11 +113,12 @@ class EntityManager : public Ogre::Singleton<EntityManager>{
          * @param rotation[in] Entity face direction.
          * @param scale[in] Entity scale.
          * @param root_orientation[in] Map orientation.
+         * @param index[in] Index of the entity on the map.
          */
         void AddEntity(
           const Ogre::String& name, const Ogre::String& file_name,
           const Ogre::Vector3& position, const Ogre::Degree& rotation,
-          const Ogre::Vector3& scale, const Ogre::Quaternion& root_orientation
+          const Ogre::Vector3& scale, const Ogre::Quaternion& root_orientation, int index
         );
 
         /**
@@ -128,10 +130,11 @@ class EntityManager : public Ogre::Singleton<EntityManager>{
          * @param y[in] Y coordinate of the entity position in the map.
          * @param z[in] Z coordinate of the entity position in the map.
          * @param direction[in] Entity face direction.
+         * @param index[in] Index of the entity on the map.
          */
         void ScriptAddEntity(
           const char* name, const char* file_name,
-          const float x, const float y, const float z, const float direction
+          const float x, const float y, const float z, const float direction, int index
         );
 
         /**
@@ -185,6 +188,14 @@ class EntityManager : public Ogre::Singleton<EntityManager>{
          */
         Entity* GetEntity(const Ogre::String& name) const;
 
+        /**
+         * Retrieves an entity by it's index in the field.
+         *
+         * @param index[in] Index of the entity to retrieve.
+         * @return The entity with the ID, or nullptr if there is no one.
+         */
+        Entity* GetEntityFromIndex(const int id) const;
+
         /**
          * Retrieves an entity by it's assigned character ID.
          *
@@ -311,7 +322,7 @@ class EntityManager : public Ogre::Singleton<EntityManager>{
          * @param key_code[in] The code of the key to test.
          * @return False if the key is being pressed, true otherwise.
          */
-        bool IsKeyOn(unsigned int key_code);
+        bool IsKeyOff(unsigned int key_code);
 
         /**
          * Assigns a character to an entity.
@@ -327,7 +338,10 @@ class EntityManager : public Ogre::Singleton<EntityManager>{
         /**
          * Attaches an entity to the walkmesh.
          *
-         * It sets the triangle from the entity position coordinates.
+         * It sets the triangle from the entity position coordinates. To
+         * account for multiple triangles on different levels, it uses only
+         * the X and Y coordinates, and automatically sets the Z one to the
+         * closest triangle.
          *
          * @param entity[in] Entity to attach.
          * @return True if the entity was assigned to a walkmesh triangle,
@@ -379,14 +393,17 @@ class EntityManager : public Ogre::Singleton<EntityManager>{
         );
 
         /**
-         * Checks for entity triggers at a specified location.
+         * Checks for entity triggers near a entity.
          *
-         * @param entity[in] Entity to check for triggers.
-         * @param position[in] Position of the entity trigger.
-         * @return True if the entity is colliding with another, false
-         * otherwise. If the entity is not solid, always false.
+         * If there are triggers, and the conditions are met, the appropriate
+         * trigger function will be added to the queue. This must be tested
+         * every time an entity moves. If the entity is not solid, it will do
+         * nothing.
+         *
+         * @param entity[in] Entity to check for nearby triggers.
+         * @param position[in] The position of the entity.
          */
-        void CheckTriggers(Entity* entity, Ogre::Vector3& position);
+        void CheckTriggers(Entity* entity, const Ogre::Vector3& position);
 
         /**
          * Checks if an entity can be interacted.
@@ -413,16 +430,16 @@ class EntityManager : public Ogre::Singleton<EntityManager>{
         void SetNextTurnStep(Entity* entity);
 
         /**
-         * @todo Understand and document.
+         * Calculates and sets the next position during a linear movement.
          *
-         * @param entity[in] @todo.
+         * @param entity[in] The moving entity.
          */
         void SetNextLinearStep(Entity* entity);
 
         /**
-         * @todo Understand and document.
+         * Calculates and sets the next position during a jump.
          *
-         * @param entity[in] @todo.
+         * @param entity[in] The jump entity.
          */
         void SetNextJumpStep(Entity* entity);
 

+ 12 - 6
V-Gears/include/core/ScriptManagerBinds.h

@@ -110,7 +110,8 @@ void ScriptManager::InitBinds(){
           .def(
             "linear_to_position",
             (void(Entity::*)(
-              const float, const float, const float, const LinearMovement, const char*
+              const float, const float, const float, const LinearMovement,
+              const char*, const float, const int
             )) &Entity::ScriptLinearToPosition
           )
           .def(
@@ -118,7 +119,7 @@ void ScriptManager::InitBinds(){
           )
           .def(
             "jump_to_position",
-            (void(Entity::*)(const float, const float, const float, const float))
+            (void(Entity::*)(const float, const float, const float, const float, const int))
               &Entity::ScriptJumpToPosition
           )
           .def("jump_sync", (int(Entity::*)()) &Entity::ScriptJumpSync, luabind::yield)
@@ -200,7 +201,8 @@ void ScriptManager::InitBinds(){
           .def(
              "add_entity",
              (void(EntityManager::*)(
-               const char*, const char*, const float, const float, const float, const float
+               const char*, const char*, const float,const float,
+               const float, const float, const int
              )) &EntityManager::ScriptAddEntity
           )
           .def(
@@ -210,6 +212,10 @@ void ScriptManager::InitBinds(){
           .def(
              "get_entity", (Entity*(EntityManager::*)(const char*)) &EntityManager::ScriptGetEntity
           )
+          .def(
+             "get_entity_from_index",
+             (Entity*(EntityManager::*)(const int)) &EntityManager::GetEntityFromIndex
+           )
           .def(
              "get_entity_from_character_id",
              (Entity*(EntityManager::*)(const char*)) &EntityManager::GetEntityFromCharacterId
@@ -223,9 +229,9 @@ void ScriptManager::InitBinds(){
              (void(EntityManager::*)(const char*)) &EntityManager::ScriptSetPlayerEntity
           )
           .def(
-               "get_player_entity",
-               (Entity*(EntityManager::*)()) &EntityManager::ScriptGetPlayerEntity
-            )
+             "get_player_entity",
+             (Entity*(EntityManager::*)()) &EntityManager::ScriptGetPlayerEntity
+          )
           .def(
             "unset_player_entity",
             (void(EntityManager::*)()) &EntityManager::ScriptUnsetPlayerEntity

+ 207 - 328
V-Gears/src/core/Background2D.cpp

@@ -26,37 +26,29 @@
 #include "core/Logger.h"
 #include "core/Timer.h"
 
-ConfigVar cv_debug_background2d(
-  "debug_background2d", "Draw background debug info", "false"
-);
-ConfigVar cv_show_background2d(
-  "show_background2d", "Draw background", "true"
-);
-ConfigVar cv_background2d_manual(
-  "background2d_manual", "Manual scrolling for 2d background", "false"
-);
+ConfigVar cv_debug_background2d("debug_background2d", "Draw background debug info", "false");
+ConfigVar cv_show_background2d("show_background2d", "Draw background", "true");
+ConfigVar cv_background2d_manual("background2d_manual", "Manual 2d background scrolling", "false");
 
 Background2D::Background2D():
-    alpha_max_vertex_count_(0),
-    add_max_vertex_count_(0),
-    subtract_max_vertex_count_(0),
-    scroll_entity_(nullptr),
-    scroll_position_start_(Ogre::Vector2::ZERO),
-    scroll_position_end_(Ogre::Vector2::ZERO),
-    scroll_type_(Background2D::NONE),
-    scroll_seconds_(0),
-    scroll_current_seconds_(0),
-    position_(Ogre::Vector2::ZERO),
-    position_real_(Ogre::Vector2::ZERO),
-    range_(Ogre::AxisAlignedBox::BOX_INFINITE),
-    virtual_screen_size_(320, 240) // FFVII original resolution
+  alpha_max_vertex_count_(0),
+  add_max_vertex_count_(0),
+  subtract_max_vertex_count_(0),
+  scroll_entity_(nullptr),
+  scroll_position_start_(Ogre::Vector2::ZERO),
+  scroll_position_end_(Ogre::Vector2::ZERO),
+  scroll_type_(Background2D::NONE),
+  scroll_seconds_(0),
+  scroll_current_seconds_(0),
+  position_(Ogre::Vector2::ZERO),
+  position_real_(Ogre::Vector2::ZERO),
+  range_(Ogre::AxisAlignedBox::BOX_INFINITE),
+  virtual_screen_size_(320, 240) // FFVII original resolution
 {
     scene_manager_ = Ogre::Root::getSingleton().getSceneManager("Scene");
     render_system_ = Ogre::Root::getSingletonPtr()->getRenderSystem();
     CreateVertexBuffers();
-    alpha_material_ = Ogre::MaterialManager::getSingleton().create(
-      "Background2DAlpha", "General"
-    );
+    alpha_material_ = Ogre::MaterialManager::getSingleton().create("Background2DAlpha", "General");
     Ogre::Pass* pass = alpha_material_->getTechnique(0)->getPass(0);
     pass->setVertexColourTracking(Ogre::TVC_AMBIENT);
     pass->setCullingMode(Ogre::CULL_NONE);
@@ -70,10 +62,7 @@ Background2D::Background2D():
     tex->setTextureName("system/blank.png");
     tex->setNumMipmaps(-1);
     tex->setTextureFiltering(Ogre::TFO_NONE);
-
-    add_material = Ogre::MaterialManager::getSingleton().create(
-      "Background2DAdd", "General"
-    );
+    add_material = Ogre::MaterialManager::getSingleton().create("Background2DAdd", "General");
     pass = add_material->getTechnique(0)->getPass(0);
     pass->setVertexColourTracking(Ogre::TVC_AMBIENT);
     pass->setCullingMode(Ogre::CULL_NONE);
@@ -87,7 +76,6 @@ Background2D::Background2D():
     tex->setTextureName("system/blank.png");
     tex->setNumMipmaps(-1);
     tex->setTextureFiltering(Ogre::TFO_NONE);
-
     subtract_material_ = Ogre::MaterialManager::getSingleton().create(
       "Background2DSubtract", "General"
     );
@@ -108,20 +96,14 @@ Background2D::Background2D():
     scene_manager_->addRenderQueueListener(this);
 }
 
-
 Background2D::~Background2D(){
     scene_manager_->removeRenderQueueListener(this);
-    for (unsigned int i = 0; i < animations_.size(); ++ i)
-        delete animations_[i];
+    for (unsigned int i = 0; i < animations_.size(); ++ i) delete animations_[i];
     DestroyVertexBuffers();
 }
 
-
 void Background2D::InputDebug(const QGears::Event& event){
-    if (
-      cv_background2d_manual.GetB() == true
-      && event.type == QGears::ET_KEY_IMPULSE
-    ){
+    if (cv_background2d_manual.GetB() == true && event.type == QGears::ET_KEY_IMPULSE){
         if (event.param1 == OIS::KC_W)
             position_real_.y += 2;
         else if (event.param1 == OIS::KC_A)
@@ -137,46 +119,35 @@ void Background2D::InputDebug(const QGears::Event& event){
 void Background2D::Update(){
     for (unsigned int i = 0; i < animation_played_.size(); ++ i){
         for (unsigned int j = 0; j < animations_.size(); ++ j){
-            if( animations_[j]->GetName() == animation_played_[i].name){
+            if (animations_[j]->GetName() == animation_played_[i].name){
                 float delta_time = Timer::getSingleton().GetGameTimeDelta();
                 float time = animations_[j]->GetTime();
                 float end_time = animations_[j]->GetLength();
 
                 // If animation ended
                 if (time + delta_time >= end_time){
-                    // set to last frame of animation
+                    // Set to last frame of animation.
                     if (time != end_time) animations_[j]->SetTime(end_time);
 
-                    if (
-                      animation_played_[i].state == Background2DAnimation::ONCE
-                    ){
-                        for (
-                          unsigned int k = 0;
-                          k < animation_played_[i].sync.size();
-                          ++k
-                        ){
-                            ScriptManager::getSingleton()
-                              .ContinueScriptExecution(
-                                 animation_played_[i].sync[k]
-                               );
+                    if (animation_played_[i].state == Background2DAnimation::ONCE){
+                        for (unsigned int k = 0; k < animation_played_[i].sync.size(); ++k){
+                            ScriptManager::getSingleton().ContinueScriptExecution(
+                              animation_played_[i].sync[k]
+                            );
                         }
                         animation_played_[i].sync.clear();
                         // Mark to delete this way:
                         animation_played_[i].name = "";
                     }
-                    else { // LOOPED
-                        // In case of looped we need to sync with end
-                        animations_[j]->SetTime(time + delta_time - end_time);
-                    }
-                }
-                else{
-                    animations_[j]->AddTime(delta_time);
+                    // In case of looped, sync with end:
+                    else animations_[j]->SetTime(time + delta_time - end_time);
                 }
+                else animations_[j]->AddTime(delta_time);
             }
         }
     }
 
-    // remove stopped animations
+    // Remove stopped animations.
     std::vector<AnimationPlayed>::iterator i = animation_played_.begin();
     for(; i != animation_played_.end();){
         if ((*i).name == "") i = animation_played_.erase(i);
@@ -187,9 +158,8 @@ void Background2D::Update(){
 void Background2D::UpdateDebug(){
     // TODO: is this necessary? does it cost to apply camera 2d Scroll?
     // if so maybe move this check to applyScroll
-    if(position_real_ != GetScreenScroll()) applyScroll();
-
-    if(cv_debug_background2d.GetB() == true){
+    if (position_real_ != GetScreenScroll()) applyScroll();
+    if (cv_debug_background2d.GetB() == true){
         DEBUG_DRAW.SetTextAlignment(DEBUG_DRAW.LEFT);
         DEBUG_DRAW.SetScreenSpace(true);
         DEBUG_DRAW.SetColour(Ogre::ColourValue(0.0f, 0.8f, 0.8f, 1.0f));
@@ -204,10 +174,8 @@ void Background2D::UpdateDebug(){
 
 void Background2D::calculateScreenScale(){
     Ogre::Viewport *viewport(CameraManager::getSingleton().getViewport());
-    Ogre::Real scale_width =
-      static_cast<Ogre::Real>(viewport->getActualWidth());
-    Ogre::Real scale_height =
-      static_cast<Ogre::Real>(viewport->getActualHeight());
+    Ogre::Real scale_width = static_cast<Ogre::Real>(viewport->getActualWidth());
+    Ogre::Real scale_height = static_cast<Ogre::Real>(viewport->getActualHeight());
     scale_width /= virtual_screen_size_.x;
     scale_height /= virtual_screen_size_.y;
     screen_scale_ = scale_height;
@@ -217,22 +185,17 @@ void Background2D::calculateScreenScale(){
 
 void Background2D::OnResize(){
     calculateScreenScale();
-    for(unsigned int i = 0; i < tiles_.size(); ++ i){
-        Tile &tile(tiles_[ i ]);
-        Ogre::Vector2 top_left(
-          static_cast<Ogre::Real>(tile.x), static_cast<Ogre::Real>(- tile.y)
-        );
+    for (unsigned int i = 0; i < tiles_.size(); ++ i){
+        Tile &tile(tiles_[i]);
+        Ogre::Vector2 top_left(static_cast<Ogre::Real>(tile.x), static_cast<Ogre::Real>(- tile.y));
         Ogre::Vector2 top_right(
-          static_cast<Ogre::Real>(tile.x + tile.width),
-          static_cast<Ogre::Real>(top_left.y)
+          static_cast<Ogre::Real>(tile.x + tile.width), static_cast<Ogre::Real>(top_left.y)
         );
         Ogre::Vector2 bottom_right(
-          static_cast<Ogre::Real>(top_right.x),
-          static_cast<Ogre::Real>(-(tile.y + tile.height))
+          static_cast<Ogre::Real>(top_right.x), static_cast<Ogre::Real>(-(tile.y + tile.height))
         );
         Ogre::Vector2 bottom_left(
-          static_cast<Ogre::Real>(top_left.x),
-          static_cast<Ogre::Real>(bottom_right.y)
+          static_cast<Ogre::Real>(top_left.x), static_cast<Ogre::Real>(bottom_right.y)
         );
         virtualScreenToWorldSpace(top_left);
         virtualScreenToWorldSpace(top_right);
@@ -253,26 +216,25 @@ void Background2D::OnResize(){
             vertex_buffer = add_vertex_buffer_;
         else if(tiles_[i].blending == QGears::B_SUBTRACT)
             vertex_buffer = subtract_vertex_buffer_;
-        float* writeIterator =
-          (float*) vertex_buffer->lock(Ogre::HardwareBuffer::HBL_NORMAL);
-        writeIterator += tiles_[i].start_vertex_index * TILE_VERTEX_INDEX_SIZE;
-        *writeIterator ++ = new_x1;
-        *writeIterator ++ = new_y1;
-        writeIterator += 7;
-        *writeIterator ++ = new_x2;
-        *writeIterator ++ = new_y2;
-        writeIterator += 7;
-        *writeIterator ++ = new_x3;
-        *writeIterator ++ = new_y3;
-        writeIterator += 7;
-        *writeIterator++ = new_x1;
-        *writeIterator++ = new_y1;
-        writeIterator += 7;
-        *writeIterator++ = new_x3;
-        *writeIterator++ = new_y3;
-        writeIterator += 7;
-        *writeIterator++ = new_x4;
-        *writeIterator++ = new_y4;
+        float* write_iterator = (float*) vertex_buffer->lock(Ogre::HardwareBuffer::HBL_NORMAL);
+        write_iterator += tiles_[i].start_vertex_index * TILE_VERTEX_INDEX_SIZE;
+        *write_iterator ++ = new_x1;
+        *write_iterator ++ = new_y1;
+        write_iterator += 7;
+        *write_iterator ++ = new_x2;
+        *write_iterator ++ = new_y2;
+        write_iterator += 7;
+        *write_iterator ++ = new_x3;
+        *write_iterator ++ = new_y3;
+        write_iterator += 7;
+        *write_iterator++ = new_x1;
+        *write_iterator++ = new_y1;
+        write_iterator += 7;
+        *write_iterator ++ = new_x3;
+        *write_iterator ++ = new_y3;
+        write_iterator += 7;
+        *write_iterator ++ = new_x4;
+        *write_iterator ++ = new_y4;
         vertex_buffer->unlock();
     }
     applyScroll();
@@ -292,18 +254,14 @@ void Background2D::Clear(){
     animations_.clear();
     for(unsigned int i = 0; i < animation_played_.size(); ++ i)
         for(unsigned int j = 0; j < animation_played_[i].sync.size(); ++j)
-            ScriptManager::getSingleton().ContinueScriptExecution(
-              animation_played_[i].sync[j]
-            );
+            ScriptManager::getSingleton().ContinueScriptExecution(animation_played_[i].sync[j]);
     animation_played_.clear();
     tiles_.clear();
     DestroyVertexBuffers();
     CreateVertexBuffers();
 }
 
-void Background2D::ScriptAutoScrollToEntity(Entity* entity){
-    scroll_entity_ = entity;
-}
+void Background2D::ScriptAutoScrollToEntity(Entity* entity){scroll_entity_ = entity;}
 
 Entity* Background2D::GetAutoScrollEntity() const{return scroll_entity_;}
 
@@ -344,27 +302,17 @@ void Background2D::UnsetScroll(){
     scroll_sync_.clear();
 }
 
-const Ogre::Vector2& Background2D::GetScrollPositionStart() const{
-    return scroll_position_start_;
-}
+const Ogre::Vector2& Background2D::GetScrollPositionStart() const{return scroll_position_start_;}
 
-const Ogre::Vector2& Background2D::GetScrollPositionEnd() const{
-    return scroll_position_end_;
-}
+const Ogre::Vector2& Background2D::GetScrollPositionEnd() const{return scroll_position_end_;}
 
-Background2D::ScrollType Background2D::GetScrollType() const{
-    return scroll_type_;
-}
+Background2D::ScrollType Background2D::GetScrollType() const{return scroll_type_;}
 
 float Background2D::GetScrollSeconds() const{return scroll_seconds_;}
 
-void Background2D::SetScrollCurrentSeconds(const float seconds){
-    scroll_current_seconds_ = seconds;
-}
+void Background2D::SetScrollCurrentSeconds(const float seconds){scroll_current_seconds_ = seconds;}
 
-float Background2D::GetScrollCurrentSeconds() const{
-    return scroll_current_seconds_;
-}
+float Background2D::GetScrollCurrentSeconds() const{return scroll_current_seconds_;}
 
 void Background2D::SetScreenScroll(const Ogre::Vector2& position){
     SetScroll(position / screen_scale_);
@@ -391,18 +339,12 @@ void Background2D::applyScroll(){
     }
 }
 
+const Ogre::Vector2& Background2D::GetScroll() const{return position_;}
 
-const Ogre::Vector2& Background2D::GetScroll() const{
-    return position_;
-}
-
-const Ogre::Vector2 Background2D::GetScreenScroll() const{
-    return GetScroll() * screen_scale_;
-}
+const Ogre::Vector2 Background2D::GetScreenScroll() const{return GetScroll() * screen_scale_;}
 
 void Background2D::SetImage(const Ogre::String& image){
-    Ogre::LogManager::getSingleton().stream()
-      << "Background2D::SetImage " << image;
+    Ogre::LogManager::getSingleton().stream() << "Background2D::SetImage " << image;
     Ogre::Pass* pass = alpha_material_->getTechnique(0)->getPass(0);
     Ogre::TextureUnitState* tex = pass->getTextureUnitState(0);
     tex->setTextureName(image);
@@ -418,38 +360,27 @@ void Background2D::SetRange(const Ogre::Vector4& range){
     SetRange((int)range.x, (int)range.y, (int)range.z, (int)range.w);
 }
 
-void Background2D::SetRange(
-  const int min_x, const int min_y, const int max_x, const int max_y
-){
+void Background2D::SetRange(const int min_x, const int min_y, const int max_x, const int max_y){
     Ogre::LogManager::getSingleton().stream()
-      << "Background2D::SetRange " << min_x << " " << min_y
-      << " " << max_x << " " << max_y;
+      << "Background2D::SetRange " << min_x << " " << min_y << " " << max_x << " " << max_y;
     Ogre::Vector2 half_virtual_screen_size(virtual_screen_size_ / 2);
     half_virtual_screen_size /= screen_proportion_;
-    range_.setMaximum(
-      max_x - half_virtual_screen_size.x , max_y - half_virtual_screen_size.y, 1
-    );
-    range_.setMinimum(
-      min_x + half_virtual_screen_size.x , min_y + half_virtual_screen_size.y, 0
-    );
-    Ogre::LogManager::getSingleton().stream()
-      << "Background2D::SetRange " << range_;
-
+    range_.setMaximum(max_x - half_virtual_screen_size.x , max_y - half_virtual_screen_size.y, 1);
+    range_.setMinimum(min_x + half_virtual_screen_size.x , min_y + half_virtual_screen_size.y, 0);
+    Ogre::LogManager::getSingleton().stream() << "Background2D::SetRange " << range_;
     calculateScreenScale();
 }
 
-
 void Background2D::AddTile(const QGears::Tile& tile){
     // TODO: move depth calculation to flevelBackgroundLoader maybe? and let
     // Backgorund2D only handle 0 <= depth <= 1 or so?
     // Maybe just move the < 4095 part to flevel background loader?
     Ogre::Real depth(0.0001f);
-    if(tile.depth >= 1){
-        if(tile.depth < 4095){
+    if (tile.depth >= 1){
+        if (tile.depth < 4095){
             const Ogre::Matrix4 &cam_projection(
-              CameraManager::getSingleton().GetCurrentCamera()
-                ->getProjectionMatrixWithRSDepth()
-              );
+              CameraManager::getSingleton().GetCurrentCamera()->getProjectionMatrixWithRSDepth()
+            );
             Ogre::Vector4 res(0, 0, -tile.depth, 1);
             res = cam_projection * res;
             res /= res.w;
@@ -478,24 +409,23 @@ void Background2D::virtualScreenToWorldSpace(Ogre::Vector2& pos) const{
 }
 
 void Background2D::AddTile(
-  const int x, const int y, const int width, const int height,
-  const float depth, const float u1, const float v1,
-  const float u2, const float v2, const Blending blending
+  const int x, const int y, const int width, const int height, const float depth, const float u1,
+  const float v1, const float u2, const float v2, const Blending blending
 ){
     Ogre::RenderOperation render_op;
     Ogre::HardwareVertexBufferSharedPtr vertex_buffer;
     unsigned int max_vertex_count;
-    if(blending == QGears::B_ALPHA){
+    if (blending == QGears::B_ALPHA){
         render_op = alpha_render_op_;
         vertex_buffer = alpha_vertex_buffer_;
         max_vertex_count = alpha_max_vertex_count_;
     }
-    else if(blending == QGears::B_ADD){
+    else if (blending == QGears::B_ADD){
         render_op = add_render_op_;
         vertex_buffer = add_vertex_buffer_;
         max_vertex_count = add_max_vertex_count_;
     }
-    else if(blending == QGears::B_SUBTRACT){
+    else if (blending == QGears::B_SUBTRACT){
         render_op = subtract_render_op_;
         vertex_buffer = subtract_vertex_buffer_;
         max_vertex_count = subtract_max_vertex_count_;
@@ -504,14 +434,10 @@ void Background2D::AddTile(
         LOG_ERROR("Unknown blending type.");
         return;
     }
-    if (
-      render_op.vertexData->vertexCount + TILE_VERTEX_COUNT > max_vertex_count
-    ){
+    if (render_op.vertexData->vertexCount + TILE_VERTEX_COUNT > max_vertex_count){
         LOG_ERROR(
           "Max number of tiles reached. Can't create more than "
-          + Ogre::StringConverter::toString(
-            max_vertex_count / TILE_VERTEX_COUNT
-          ) + " tiles."
+          + Ogre::StringConverter::toString(max_vertex_count / TILE_VERTEX_COUNT) + " tiles."
         );
         return;
     }
@@ -524,9 +450,7 @@ void Background2D::AddTile(
     tile.blending = blending;
     size_t index(tiles_.size());
     tiles_.push_back(tile);
-    Ogre::Vector2 top_left(
-      static_cast<Ogre::Real>(x), static_cast<Ogre::Real>(-y)
-    );
+    Ogre::Vector2 top_left(static_cast<Ogre::Real>(x), static_cast<Ogre::Real>(-y));
     Ogre::Vector2 top_right(
       static_cast<Ogre::Real>(x + width), static_cast<Ogre::Real>(top_left.y)
     );
@@ -547,79 +471,73 @@ void Background2D::AddTile(
     float new_y3 = bottom_right.y;
     float new_x4 = bottom_left.x;
     float new_y4 = bottom_left.y;
-    float* writeIterator
-      = (float*) vertex_buffer->lock(Ogre::HardwareBuffer::HBL_NORMAL);
-    writeIterator
-      += render_op.vertexData->vertexCount * TILE_VERTEX_INDEX_SIZE;
+    float* write_iterator = (float*) vertex_buffer->lock(Ogre::HardwareBuffer::HBL_NORMAL);
+    write_iterator += render_op.vertexData->vertexCount * TILE_VERTEX_INDEX_SIZE;
 
     // TODO: Can use WriteGlyph
-    *writeIterator ++ = new_x1;
-    *writeIterator ++ = new_y1;
-    *writeIterator ++ = depth;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = u1;
-    *writeIterator ++ = v1;
-    *writeIterator ++ = new_x2;
-    *writeIterator ++ = new_y2;
-    *writeIterator ++ = depth;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = u2;
-    *writeIterator ++ = v1;
-    *writeIterator ++ = new_x3;
-    *writeIterator ++ = new_y3;
-    *writeIterator ++ = depth;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = u2;
-    *writeIterator ++ = v2;
-    *writeIterator ++ = new_x1;
-    *writeIterator ++ = new_y1;
-    *writeIterator ++ = depth;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = u1;
-    *writeIterator ++ = v1;
-    *writeIterator ++ = new_x3;
-    *writeIterator ++ = new_y3;
-    *writeIterator ++ = depth;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = u2;
-    *writeIterator ++ = v2;
-    *writeIterator ++ = new_x4;
-    *writeIterator ++ = new_y4;
-    *writeIterator ++ = depth;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = 1;
-    *writeIterator ++ = u1;
-    *writeIterator ++ = v2;
+    *write_iterator ++ = new_x1;
+    *write_iterator ++ = new_y1;
+    *write_iterator ++ = depth;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = u1;
+    *write_iterator ++ = v1;
+    *write_iterator ++ = new_x2;
+    *write_iterator ++ = new_y2;
+    *write_iterator ++ = depth;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = u2;
+    *write_iterator ++ = v1;
+    *write_iterator ++ = new_x3;
+    *write_iterator ++ = new_y3;
+    *write_iterator ++ = depth;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = u2;
+    *write_iterator ++ = v2;
+    *write_iterator ++ = new_x1;
+    *write_iterator ++ = new_y1;
+    *write_iterator ++ = depth;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = u1;
+    *write_iterator ++ = v1;
+    *write_iterator ++ = new_x3;
+    *write_iterator ++ = new_y3;
+    *write_iterator ++ = depth;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = u2;
+    *write_iterator ++ = v2;
+    *write_iterator ++ = new_x4;
+    *write_iterator ++ = new_y4;
+    *write_iterator ++ = depth;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = 1;
+    *write_iterator ++ = u1;
+    *write_iterator ++ = v2;
     render_op.vertexData->vertexCount += TILE_VERTEX_COUNT;
     vertex_buffer->unlock();
 }
 
 void Background2D::UpdateTileUV(
-  const unsigned int tile_id, const float u1, const float v1,
-  const float u2, const float v2
+  const unsigned int tile_id, const float u1, const float v1, const float u2, const float v2
 ){
     if (tile_id >= tiles_.size()){
-        LOG_ERROR(
-          "Tile with id " + Ogre::StringConverter::toString( tile_id )
-          + " doesn't exist."
-        );
+        LOG_ERROR("Tile with id " + Ogre::StringConverter::toString( tile_id ) + " doesn't exist.");
         return;
     }
     Ogre::HardwareVertexBufferSharedPtr vertex_buffer;
@@ -629,34 +547,30 @@ void Background2D::UpdateTileUV(
         vertex_buffer = add_vertex_buffer_;
     else if(tiles_[tile_id].blending == QGears::B_SUBTRACT)
         vertex_buffer = subtract_vertex_buffer_;
-    float* writeIterator
-      = (float*) vertex_buffer->lock(Ogre::HardwareBuffer::HBL_NORMAL);
-    writeIterator
-      += tiles_[tile_id].start_vertex_index * TILE_VERTEX_INDEX_SIZE;
-    writeIterator += 7;
-    *writeIterator ++ = u1;
-    *writeIterator ++ = v1;
-    writeIterator += 7;
-    *writeIterator ++ = u2;
-    *writeIterator ++ = v1;
-    writeIterator += 7;
-    *writeIterator ++ = u2;
-    *writeIterator ++ = v2;
-    writeIterator += 7;
-    *writeIterator ++ = u1;
-    *writeIterator ++ = v1;
-    writeIterator += 7;
-    *writeIterator ++ = u2;
-    *writeIterator ++ = v2;
-    writeIterator += 7;
-    *writeIterator ++ = u1;
-    *writeIterator ++ = v2;
+    float* write_iterator = (float*) vertex_buffer->lock(Ogre::HardwareBuffer::HBL_NORMAL);
+    write_iterator += tiles_[tile_id].start_vertex_index * TILE_VERTEX_INDEX_SIZE;
+    write_iterator += 7;
+    *write_iterator ++ = u1;
+    *write_iterator ++ = v1;
+    write_iterator += 7;
+    *write_iterator ++ = u2;
+    *write_iterator ++ = v1;
+    write_iterator += 7;
+    *write_iterator ++ = u2;
+    *write_iterator ++ = v2;
+    write_iterator += 7;
+    *write_iterator ++ = u1;
+    *write_iterator ++ = v1;
+    write_iterator += 7;
+    *write_iterator ++ = u2;
+    *write_iterator ++ = v2;
+    write_iterator += 7;
+    *write_iterator ++ = u1;
+    *write_iterator ++ = v2;
     vertex_buffer->unlock();
 }
 
-void Background2D::AddAnimation(Background2DAnimation* animation){
-    animations_.push_back(animation);
-}
+void Background2D::AddAnimation(Background2DAnimation* animation){animations_.push_back(animation);}
 
 void Background2D::PlayAnimation(
   const Ogre::String& animation, const Background2DAnimation::State state
@@ -670,9 +584,8 @@ void Background2D::PlayAnimation(
         }
     }
     for (unsigned int i = 0; i < animation_played_.size(); ++ i){
-        if (animation_played_[i].name == animation){
+        if (animation_played_[i].name == animation)
             animation_played_.erase(animation_played_.begin() + i);
-        }
     }
     if(found == true){
         AnimationPlayed anim;
@@ -696,8 +609,7 @@ void Background2D::ScriptPlayAnimationOnce(const char* name){
 int Background2D::ScriptAnimationSync(const char* animation){
     for (unsigned int i = 0; i < animation_played_.size(); ++ i){
         if (animation_played_[i].name == animation){
-            ScriptId script
-              = ScriptManager::getSingleton().GetCurrentScriptId();
+            ScriptId script = ScriptManager::getSingleton().GetCurrentScriptId();
             animation_played_[i].sync.push_back(script);
             return -1;
         }
@@ -706,53 +618,38 @@ int Background2D::ScriptAnimationSync(const char* animation){
 }
 
 void Background2D::renderQueueEnded(
-  Ogre::uint8 queue_group_id, const Ogre::String& invocation,
-  bool& repeat_this_invocation
+  Ogre::uint8 queue_group_id, const Ogre::String& invocation, bool& repeat_this_invocation
 ){
     if (cv_show_background2d.GetB() == false) return;
     if (queue_group_id == Ogre::RENDER_QUEUE_MAIN){
-        Ogre::GpuProgramParametersPtr rs_params
-          = render_system_->getFixedFunctionParams(
-            Ogre::TVC_NONE, Ogre::FOG_NONE
-          );
+        Ogre::GpuProgramParametersPtr rs_params = render_system_->getFixedFunctionParams(
+          Ogre::TVC_NONE, Ogre::FOG_NONE
+        );
         rs_params->setConstant(
           Ogre::GpuProgramParameters::ACT_WORLD_MATRIX, Ogre::Matrix4::IDENTITY
         );
         rs_params->setConstant(
-          Ogre::GpuProgramParameters::ACT_PROJECTION_MATRIX,
-          Ogre::Matrix4::IDENTITY
+          Ogre::GpuProgramParameters::ACT_PROJECTION_MATRIX, Ogre::Matrix4::IDENTITY
         );
         Ogre::Viewport *viewport(CameraManager::getSingleton().getViewport());
         float width = static_cast<float>(viewport->getActualWidth());
         float height = static_cast<float>(viewport->getActualHeight());
         Ogre::Matrix4 view;
-        view.makeTrans(
-          Ogre::Vector3(position_real_.x /* * 2*/ / width,
-          -position_real_.y /* * 2*/ / height, 0)
-        );
-        // TODO This is deprecated, but if not done , the background image
-        // disappears.
+        view.makeTrans(Ogre::Vector3(position_real_.x / width, -position_real_.y / height, 0));
+        // TODO This is deprecated, but if not done , the background image disappears.
         render_system_->_setViewMatrix(view);
-        rs_params->setConstant(
-          Ogre::GpuProgramParameters::ACT_VIEW_MATRIX, view
-        );
+        rs_params->setConstant(Ogre::GpuProgramParameters::ACT_VIEW_MATRIX, view);
         render_system_->applyFixedFunctionParams(rs_params, Ogre::GPV_GLOBAL);
         if (alpha_render_op_.vertexData->vertexCount != 0){
-            scene_manager_->_setPass(
-              alpha_material_->getTechnique(0)->getPass(0), true, false
-            );
+            scene_manager_->_setPass(alpha_material_->getTechnique(0)->getPass(0), true, false);
             render_system_->_render(alpha_render_op_);
         }
         if (add_render_op_.vertexData->vertexCount != 0){
-            scene_manager_->_setPass(
-              add_material->getTechnique(0)->getPass(0), true, false
-            );
+            scene_manager_->_setPass(add_material->getTechnique(0)->getPass(0), true, false);
             render_system_->_render(add_render_op_);
         }
         if(subtract_render_op_.vertexData->vertexCount != 0){
-            scene_manager_->_setPass(
-              subtract_material_->getTechnique(0)->getPass(0), true, false
-            );
+            scene_manager_->_setPass(subtract_material_->getTechnique(0)->getPass(0), true, false);
             render_system_->_render(subtract_render_op_);
         }
 
@@ -763,68 +660,54 @@ void Background2D::CreateVertexBuffers(){
     alpha_max_vertex_count_ = 2048 * TILE_VERTEX_COUNT;
     alpha_render_op_.vertexData = new Ogre::VertexData;
     alpha_render_op_.vertexData->vertexStart = 0;
-    Ogre::VertexDeclaration* vDecl
+    Ogre::VertexDeclaration* vertex_declaration
       = alpha_render_op_.vertexData->vertexDeclaration;
     size_t offset = 0;
-    vDecl->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
+    vertex_declaration->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
     offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
-    vDecl->addElement(0, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE);
+    vertex_declaration->addElement(0, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE);
     offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT4);
-    vDecl->addElement(
-      0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES
-    );
-    alpha_vertex_buffer_
-      = Ogre::HardwareBufferManager::getSingletonPtr()->createVertexBuffer(
-        vDecl->getVertexSize(0), alpha_max_vertex_count_,
-        Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false
-      );
-    alpha_render_op_.vertexData->vertexBufferBinding->setBinding(
-      0, alpha_vertex_buffer_
+    vertex_declaration->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);
+    alpha_vertex_buffer_ = Ogre::HardwareBufferManager::getSingletonPtr()->createVertexBuffer(
+      vertex_declaration->getVertexSize(0), alpha_max_vertex_count_,
+      Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false
     );
+    alpha_render_op_.vertexData->vertexBufferBinding->setBinding(0, alpha_vertex_buffer_);
     alpha_render_op_.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
     alpha_render_op_.useIndexes = false;
-    add_max_vertex_count_ = 256 * TILE_VERTEX_COUNT;
+    add_max_vertex_count_ = 1024 * TILE_VERTEX_COUNT;
     add_render_op_.vertexData = new Ogre::VertexData;
     add_render_op_.vertexData->vertexStart = 0;
-    vDecl = add_render_op_.vertexData->vertexDeclaration;
+    vertex_declaration = add_render_op_.vertexData->vertexDeclaration;
     offset = 0;
-    vDecl->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
+    vertex_declaration->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
     offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
-    vDecl->addElement(0, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE);
+    vertex_declaration->addElement(0, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE);
     offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT4);
-    vDecl->addElement(
-      0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES
-    );
-    add_vertex_buffer_
-      = Ogre::HardwareBufferManager::getSingletonPtr()->createVertexBuffer(
-        vDecl->getVertexSize(0), add_max_vertex_count_,
-        Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false
-      );
-    add_render_op_.vertexData->vertexBufferBinding->setBinding(
-      0, add_vertex_buffer_
+    vertex_declaration->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);
+    add_vertex_buffer_ = Ogre::HardwareBufferManager::getSingletonPtr()->createVertexBuffer(
+      vertex_declaration->getVertexSize(0), add_max_vertex_count_,
+      Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false
     );
+    add_render_op_.vertexData->vertexBufferBinding->setBinding(0, add_vertex_buffer_);
     add_render_op_.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
     add_render_op_.useIndexes = false;
-    subtract_max_vertex_count_ = 256 * TILE_VERTEX_COUNT; // FIXME: 256?
+    subtract_max_vertex_count_ = 512 * TILE_VERTEX_COUNT;
     subtract_render_op_.vertexData = new Ogre::VertexData;
     subtract_render_op_.vertexData->vertexStart = 0;
-    vDecl = subtract_render_op_.vertexData->vertexDeclaration;
+    vertex_declaration = subtract_render_op_.vertexData->vertexDeclaration;
     offset = 0;
-    vDecl->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
+    vertex_declaration->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
     offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
-    vDecl->addElement(0, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE);
+    vertex_declaration->addElement(0, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE);
     offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT4);
-    vDecl->addElement(
-      0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES
+    vertex_declaration->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES
     );
-    subtract_vertex_buffer_
-      = Ogre::HardwareBufferManager::getSingletonPtr()->createVertexBuffer(
-        vDecl->getVertexSize(0), subtract_max_vertex_count_,
-        Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false
-      );
-    subtract_render_op_.vertexData->vertexBufferBinding->setBinding(
-      0, subtract_vertex_buffer_
+    subtract_vertex_buffer_ = Ogre::HardwareBufferManager::getSingletonPtr()->createVertexBuffer(
+      vertex_declaration->getVertexSize(0), subtract_max_vertex_count_,
+      Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false
     );
+    subtract_render_op_.vertexData->vertexBufferBinding->setBinding(0, subtract_vertex_buffer_);
     subtract_render_op_.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
     subtract_render_op_.useIndexes = false;
 }
@@ -868,17 +751,13 @@ void Background2D::load(const QGears::Background2DFile::TileList& tiles){
     }
 }
 
-void Background2D::load(
-  const size_t tile_index, const QGears::AnimationMap& animations
-){
+void Background2D::load(const size_t tile_index, const QGears::AnimationMap& animations){
     QGears::AnimationMap::const_iterator it(animations.begin());
     QGears::AnimationMap::const_iterator it_end(animations.end());
     while(it != it_end){
         const QGears::String& name(it->first);
         const QGears::Animation& animation(it->second);
-        Background2DAnimation* anim(
-          new Background2DAnimation(name, this, tile_index)
-        );
+        Background2DAnimation* anim(new Background2DAnimation(name, this, tile_index));
         anim->SetLength(animation.length);
         QGears::KeyFrameList::const_iterator itk(animation.key_frames.begin());
         QGears::KeyFrameList::const_iterator itk_end(animation.key_frames.end());

+ 44 - 20
V-Gears/src/core/Entity.cpp

@@ -26,7 +26,8 @@ Entity::Entity(const Ogre::String& name, Ogre::SceneNode* node):
   name_(name),
   scene_node_(node),
   height_(1.0f),
-  solid_radius_(0.24f),
+  //solid_radius_(0.24f),
+  solid_radius_(0.21f),
   solid_(true),
   talk_radius_(0.45f),
   talkable_(true),
@@ -45,10 +46,12 @@ Entity::Entity(const Ogre::String& name, Ogre::SceneNode* node):
   linear_movement_(LM_UP_TO_DOWN),
   linear_start_(0.0f, 0.0f, 0.0f),
   linear_end_(0.0f, 0.0f, 0.0f),
+  linear_dest_triangle_(-1),
   jump_start_(0.0f, 0.0f, 0.0f),
   jump_end_(0.0f, 0.0f, 0.0f),
   jump_seconds_(0.0f),
   jump_current_seconds_(0.0f),
+  jump_dest_triangle_(-1),
   offset_position_start_(0.0f, 0.0f, 0.0f),
   offset_position_end_(0.0f, 0.0f, 0.0f),
   offset_type_(AT_NONE),
@@ -67,7 +70,8 @@ Entity::Entity(const Ogre::String& name, Ogre::SceneNode* node):
   animation_auto_play_(true),
   is_character_(false),
   character_id_(0),
-  character_name_("")
+  character_name_(""),
+  is_line_(false)
 {
     model_root_node_ = scene_node_->createChildSceneNode();
     model_node_ = model_root_node_->createChildSceneNode();
@@ -279,6 +283,13 @@ void Entity::setScale(const Ogre::Vector3 &scale) {
     model_root_node_->setScale(scale);
 }
 
+void Entity::SetIndex(const int index){
+    assert(model_root_node_);
+    index_ = index;
+}
+
+int Entity::GetIndex(){return index_;}
+
 void Entity::setRootOrientation(const Ogre::Quaternion &root_orientation){
     assert(model_node_);
     model_node_->setOrientation(root_orientation);
@@ -401,11 +412,11 @@ void Entity::UnsetMove(){
 }
 
 void Entity::ScriptLinearToPosition(
-  const float x, const float y, const float z,
-  const LinearMovement movement, const char* animation
+  const float x, const float y, const float z, const LinearMovement movement,
+  const char* animation, const float orientation, const int dest_triangle
 ){
     Ogre::Vector3 pos = Ogre::Vector3(x, y, z);
-    SetLinear(pos, movement, animation);
+    SetLinear(pos, movement, animation, orientation, dest_triangle);
     LOG_TRIVIAL(
       "[SCRIPT] Entity \"" + name_ + "\" set linear move to position \""
       + Ogre::StringConverter::toString(pos) + "\" with animation \""
@@ -425,30 +436,29 @@ int Entity::ScriptLinearSync(){
 
 void Entity::SetLinear(
   const Ogre::Vector3& end, const LinearMovement movement,
-  const Ogre::String& animation
+  const Ogre::String& animation, const float orientation, const int dest_triangle
 ){
+    SetRotation(Ogre::Angle(orientation));
     state_ = Entity::LINEAR;
     linear_movement_ = movement;
     linear_start_ = GetPosition();
     linear_end_ = end;
+    linear_dest_triangle_ = dest_triangle;
 
-    // Linear animation
+    // Linear animation.
     animation_auto_play_ = false;
-    PlayAnimation(
-      animation, Entity::AUTO_ANIMATION, Entity::PLAY_LOOPED, 0, -1
-    );
+    PlayAnimation(animation, Entity::AUTO_ANIMATION, Entity::PLAY_LOOPED, 0, -1);
 
-    // After moving the entity needs to be reattached to the walkmesh.
+    // While moving, the entity is not in a triangle.
     move_triangle_id_ = -1;
 }
 
 void Entity::UnsetLinear(){
-    state_ = Entity::NONE;
+    state_ = Entity::NEEDS_TO_REATTACH;
+    move_triangle_id_ = linear_dest_triangle_; // Set for NPCs. Playable can end up in two places.
     animation_auto_play_ = true;
-    PlayAnimation(
-      animation_default_, Entity::AUTO_ANIMATION, Entity::PLAY_LOOPED, 0, -1
-    );
-    for (size_t i = 0; i < sync_.size(); ++i)
+    PlayAnimation(animation_default_, Entity::AUTO_ANIMATION, Entity::PLAY_LOOPED, 0, -1);
+    for (size_t i = 0; i < sync_.size(); ++ i)
         ScriptManager::getSingleton().ContinueScriptExecution(sync_[i]);
     sync_.clear();
 }
@@ -459,11 +469,16 @@ const Ogre::Vector3& Entity::GetLinearStart() const{return linear_start_;}
 
 const Ogre::Vector3& Entity::GetLinearEnd() const{return linear_end_;}
 
+const int Entity::GetLinearDestTriangle() const{return linear_dest_triangle_;}
+
 void Entity::ScriptJumpToPosition(
-  const float x, const float y, const float z, const float seconds
+  const float x, const float y, const float z, const float seconds, const int dest_triangle
 ){
-    Ogre::Vector3 jump_to(x, y, z);
-    SetJump(jump_to, seconds);
+    float new_z = z;
+    // If z not specified (-1), asume same Z.
+    if (z < 0) new_z = GetPosition().z;
+    Ogre::Vector3 jump_to(x, y, new_z);
+    SetJump(jump_to, seconds, dest_triangle);
     LOG_TRIVIAL(
       "[SCRIPT] Entity \"" + name_ + "\" set jump to position \""
       + Ogre::StringConverter::toString(jump_to) + "\" in "
@@ -481,17 +496,22 @@ int Entity::ScriptJumpSync(){
     return -1;
 }
 
-void Entity::SetJump(const Ogre::Vector3& jump_to, const float seconds){
+void Entity::SetJump(const Ogre::Vector3& jump_to, const float seconds, const int dest_triangle){
     state_ = Entity::JUMP;
     jump_start_ = GetPosition();
     jump_end_ = jump_to;
     jump_seconds_ = seconds;
     jump_current_seconds_ = 0;
+    jump_was_solid_ = IsSolid();
+    jump_dest_triangle_ = dest_triangle;
+    SetSolid(false);
     // After moving the entity needs to be reattached to the walkmesh.
     move_triangle_id_ = -1;
 }
 
 void Entity::UnsetJump(){
+    SetSolid(jump_was_solid_);
+    move_triangle_id_ = linear_dest_triangle_;
     state_ = Entity::NONE;
     for (size_t i = 0; i < sync_.size(); ++ i)
         ScriptManager::getSingleton().ContinueScriptExecution(sync_[i]);
@@ -510,6 +530,8 @@ void Entity::SetJumpCurrentSeconds(const float seconds){
 
 float Entity::GetJumpCurrentSeconds() const{ return jump_current_seconds_;}
 
+const int Entity::GetJumpDestTriangle() const{return jump_dest_triangle_;}
+
 void Entity::ScriptOffsetToPosition(
   const float x, const float y, const float z,
   const ActionType type, const float seconds
@@ -752,6 +774,8 @@ uint Entity::GetCharacterId(){return character_id_;}
 
 std::string Entity::GetCharacterName(){return character_name_;}
 
+bool Entity::IsLine(){return is_line_;}
+
 Ogre::Degree Entity::GetDirectionToEntity(Entity* entity) const{
     Ogre::Vector3 current_point = GetPosition();
     Ogre::Vector3 direction_point = entity->GetPosition();

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 202 - 397
V-Gears/src/core/EntityManager.cpp


+ 2 - 1
V-Gears/src/core/XmlMapFile.cpp

@@ -98,8 +98,9 @@ void XmlMapFile::LoadMap(){
             Ogre::Quaternion orientation(
               GetQuaternion(node, "root_orientation")
             );
+            int index(GetInt(node, "index"));
             EntityManager::getSingleton().AddEntity(
-              name, file_name, position, direction, scale, orientation
+              name, file_name, position, direction, scale, orientation, index
             );
         }
         else if (

+ 13 - 24
lib/SUDM/decompiler/ff7_field/ff7_field_disassembler.cpp

@@ -107,21 +107,6 @@ std::unique_ptr<Function> FF7::FF7Disassembler::StartFunction(size_t scriptIndex
     return func;
 }
 
-std::unique_ptr<Function> FF7::FF7Disassembler::StartLineFunction(size_t script_index){
-    auto func = std::make_unique<Function>();
-    func->_retVal = false;
-    func->_args = 0;
-    switch (script_index){
-        case 0: func->_name = "on_enter_line"; break;
-        case 1: func->_name = "on_move_to_line"; break;
-        case 4: func->_name = "on_cross_line"; break;
-        case 5: func->_name = "on_leave_line"; break;
-        default: func->_name = "script_" + std::to_string(script_index);
-    }
-    func->mStartAddr = _address;
-    return func;
-}
-
 struct ScriptInfo
 {
     uint16 mEntryPoint;
@@ -203,11 +188,9 @@ void FF7::FF7Disassembler::AddFunc(
 
     // Read each block of opcodes up to a return.
     const size_t old_num_instructions = _insts.size();
-    std::unique_ptr<Function> func;
 
     // Initialize the function.
-    if (mEngine->EntityIsLine(entity_index)) func = StartLineFunction(script_index);
-    else func = StartFunction(script_index);
+    std::unique_ptr<Function> func = StartFunction(script_index);
 
     // Read.
     if (to_return_only){
@@ -242,16 +225,22 @@ void FF7::FF7Disassembler::AddFunc(
 
     if (!func_name.empty()) func->_name = func_name;
 
-    // TODO: Remove and test. Should be applied in StartLineFunction
-    // TODO: I dont know which one is OK. Check.
     if (mEngine->EntityIsLine(entity_index)){
         switch (script_index){
-            case 1:
-            case 2:
-                func->_name = "on_enter_line"; break;
+            // main   - on_update
+            case 0: break;
+            // [OK]   - on_interact
+            case 1: break;
+            // Move - on_enter_line
+            case 2: func->_name = "on_enter_line"; break;
+            // Move - on_move_to_line
             case 3: func->_name = "on_move_to_line"; break;
+            // Go - on_cross_line
             case 4: func->_name = "on_cross_line"; break;
-            case 5: func->_name = "on_leave_line"; break;
+            // Go1x - on_cross_line
+            case 5: func->_name = "on_cross_line_once"; break;
+            // GoAway - on_leave_line
+            case 6: func->_name = "on_leave_line"; break;
         }
     }
 

+ 1 - 11
lib/SUDM/decompiler/ff7_field/ff7_field_disassembler.h

@@ -366,22 +366,12 @@ namespace FF7
         );
 
         /**
-         * Initializes a function for a non-line entity.
+         * Initializes a function for an entity.
          *
          * @param script_index[in] Index of the script.
          */
         std::unique_ptr<Function> StartFunction(size_t scriptIndex);
 
-        /**
-         * Initializes a function for a line entity.
-         *
-         * The name is set according to the script index, using line standard
-         * names.
-         *
-         * @param script_index[in] Index of the script.
-         */
-        std::unique_ptr<Function> StartLineFunction(size_t script_index);
-
         FF7FieldEngine* mEngine;
 
         uint32 mHeaderEndPos = 0;

+ 162 - 35
lib/SUDM/decompiler/ff7_field/ff7_field_engine.cpp

@@ -92,6 +92,33 @@ std::map<std::string, int> FF7::FF7FieldEngine::GetEntities() const{
     return r;
 }
 
+std::vector<SUDM::FF7::Field::FieldEntity> FF7::FF7FieldEngine::GetEntityList() const{
+    std::vector<SUDM::FF7::Field::FieldEntity> entities;
+    for (auto entity: mEntityIndexMap){
+        if (entity.second.IsLine() == false){
+            SUDM::FF7::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;
+                FF7::FunctionMetaData meta(func._metadata);
+                if (meta.EntityName() == ent.name){
+                    ent.char_id = meta.CharacterId();
+                    break;
+                }
+            }
+            entities.push_back(ent);
+        }
+    }
+    return entities;
+}
+
 std::vector<SUDM::FF7::Field::Line> FF7::FF7FieldEngine::GetLineList() const{
     std::vector<SUDM::FF7::Field::Line> lines;
     for (auto entity: mEntityIndexMap){
@@ -113,7 +140,7 @@ void FF7::FF7FieldEngine::AddEntityFunction(
     auto it = mEntityIndexMap.find(entity_index);
     if (it != std::end(mEntityIndexMap)) (*it).second.AddFunction(func_name, func_index);
     else{
-        Entity e(entity_name);
+        Entity e(entity_name, entity_index);
         e.AddFunction(func_name, func_index);
         mEntityIndexMap.insert(std::make_pair(entity_index, e));
     }
@@ -767,7 +794,7 @@ void FF7::FF7MathInstruction::processBITON(CodeGenerator* code_gen){
 }
 
 void FF7::FF7MathInstruction::processBITOFF(CodeGenerator* code_gen){
-    code_gen->addOutputLine((boost::format("bit_on(%1%, %2%, %3%)")
+    code_gen->addOutputLine((boost::format("bit_off(%1%, %2%, %3%)")
       % _params[0]->getUnsigned() % _params[2]->getUnsigned() % _params[3]->getUnsigned()
     ).str());
 }
@@ -1042,9 +1069,9 @@ void FF7::FF7ModelInstruction::processInst(
         case eOpcodes::CANM_2: processCANM_2(code_gen, md.EntityName(), md.CharacterId()); break;
         case eOpcodes::ASPED: WriteTodo(code_gen, md.EntityName(), "ASPED"); break;
         case eOpcodes::CC: processCC(code_gen, eng); break;
-        case eOpcodes::JUMP: WriteTodo(code_gen, md.EntityName(), "JUMP"); break;
-        case eOpcodes::AXYZI: WriteTodo(code_gen, md.EntityName(), "AXYZI"); break;
-        case eOpcodes::LADER: WriteTodo(code_gen, md.EntityName(), "LADER"); break;
+        case eOpcodes::JUMP: processJUMP(code_gen, md.EntityName()); break;
+        case eOpcodes::AXYZI: processAXYZI(code_gen); break;
+        case eOpcodes::LADER: processLADER(code_gen, md.EntityName()); break;
         case eOpcodes::OFST: processOFST(code_gen, md.EntityName()); break;
         case eOpcodes::OFSTW:
             code_gen->addOutputLine("self." + md.EntityName() + ":offset_sync()");
@@ -1070,22 +1097,37 @@ void FF7::FF7ModelInstruction::processJOIN(CodeGenerator* code_gen){
 }
 
 void FF7::FF7ModelInstruction::processSPLIT(CodeGenerator* code_gen){
-    code_gen->addOutputLine(
-      "split_party("
-      + std::to_string(_params[0]->getUnsigned()) + ", " // ax_addr
-      + std::to_string(_params[1]->getUnsigned()) + ", " // ay_addr
-      + std::to_string(_params[2]->getUnsigned()) + ", " // ar_addr
-      + std::to_string(_params[3]->getUnsigned()) + ", " // bx_addr
-      + std::to_string(_params[4]->getUnsigned()) + ", " // by_addr
-      + std::to_string(_params[5]->getUnsigned()) + ", " // br_addr
-      + std::to_string(_params[6]->getSigned()) + ", " // ax
-      + std::to_string(_params[7]->getSigned()) + ", " // ay
-      + std::to_string(_params[8]->getSigned()) + ", " // ar
-      + std::to_string(_params[9]->getSigned()) + ", " // bx
-      + std::to_string(_params[10]->getSigned()) + ", " // by
-      + std::to_string(_params[11]->getSigned()) + ", " // br
-      + std::to_string(_params[12]->getUnsigned()) + ", " // speed
-      + ")");
+    FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
+    const float scale = 128.0f * cg->ScaleFactor();
+    const auto& ax = FF7CodeGeneratorHelpers::FormatValueOrVariable(
+      cg->mFormatter, _params[0]->getUnsigned(), _params[6]->getSigned(),
+      FF7CodeGeneratorHelpers::ValueType::Float, scale
+    );
+    const auto& ay = FF7CodeGeneratorHelpers::FormatValueOrVariable(
+      cg->mFormatter, _params[1]->getUnsigned(), _params[7]->getSigned(),
+      FF7CodeGeneratorHelpers::ValueType::Float, scale
+    );
+    const auto& ar = FF7CodeGeneratorHelpers::FormatValueOrVariable(
+      cg->mFormatter, _params[2]->getUnsigned(), _params[8]->getSigned(),
+      FF7CodeGeneratorHelpers::ValueType::Float, scale
+    );
+    const auto& bx = FF7CodeGeneratorHelpers::FormatValueOrVariable(
+      cg->mFormatter, _params[3]->getUnsigned(), _params[9]->getSigned(),
+      FF7CodeGeneratorHelpers::ValueType::Float, scale
+    );
+    const auto& by = FF7CodeGeneratorHelpers::FormatValueOrVariable(
+      cg->mFormatter, _params[4]->getUnsigned(), _params[10]->getSigned(),
+      FF7CodeGeneratorHelpers::ValueType::Float, scale
+    );
+    const auto& br = FF7CodeGeneratorHelpers::FormatValueOrVariable(
+      cg->mFormatter, _params[5]->getUnsigned(), _params[11]->getSigned(),
+      FF7CodeGeneratorHelpers::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 FF7::FF7ModelInstruction::processTLKON(CodeGenerator* code_gen, const std::string& entity){
@@ -1309,6 +1351,87 @@ void FF7::FF7ModelInstruction::processCC(CodeGenerator* code_gen, const FF7Field
     );
 }
 
+void FF7::FF7ModelInstruction::processJUMP(CodeGenerator* code_gen, const std::string& entity){
+    FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
+    const float scale = 128.0f * cg->ScaleFactor();
+    float x = std::stof(FF7CodeGeneratorHelpers::FormatValueOrVariable(
+      cg->mFormatter, _params[0]->getUnsigned(), _params[4]->getSigned(),
+      FF7CodeGeneratorHelpers::ValueType::Float, scale
+    ));
+    float y = std::stof(FF7CodeGeneratorHelpers::FormatValueOrVariable(
+      cg->mFormatter, _params[1]->getUnsigned(), _params[5]->getSigned(),
+      FF7CodeGeneratorHelpers::ValueType::Float, scale
+    ));
+    int i = atoi(FF7CodeGeneratorHelpers::FormatValueOrVariable(
+      cg->mFormatter, _params[2]->getUnsigned(), _params[6]->getSigned()
+    ).c_str());
+    int steps = atoi(FF7CodeGeneratorHelpers::FormatValueOrVariable(
+      cg->mFormatter, _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 FF7::FF7ModelInstruction::processAXYZI(CodeGenerator* code_gen){
+    FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
+    const float scale = 128.0f * cg->ScaleFactor();
+    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 FF7::FF7ModelInstruction::processLADER(CodeGenerator* code_gen, const std::string& entity){
+    FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
+    const float scale = 128.0f * cg->ScaleFactor();
+    const auto& x = FF7CodeGeneratorHelpers::FormatValueOrVariable(
+      cg->mFormatter, _params[0]->getUnsigned(), _params[4]->getSigned(),
+      FF7CodeGeneratorHelpers::ValueType::Float, scale
+    );
+    const auto& y = FF7CodeGeneratorHelpers::FormatValueOrVariable(
+      cg->mFormatter, _params[1]->getUnsigned(), _params[5]->getSigned(),
+      FF7CodeGeneratorHelpers::ValueType::Float, scale
+    );
+    const auto& z = FF7CodeGeneratorHelpers::FormatValueOrVariable(
+      cg->mFormatter, _params[2]->getUnsigned(), _params[6]->getSigned(),
+      FF7CodeGeneratorHelpers::ValueType::Float, scale
+    );
+    uint end_triangle = atoi(FF7CodeGeneratorHelpers::FormatValueOrVariable(
+      cg->mFormatter, _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 = FF7CodeGeneratorHelpers::FormatValueOrVariable(
+      cg->mFormatter, 0, _params[10]->getSigned(),
+      FF7CodeGeneratorHelpers::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 FF7::FF7ModelInstruction::processSOLID(CodeGenerator* code_gen, const std::string& entity){
     code_gen->addOutputLine((
       boost::format("self.%1%:set_solid(%2%)")
@@ -1318,23 +1441,27 @@ void FF7::FF7ModelInstruction::processSOLID(CodeGenerator* code_gen, const std::
 
 void FF7::FF7ModelInstruction::processOFST(CodeGenerator* code_gen, const std::string& entity){
     FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
-    float x = atoi(FF7CodeGeneratorHelpers::FormatValueOrVariable(
-      cg->mFormatter, _params[0]->getUnsigned(), _params[5]->getSigned()
-    ).c_str());
-    float y = atoi(FF7CodeGeneratorHelpers::FormatValueOrVariable(
-      cg->mFormatter, _params[1]->getUnsigned(),_params[6]->getSigned()
-    ).c_str());
-    float z = atoi(FF7CodeGeneratorHelpers::FormatValueOrVariable(
-      cg->mFormatter, _params[2]->getUnsigned(), _params[7]->getSigned()
-    ).c_str());
-    float speed = atoi(FF7CodeGeneratorHelpers::FormatValueOrVariable(
+    const float scale = 128.0f * cg->ScaleFactor();
+    float x = std::stof(FF7CodeGeneratorHelpers::FormatValueOrVariable(
+      cg->mFormatter, _params[0]->getUnsigned(), _params[5]->getSigned(),
+      FF7CodeGeneratorHelpers::ValueType::Float, scale
+    ));
+    float y = std::stof(FF7CodeGeneratorHelpers::FormatValueOrVariable(
+      cg->mFormatter, _params[1]->getUnsigned(),_params[6]->getSigned(),
+      FF7CodeGeneratorHelpers::ValueType::Float, scale
+    ));
+    float z = std::stof(FF7CodeGeneratorHelpers::FormatValueOrVariable(
+      cg->mFormatter, _params[2]->getUnsigned(), _params[7]->getSigned(),
+      FF7CodeGeneratorHelpers::ValueType::Float, scale
+    ));
+    float speed = std::stof(FF7CodeGeneratorHelpers::FormatValueOrVariable(
       cg->mFormatter, _params[3]->getUnsigned(), _params[8]->getUnsigned()
-    ).c_str());
+    ));
     // 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;
+    //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((

+ 197 - 14
lib/SUDM/decompiler/ff7_field/ff7_field_engine.h

@@ -77,15 +77,27 @@ namespace FF7{
                      *
                      * @param name[in] Entity name.
                      */
-                    Entity(const std::string& name): mName(name), is_line_(false){}
+                    Entity(const std::string& name, size_t index):
+                      mName(name), index_(index), is_line_(false)
+                    {}
 
                     /**
                      * Retrieves the entity name.
                      *
-                     * @return 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.
                      *
@@ -114,17 +126,7 @@ namespace FF7{
                      * @todo What is a function here? An Opcode?
                      */
                     void AddFunction(const std::string& name, size_t index){
-                        // TODO: Delete renaming and test. It should work.
-                        std::string new_name = name;
-                        if (is_line_){
-                            switch (index){
-                                case 2: new_name = "on_enter_line"; break;
-                                case 3: new_name = "on_move_to_line"; break;
-                                case 4: new_name = "on_cross_line"; break;
-                                case 5: new_name = "on_leave_line"; break;
-                            }
-                        }
-                        mFunctions[index] = new_name;
+                        mFunctions[index] = name;
                     }
 
                     /**
@@ -200,6 +202,11 @@ namespace FF7{
                      */
                     std::string mName;
 
+                    /**
+                     * Entity index.
+                     */
+                    size_t index_;
+
                     /**
                      * Function list.
                      * @todo What is a function here? An Opcode?
@@ -284,6 +291,13 @@ namespace FF7{
              */
             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::FF7::Field::FieldEntity> GetEntityList() const;
+
             /**
              * Retrieves all line entities in the map.
              *
@@ -1107,6 +1121,175 @@ namespace FF7{
             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);
 
             /**
@@ -1161,7 +1344,7 @@ namespace FF7{
              * Script execution may also be halted until the gradual offset
              * has been completed. For this, see OFSTW.
              *
-             * @param codegen The code generator.
+             * @param codegen[in] The code generator.
              * @param entity[in] The entity name.
              */
             void processOFST(CodeGenerator* codegen, const std::string& entity);

+ 45 - 73
lib/SUDM/decompiler/sudm.cpp

@@ -1,107 +1,79 @@
+/*
+ * Copyright (C) 2022 The V-Gears Team
+ *
+ * This file is part of V-Gears
+ *
+ * V-Gears is free software: you can redistribute it and/or modify it under
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3.0 (GPLv3) of the License.
+ *
+ * V-Gears 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.
+ */
+
 #include "sudm.h"
 #include "decompiler/ff7_field/ff7_field_engine.h"
 #include "decompiler/ff7_field/ff7_field_disassembler.h"
 #include "decompiler/ff7_field/ff7_field_codegen.h"
 #include "decompiler/control_flow.h"
 
-namespace SUDM
-{
-    namespace FF7
-    {
-        namespace Animation
-        {
-            // TODO
-        }
+namespace SUDM{
+    namespace FF7{
+        namespace Animation{} // TODO
 
-        namespace AI
-        {
-            // TODO
-        }
+        namespace AI{} // TODO
 
-        namespace World
-        {
-            // TODO
-        }
+        namespace World{} // TODO
+
+        namespace Field{
 
-        namespace Field
-        {
-            float ScaleFactor(const std::vector<unsigned char>& scriptBytes)
-            {
-                // Could be cleaner, but just does enough work to pull out the fields scale
+            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;
                 ::FF7::FF7FieldEngine engine(formatter, "Unused");
                 InstVec insts;
-                engine.getDisassembler(insts, scriptBytes);
+                engine.getDisassembler(insts, script_bytes);
                 return engine.ScaleFactor();
             }
 
-            DecompiledScript Decompile(std::string scriptName,
-                                  const std::vector<unsigned char>& scriptBytes,
-                                  IScriptFormatter& formatter, 
-                                  std::string textToAppend,
-                                  std::string textToPrepend)
-            {
-                // Disassemble the script
-                ::FF7::FF7FieldEngine engine(formatter, scriptName);
+            DecompiledScript Decompile(
+              std::string script_name, const std::vector<unsigned char>& script_bytes,
+              IScriptFormatter& formatter, std::string text_after, std::string text_before
+            ){
+                // Disassemble the script.
+                ::FF7::FF7FieldEngine engine(formatter, script_name);
                 InstVec insts;
-
-                auto disassembler = engine.getDisassembler(insts, scriptBytes);
+                auto disassembler = engine.getDisassembler(insts, script_bytes);
                 disassembler->disassemble();
-
-                //disassembler->dumpDisassembly(std::cout);
-
-                // Check if the script contains the opcode LINE.
-                /*bool is_line = false;
-                for(InstPtr inst : insts){
-                    if ("LINE" == inst->_name){
-                        std::cout << " INSTRUCTION: " << inst->_name << " (" << scriptName << ")" << std::endl;
-                        disassembler->dumpDisassembly(std::cout);
-                        std::cout << " INSTRUCTION END" << std::endl;
-                        is_line = true;
-                        break;
-                    }
-                }*/
-
-                // Create CFG
-                auto controlFlow = std::make_unique<ControlFlow>(insts, engine);
-                controlFlow->createGroups();
-
+                // 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);
                 Graph graph;
-
                 DecompiledScript ds;
-
-                // Generate code and return it
+                // Generate code and return it.
                 std::stringstream output;
                 auto cg = engine.getCodeGenerator(insts, output);
                 cg->generate(insts, graph);
-                ds.luaScript = textToPrepend + output.str() + textToAppend;
-                ds.entities = engine.GetEntities();
-                for (auto line : engine.GetLineList()){
-                    ds.lines.push_back(line);
-                }
-
-                ds.lines = engine.GetLineList();
+                ds.luaScript = text_before + output.str() + text_after;
+                for (auto entity : engine.GetEntityList()) ds.entities.push_back(entity);
+                for (auto line : engine.GetLineList()) ds.lines.push_back(line);
                 return ds;
             }
         }
     }
 
-    namespace FF8
-    {
-        namespace Field
-        {
-            // TODO
-        }
+    namespace FF8{
+
+        namespace Field{} // TODO
     }
 
-    namespace FF9
-    {
-        namespace Field
-        {
-            // TODO
-        }
+    namespace FF9{
+
+        namespace Field{} // TODO
     }
 }

+ 219 - 64
lib/SUDM/decompiler/sudm.h

@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2022 The V-Gears Team
+ *
+ * This file is part of V-Gears
+ *
+ * V-Gears is free software: you can redistribute it and/or modify it under
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3.0 (GPLv3) of the License.
+ *
+ * V-Gears 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.
+ */
+
 #pragma once
 
 #include <map>
@@ -5,84 +20,224 @@
 #include <string>
 #include "unknown_opcode_exception.h"
 
-namespace SUDM
-{
-    class IScriptFormatter
-    {
-    public:
-        virtual ~IScriptFormatter() = default;
-
-        virtual void AddSpawnPoint(unsigned int /*targetMapId*/, const std::string& /*entity*/, const std::string& /*funcName*/, unsigned int /*address*/, int /*x*/, int /*y*/, int /*triangleId*/, int /*angle*/)
-        {
-
-        }
-
-        virtual std::string SpawnPointName(unsigned int targetMapId, const std::string& entity, const std::string& funcName, unsigned int address)
-        {
-            return MapName(targetMapId) + "_" + entity + "_" + funcName + "_" + std::to_string(address);
-        }
-
-        virtual std::string MapName(unsigned int mapId) { return std::to_string(mapId); }
-
-        // Renames a variable, return empty string for generated name, can return empty
-        virtual std::string VarName(unsigned int /*bank*/, unsigned int /*addr*/) { return ""; }
+namespace SUDM{
+
+    class IScriptFormatter{
+
+        public:
+
+            virtual ~IScriptFormatter() = default;
+
+            /**
+             * Adds an spawn point.
+             *
+             * If the spawn is new, a new record will be added to the spawn
+             * point database. If it was already there, update the record to
+             * add the origin.
+             *
+             * @param map_id[in] The target map ID.
+             * @param entity[in] The entity that acts as the spawn point.
+             * @param function_name[in] The spawn function name.
+             * @param address[in] @todo Understand and document.
+             * @param x[in] X coordinate of the field at which to spawn.
+             * @param y[in] Y coordinate of the field at which to spawn.
+             * @param z[in] Z coordinate of the field at which to spawn.
+             * @param angle[in] Orientation at which to spawn.
+             */
+            virtual void AddSpawnPoint(
+              unsigned int map_id, const std::string& entity, const std::string& function_name,
+              unsigned int address, int x, int y, int triangle_id, int angle
+            ){}
+
+            /**
+             * Retrieves the name of a spawn point.
+             *
+             * @param map_id[in] The target map ID.
+             * @param entity[in] The entity that acts as the spawn point.
+             * @param function_name[in] The spawn function name.
+             * @param address[in] @todo Understand and document.
+             * @return The name of the spawn point.
+             */
+            virtual std::string SpawnPointName(
+              unsigned int map_id, const std::string& entity,
+              const std::string& function_name, unsigned int address
+            ){
+                return MapName(map_id)
+                  + "_" + entity + "_" + function_name + "_" + std::to_string(address);
+            }
+
+            /**
+             * Retrieves the name of a map.
+             *
+             * The name of a map is usually it's ID.
+             *
+             * @param map_id[in] The map ID.
+             * @return The map name.
+             */
+            virtual std::string MapName(unsigned int map_id) { return std::to_string(map_id);}
+
+            /**
+             * Retrieves a friendly name for a variable.
+             *
+             * @param bank[in] Variable memory bank.
+             * @param address[in] Variable memory address.
+             * @return Friendly name assigned to the variable, or an empty
+             * string if there is none.
+             */
+            virtual std::string VarName(unsigned int bank, unsigned int addr){return "";}
+
+            /**
+             * Retrieves a friendly name for an entity.
+             *
+             * @param entity_name[in] Name of the entity.
+             * @return Friendly name assigned to the entity, or <entity_name>
+             * if there is none.
+             */
+            virtual std::string EntityName(const std::string& entity_name){return entity_name;}
+
+            /**
+             * Retrieves a friendly name for an animation.
+             *
+             * @param animation_id[in] ID of the animation.
+             * @return Friendly name assigned to the animation. If there is
+             * no one, the ID in string format.
+             */
+            virtual std::string AnimationName(int animation_id, int id){
+                return std::to_string(animation_id);
+            }
+
+            /**
+             * Retrieves a friendly name for a character.
+             *
+             * @param char_id[in] ID of the character.
+             * @return Friendly name assigned to the character. If there is
+             * no one, the ID in string format.
+             */
+            virtual std::string CharName(int char_id){return std::to_string(char_id);}
+
+            /**
+             * Retrieves a friendly name for a function.
+             *
+             * @param entity_name[in] Name of the entity.
+             * @param function_name[in] Name of the function.
+             * @return Friendly name assigned to the entity, or
+             * <function_name> if there is none.
+             */
+            virtual std::string FunctionName(
+              const std::string& entity_name, const std::string& function_name
+            ){return function_name;}
+
+            /**
+             * Retrieves the header comment for a function in an entity.
+             *
+             * @param entity_name[in] Name of the entity.
+             * @param function_name[in] Name of the function.
+             * @return The function comment. An empty string if the entity or
+             * the function don't exist.
+             */
+            virtual std::string FunctionComment(
+              const std::string& entity_name, const std::string& function_name
+            ){return "";}
+        };
+
+    namespace FF7{
+
+        namespace Field{
+
+            /**
+             * A line.
+             */
+            struct Line{
 
-        // Renames an entity, can't return empty
-        virtual std::string EntityName(const std::string& entity) { return entity; }
+                /**
+                 * Name of the line entity.
+                 */
+                std::string name;
 
-        // Names an animation, can't return empty
-        virtual std::string AnimationName(int /*charId*/, int id)  { return std::to_string(id); }
+                /**
+                 * First point of the line.
+                 */
+                std::vector<float> point_a;
 
-        // Get name of char from its id, can't return empty
-        virtual std::string CharName(int charId) { return std::to_string(charId);  }
+                /**
+                 * Second point of the line.
+                 */
+                std::vector<float> point_b;
+            };
 
-        // Renames a function in an entity, can't return empty
-        virtual std::string FunctionName(const std::string& /*entity*/, const std::string& funcName) { return funcName; }
+            /**
+             * An entity.
+             */
+            struct FieldEntity{
 
-        // Sets the header comment for a function in an entity, can return empty
-        virtual std::string FunctionComment(const std::string& /*entity*/, const std::string& /*funcName*/)  { return ""; }
-    };
+                /**
+                 * Character identifier of the entity.
+                 */
+                uint char_id;
 
-    namespace FF7
-    {
-        namespace Field
-        {
-            // Entities list, with entity type of
-            // entity_script
-            // entity_model, which somehow links to model loader
+                /**
+                 * Index of the entity in the field.
+                 */
+                uint index;
 
-            struct Line{
+                /**
+                 * Name of the entity.
+                 */
                 std::string name;
-                std::vector<float> point_a;
-                std::vector<float> point_b;
-                float ax, ay, az;
-                float bx, by, bz;
             };
 
-            struct DecompiledScript
-            {
+            /**
+             * The field decompiled script.
+             */
+            struct DecompiledScript{
+
+                /**
+                 * The LUA script for the field.
+                 */
                 std::string luaScript;
-                std::map<std::string, int> entities;
-                //std::map<size_t, FF7FieldEngine::Entity> entity_map;
+
+                /**
+                 * The field entities.
+                 *
+                 * Lines are not included.
+                 */
+                std::vector<FieldEntity> entities;
+
+                /**
+                 * Lines in the field.
+                 */
                 std::vector<Line> lines;
             };
 
-            float ScaleFactor(const std::vector<unsigned char>& scriptBytes);
-
-            /*
-            * Throws ::InternalDecompilerError on failure.
-            * scriptName - name of the script to be converted, should match file name.
-            * scriptBytes - vector of raw byte data that makes up the script.
-            * formatter - used to rename variables, drop functions etc.
-            * textToAppend - raw text that is glued on to the end of the decompiled output.
-            * textToPrepend - raw text that is glued to to the start of the decompiled output.
-            * returns a string containing [textToPrepend] [decompiled script] [textToAppend]
-            */
-            DecompiledScript Decompile(std::string scriptName,
-                const std::vector<unsigned char>& scriptBytes,
-                IScriptFormatter& formatter,
-                std::string textToAppend = "",
-                std::string textToPrepend = "");
+            /**
+             * Retrieves the scale factor of a field.
+             *
+             * @param script_bytes[in] Vector of raw byte data that makes up
+             * the script.
+             * @return The scale fctor.
+             */
+            float ScaleFactor(const std::vector<unsigned char>& script_bytes);
+
+            /**
+             * Decompiles a field script.
+             *
+             * @param script_name[in] Name of the script to be converted,
+             * should match file name.
+             * @param script_bytes[in] Vector of raw byte data that makes up
+             * the script.
+             * @param formatter[in] Formatter used to rename variables, drop
+             * functions...
+             * @param text_after[in] Raw text that is added at to the end of
+             * the decompiled output.
+             * @param text_before[in] Raw text that is added at to the start of
+             * the decompiled output.
+             * @return A string with the decompiled script.
+             * @throws InternalDecompilerError on failure.
+             */
+            DecompiledScript Decompile(
+              std::string script_name, const std::vector<unsigned char>& script_bytes,
+              IScriptFormatter& formatter, std::string text_after = "", std::string text_before = ""
+            );
         }
     }
 }

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

@@ -106,7 +106,7 @@ FFVII.Battle.init = function()
 
     -- load players
     EntityContainer.Cloud = FFVII.Characters.Cloud
-    entity_manager:add_entity( "Cloud", "models/ffvii/battle/units/first_ray.mesh", 0, 2, 0, 0 )
+    entity_manager:add_entity( "Cloud", "models/ffvii/battle/units/first_ray.mesh", 0, 2, 0, 0 -1)
 
 
 

+ 30 - 1
output/data/scripts/ffvii/field.lua

@@ -72,7 +72,7 @@ end
  @param br Direction the third character faces after the split, or address for the value if br_addr is non-zero.
  @param speed Speed at which the characters split.
 ]]
-split_party = function(ax_addr, ay_addr, ar_addr, bx_addr, by_addr, br_addr, ax, ay, ar, bx, by, br, speed)
+split_party = function(ax, ay, ar, bx, by, br, speed)
     local player = entity_manager:get_player_entity()
     local x, y, z = player:get_position()
     for c = 2, 3 do
@@ -155,6 +155,35 @@ KeyOn = function(key_code)
     return true;
 end
 
+--[[
+ Stores the coordinates and walkmesh triangle in memory.
+ Stores the values as in the original game, without scaling.
+ @param bx Bank at which to store the X coordinate.
+ @param by Bank at which to store the Y coordinate.
+ @param bz Bank at which to store the Z coordinate.
+ @param bt Bank at which to store the triangle.
+ @param id The entity ID.
+ @param ax Address at which to store the X coordinate.
+ @param ay Address at which to store the Y coordinate.
+ @param az Address at which to store the Z coordinate.
+ @param at Address at which to store the triangle.
+ @param scale Map scale to multiply values
+]]
+axyzi = function(bx, by, bz, bt, id, ax, ay, az, at, scale)
+    local entity = entity_manager:get_entity_from_index(id)
+    if entity == nil then
+        do return end
+    end
+    script:wait(0.666667)
+    local x, y, z = entity:get_position()
+    local t = entity:get_move_triangle_id()
+    FFVII.Banks[bx + 1][ax + 1] = math.floor(x * scale)
+    FFVII.Banks[by + 1][ay + 1] = math.floor(y * scale)
+    FFVII.Banks[bz + 1][az + 1] = math.floor(z * scale)
+    FFVII.Banks[bt + 1][at + 1] = t
+    return 0
+end
+
 System[ "MapChanger" ] = {
     map_name = "",
     point_name = "",

+ 1 - 0
output/field_models_and_animation_metadata.xml

@@ -235,6 +235,7 @@
 		<animation name="acfe" target="Idle"></animation>
 		<animation name="aaff" target="Walk"></animation>
 		<animation name="aaga" target="Run"></animation>
+		<animation name="bygc" target="Climb"></animation>
 		<animation name="bvjf" target="JumpFromTrain"></animation>
 		<animation name="bxbb" target="JumpFromTrain"></animation>
 		<animation name="bxbc" target="Throw"></animation>

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác