Browse Source

Added correct entity_points - must pull them from the linking fields

Paul 11 years ago
parent
commit
f151491926

+ 1 - 1
QGearsMain/include/data/QGearsTriggersFile.h

@@ -59,7 +59,7 @@ namespace QGears
         {
             std::array<Vertex_s, 2> exit_line;
             Vertex_s destination;
-            u16 fieldID;
+            u16 destinationFieldId;
             u8 dir, dir_copy1, dir_copy2, dir_copy3;
         };
 

+ 1 - 1
QGearsMain/src/data/QGearsTriggersFile.cpp

@@ -108,7 +108,7 @@ namespace QGears
             ReadVertex_s(stream, exit.exit_line[i]);
         }
         ReadVertex_s(stream, exit.destination);
-        readShort(stream, exit.fieldID);
+        readShort(stream, exit.destinationFieldId);
         readUInt8(stream, exit.dir);
         readUInt8(stream, exit.dir_copy1);
         readUInt8(stream, exit.dir_copy2);

+ 141 - 60
utilities/q-gears-launcher/src/ff7DataInstaller.cpp

@@ -151,7 +151,38 @@ public:
     }
 };
 
-static void FF7PcFieldToQGearsField(QGears::FLevelFilePtr& field, const std::string& outDir)
+const int kInactiveGateWayId = 32767;
+
+class SpawnPointDb
+{
+public:
+    // Id of the field the gateways records from N other number of fields are linking to
+    u16 mTargetFieldId = 0;
+
+    class Record
+    {
+    public:
+        u16 mFieldId = 0;
+        u32 GatewayIndex = 0;
+        QGears::TriggersFile::Gateway mGateway;
+    };
+    std::vector<Record> mGatewaysToThisField;
+};
+typedef std::map<u16, SpawnPointDb> FieldSpawnPointsMap;
+
+static size_t FieldId(const std::string& name, const std::vector<std::string>& fieldIdToNameLookup)
+{
+    for (size_t i = 0; i < fieldIdToNameLookup.size(); i++)
+    {
+        if (fieldIdToNameLookup[i] == name)
+        {
+            return i;
+        }
+    }
+    throw std::runtime_error("No Id found for field name");
+}
+
+static void FF7PcFieldToQGearsField(QGears::FLevelFilePtr& field, const std::string& outDir, const std::vector<std::string>& fieldIdToNameLookup, const FieldSpawnPointsMap& spawnMap)
 {
     // Save out the tiles as a PNG image
     
@@ -221,7 +252,7 @@ static void FF7PcFieldToQGearsField(QGears::FLevelFilePtr& field, const std::str
         // entity_manager:get_entity("cl") is done via CHAR opcode
 
 
-        // TODO: Get these scales from the field game data,  1024 for md1_1 and 512 for md1_2, DAT CFG has them as 2 and 1
+        // TODO: Get these scales from the field game data,  1024 for md1_1 and 512 for md1_2, DAT CFG has them as 2 and 1?
         const float downscaler_next = 128.0f; //  * MapIdToScale( map_id );
         const float downscaler_this = 128.0f; // * field.scale
 
@@ -230,54 +261,56 @@ static void FF7PcFieldToQGearsField(QGears::FLevelFilePtr& field, const std::str
         {
             const QGears::TriggersFile::Gateway& gateway = gateways[i];
             // if not inactive gateway
-            if (gateway.fieldID != 32767)
+            if (gateway.destinationFieldId != kInactiveGateWayId)
             {
-                // entity_trigger
-                {
-                    std::unique_ptr<TiXmlElement> xmlEntityTrigger(new TiXmlElement("entity_trigger"));
+                std::unique_ptr<TiXmlElement> xmlEntityTrigger(new TiXmlElement("entity_trigger"));
 
-                    xmlEntityTrigger->SetAttribute("name", "Gateway" + std::to_string(i));
+                xmlEntityTrigger->SetAttribute("name", "Gateway" + std::to_string(i));
 
-                    xmlEntityTrigger->SetAttribute("point1",
-                        Ogre::StringConverter::toString(
-                        Ogre::Vector3(gateway.exit_line[0].x, gateway.exit_line[0].y, gateway.exit_line[0].z) / downscaler_this));
+                xmlEntityTrigger->SetAttribute("point1",
+                    Ogre::StringConverter::toString(
+                    Ogre::Vector3(gateway.exit_line[0].x, gateway.exit_line[0].y, gateway.exit_line[0].z) / downscaler_this));
 
-                    xmlEntityTrigger->SetAttribute("point2",
-                        Ogre::StringConverter::toString(
-                        Ogre::Vector3(gateway.exit_line[1].x, gateway.exit_line[1].y, gateway.exit_line[1].z) / downscaler_this));
+                xmlEntityTrigger->SetAttribute("point2",
+                    Ogre::StringConverter::toString(
+                    Ogre::Vector3(gateway.exit_line[1].x, gateway.exit_line[1].y, gateway.exit_line[1].z) / downscaler_this));
 
-                    // enabled hard coded to true
-                    xmlEntityTrigger->SetAttribute("enabled", "true");
-                    element->LinkEndChild(xmlEntityTrigger.release());
-                }
+                // enabled hard coded to true
+                xmlEntityTrigger->SetAttribute("enabled", "true");
+                element->LinkEndChild(xmlEntityTrigger.release());
+            }
+        }
+
+        // Get this fields Id
+        const size_t thisFieldId = FieldId(field->getName(), fieldIdToNameLookup);
 
+        // Use that to find the pre-computed list of gateways in all other fields that link to this field
+        auto spawnIterator = spawnMap.find(thisFieldId);
+
+        // If not found that it probably just means no other fields have doors to this one
+        if (spawnIterator != std::end(spawnMap))
+        {
+            const std::vector<SpawnPointDb::Record>& spawnPointRecords = spawnIterator->second.mGatewaysToThisField;
+
+            for (size_t i = 0; i < spawnPointRecords.size(); i++)
+            {
+                const QGears::TriggersFile::Gateway& gateway = spawnPointRecords[i].mGateway;
                 // entity_point
-                {
-                    std::unique_ptr<TiXmlElement> xmlEntityPoint(new TiXmlElement("entity_point"));
-                    xmlEntityPoint->SetAttribute("name", "Spawn_" + std::to_string(gateway.fieldID)); // TODO: Meta data for field name, maplist file in PC has the names 2 bytes for count of maps, the 32bytes per map name
-
-                    // TODO: These are wrong because game data says when going from this field to gateway.fieldID
-                    // spawn at position and rotation in gateway.fieldID.
-                    // But QGears data is reversed, it means when entering this field from gateway.fieldID 
-                    // spawn at position and rotation in gateway.fieldID.
-                    // However I think this adds limit of one entrance from gateway.fieldID to this field as there can only be
-                    // one Spawn_FieldName entity_point.
-                    // cosin1 field has 2 links to cos_btm
-                    // for fix we put in gateway name, so script calls:
-                    // load_field_map_request( "ffvii_nrthmk", "Spawn_md1_2_Gateway1" )
-                    // Instead of:
-                    // load_field_map_request( "ffvii_nrthmk", "Spawn_md1_2" )
-                    xmlEntityPoint->SetAttribute("position",
-                        Ogre::StringConverter::toString(
-                        Ogre::Vector3(gateway.destination.x, gateway.destination.y, gateway.destination.z) / downscaler_next));
-
-                    const float rotation = (360.0f * static_cast<float>(gateway.dir)) / 255.0f;
-                    xmlEntityPoint->SetAttribute("rotation", std::to_string(rotation));
-
-                    element->LinkEndChild(xmlEntityPoint.release());
-                }
-            }
+                std::unique_ptr<TiXmlElement> xmlEntityPoint(new TiXmlElement("entity_point"));
+
+                // Must also include the gateway index for the case where 2 fields have more than one door linking to each other
+                xmlEntityPoint->SetAttribute("name", "Spawn_" + fieldIdToNameLookup.at(spawnPointRecords[i].mFieldId) + "_" + std::to_string(spawnPointRecords[i].GatewayIndex));
+
+
+                xmlEntityPoint->SetAttribute("position",
+                    Ogre::StringConverter::toString(
+                    Ogre::Vector3(gateway.destination.x, gateway.destination.y, gateway.destination.z) / downscaler_next));
+
+                const float rotation = (360.0f * static_cast<float>(gateway.dir)) / 255.0f;
+                xmlEntityPoint->SetAttribute("rotation", std::to_string(rotation));
 
+                element->LinkEndChild(xmlEntityPoint.release());
+            }
         }
 
         doc.LinkEndChild(element.release());
@@ -406,38 +439,86 @@ static void FF7PcFieldToQGearsField(QGears::FLevelFilePtr& field, const std::str
     }
 }
 
+
+
+static void CollectSpawnPoints(QGears::FLevelFilePtr& field, const std::vector<std::string>& fieldIdToNameLookup, FieldSpawnPointsMap& spawnPoints)
+{
+    const size_t thisFieldId = FieldId(field->getName(), fieldIdToNameLookup);
+    const QGears::TriggersFilePtr& triggers = field->getTriggers();
+    const auto& gateways = triggers->GetGateways();
+    for (size_t i = 0; i < gateways.size(); i++)
+    {
+        const QGears::TriggersFile::Gateway& gateway = gateways[i];
+        if (gateway.destinationFieldId != kInactiveGateWayId)
+        {
+            auto it = spawnPoints.find(gateway.destinationFieldId);
+            if (it != std::end(spawnPoints))
+            {
+                // Add to the list of gateways that link to destinationFieldId
+                SpawnPointDb::Record rec;
+                rec.mFieldId = thisFieldId;
+                rec.mGateway = gateway;
+                rec.GatewayIndex = i;
+                it->second.mGatewaysToThisField.push_back(rec);
+            }
+            else
+            {
+                // Create a new record for destinationFieldId
+                SpawnPointDb db;
+                db.mTargetFieldId = gateway.destinationFieldId;
+
+                SpawnPointDb::Record rec;
+                rec.mFieldId = thisFieldId;
+                rec.mGateway = gateway;
+                rec.GatewayIndex = i;
+                db.mGatewaysToThisField.push_back(rec);
+
+                spawnPoints.insert(std::make_pair(db.mTargetFieldId, db));
+            }
+        }
+    }
+}
+
+static bool IsAFieldFile(Ogre::String& resourceName)
+{
+    return (!QGears::StringUtil::endsWith(resourceName, ".tex")
+        && !QGears::StringUtil::endsWith(resourceName, ".tut")
+        && !QGears::StringUtil::endsWith(resourceName, ".siz")
+        && resourceName != "maplist");
+}
+
 void FF7DataInstaller::ConvertFields(std::string archive, std::string outDir)
 {
-    // Everything in here is a field
+    // List whats in the LGP archive
     Ogre::StringVectorPtr resources = mApp.ResMgr()->listResourceNames("FFVIIFields", "*");
 
+    // Load the map list field
     QGears::MapListFilePtr mapList = QGears::MapListFileManager::getSingleton().load("maplist", "FFVIIFields").staticCast<QGears::MapListFile>();
-    for (const auto& fieldName : mapList->GetMapList())
+
+    // On the first pass collate required field information
+    FieldSpawnPointsMap spawnPoints;
+    for (auto& resourceName : *resources)
     {
-        std::cout << fieldName << std::endl;
+        // Exclude things that are not fields
+        if (IsAFieldFile(resourceName))
+        {
+            QGears::FLevelFilePtr field = QGears::LZSFLevelFileManager::getSingleton().load(resourceName, "FFVIIFields").staticCast<QGears::FLevelFile>();
+            CollectSpawnPoints(field, mapList->GetMapList(), spawnPoints);
+        }
     }
 
+    // Now we can do the full conversion with the collated data
     for (auto& resourceName : *resources)
     {
-        if (!QGears::StringUtil::endsWith(resourceName, ".tex")
-         && !QGears::StringUtil::endsWith(resourceName, ".tut")
-         && !QGears::StringUtil::endsWith(resourceName, ".siz")
-         && resourceName != "maplist" && resourceName == "md1_2")
+        // Exclude things that are not fields
+        if (IsAFieldFile(resourceName))
         {
-            //try
+            if (resourceName == "md1_2") // Testing conversion only on this field for now
             {
                 QGears::FLevelFilePtr field = QGears::LZSFLevelFileManager::getSingleton().load(resourceName, "FFVIIFields").staticCast<QGears::FLevelFile>();
-                FF7PcFieldToQGearsField(field, outDir);
+                FF7PcFieldToQGearsField(field, outDir, mapList->GetMapList(), spawnPoints);
             }
-            /*
-            catch (const Ogre::Exception& ex)
-            {
-                std::cout << "ERROR converting: " << resourceName << " Exception: " << ex.what() << std::endl;
-            }
-            catch (const std::exception& ex)
-            {
-                std::cout << "ERROR converting: " << resourceName << " Exception: " << ex.what() << std::endl;
-            }*/
         }
     }
+    
 }