Beispiel #1
0
        /// <summary>
        /// Gets BuildingSummary array generated from DFBlock data.
        /// DFBlock data should be provided from RMBLayout.GetLocationBuildingData() output.
        /// Otherwise not all building data will be present.
        /// </summary>
        /// <param name="blockData">DFBlock data.</param>
        /// <param name="layoutX">X coordindate in map layout used to generate building key.</param>
        /// <param name="layoutY">Y coordindate in map layout used to generate building key.</param>
        /// <returns>BuildingSummary.</returns>
        public static BuildingSummary[] GetBuildingData(DFBlock blockData, int layoutX = -1, int layoutY = -1)
        {
            // Store building information
            int buildingCount = blockData.RmbBlock.SubRecords.Length;

            BuildingSummary[] buildings = new BuildingSummary[buildingCount];
            for (int i = 0; i < buildingCount; i++)
            {
                // Create building summary
                buildings[i] = new BuildingSummary();

                // Set building data
                DFLocation.BuildingData buildingData = blockData.RmbBlock.FldHeader.BuildingDataList[i];
                buildings[i].buildingKey  = BuildingDirectory.MakeBuildingKey((byte)layoutX, (byte)layoutY, (byte)i);
                buildings[i].NameSeed     = buildingData.NameSeed;
                buildings[i].FactionId    = buildingData.FactionId;
                buildings[i].BuildingType = buildingData.BuildingType;
                buildings[i].Quality      = buildingData.Quality;

                // Set building transform info
                DFBlock.RmbSubRecord subRecord = blockData.RmbBlock.SubRecords[i];
                buildings[i].Position = new Vector3(subRecord.XPos, 0, BlocksFile.RMBDimension - subRecord.ZPos) * MeshReader.GlobalScale;
                buildings[i].Rotation = new Vector3(0, -subRecord.YRotation / BlocksFile.RotationDivisor, 0);
                buildings[i].Matrix   = Matrix4x4.TRS(buildings[i].Position, Quaternion.Euler(buildings[i].Rotation), Vector3.one);

                // First model of record is building model
                if (subRecord.Exterior.Block3dObjectRecords.Length > 0)
                {
                    buildings[i].ModelID = subRecord.Exterior.Block3dObjectRecords[0].ModelIdNum;
                }
            }

            return(buildings);
        }
Beispiel #2
0
        /// <summary>
        /// Gets BuildingSummary array generated from DFBlock data.
        /// </summary>
        /// <param name="blockData"></param>
        /// <returns></returns>
        public static BuildingSummary[] GetBuildingData(DFBlock blockData)
        {
            // Store building information
            int buildingCount = blockData.RmbBlock.SubRecords.Length;

            BuildingSummary[] buildings = new BuildingSummary[buildingCount];
            for (int i = 0; i < buildingCount; i++)
            {
                // Create building summary
                buildings[i] = new BuildingSummary();

                // Set building data
                DFLocation.BuildingData buildingData = blockData.RmbBlock.FldHeader.BuildingDataList[i];
                buildings[i].NameSeed     = buildingData.NameSeed;
                buildings[i].FactionId    = buildingData.FactionId;
                buildings[i].LocationId   = buildingData.LocationId;
                buildings[i].BuildingType = buildingData.BuildingType;
                buildings[i].Quality      = buildingData.Quality;

                // Set building transform info
                DFBlock.RmbSubRecord subRecord = blockData.RmbBlock.SubRecords[i];
                buildings[i].Position = new Vector3(subRecord.XPos, 0, BlocksFile.RMBDimension - subRecord.ZPos) * MeshReader.GlobalScale;
                buildings[i].Rotation = new Vector3(0, -subRecord.YRotation / BlocksFile.RotationDivisor, 0);
                buildings[i].Matrix   = Matrix4x4.TRS(buildings[i].Position, Quaternion.Euler(buildings[i].Rotation), Vector3.one);
            }

            return(buildings);
        }
Beispiel #3
0
        private static void OnTransitionToInterior_VariantShopTavernNPCsprites(PlayerEnterExit.TransitionEventArgs args)
        {
            PlayerEnterExit playerEnterExit = GameManager.Instance.PlayerEnterExit;

            DFLocation.BuildingData buildingData = playerEnterExit.Interior.BuildingData;
            if (buildingData.BuildingType == DFLocation.BuildingTypes.Tavern || RMBLayout.IsShop(buildingData.BuildingType))
            {
                Billboard[] dfBillboards = playerEnterExit.Interior.GetComponentsInChildren <Billboard>();
                foreach (Billboard billboard in dfBillboards)
                {
                    int record = -1;
                    if (billboard.Summary.Archive == 182 && billboard.Summary.Record == 0)
                    {
                        record = GetRecord_182_0(buildingData.Quality);     // (buildingData.Quality - 1) / 4;
#if UNITY_EDITOR
                        Debug.LogFormat("Shop quality {0} using record {1} to replace 182_0", buildingData.Quality, record);
#endif
                    }
                    else if (billboard.Summary.Archive == 182 && billboard.Summary.Record == 1)
                    {
                        if (buildingData.Quality < 12)
                        {   // Using big test flats version
                            record = 4;
                        }
                        else if (buildingData.Quality > 14)
                        {
                            record = 5;
                        }
#if UNITY_EDITOR
                        Debug.LogFormat("Tavern quality {0} using record {1} to replace 182_1", buildingData.Quality, record);
#endif
                    }
                    else if (billboard.Summary.Archive == 182 && billboard.Summary.Record == 2)
                    {
                        if (buildingData.Quality > 12)
                        {
                            record = 6;
                        }
#if UNITY_EDITOR
                        Debug.LogFormat("Tavern quality {0} using record {1} to replace 182_2", buildingData.Quality, record);
#endif
                    }

                    if (record > -1)
                    {
                        billboard.SetMaterial(197, record);
                        GameObjectHelper.AlignBillboardToGround(billboard.gameObject, billboard.Summary.Size);
                    }
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Gets all RMB blocks from a location populated with building data from MAPS.BSA.
        /// This method is using "best effort" process at this point in time.
        /// However, it does yield very accurate results most of the time.
        /// Please use exception handling when calling this method for now.
        /// It will be progressed over time.
        /// </summary>
        /// <param name="location">Location to use.</param>
        /// <param name="blocksOut">Array of blocks populated with data from MAPS.BSA.</param>
        public static void GetLocationBuildingData(DFLocation location, out DFBlock[] blocksOut)
        {
            List <BuildingPoolItem> namedBuildingPool = new List <BuildingPoolItem>();
            List <DFBlock>          blocks            = new List <DFBlock>();

            // Get content reader
            ContentReader contentReader = DaggerfallUnity.Instance.ContentReader;

            if (contentReader == null)
            {
                throw new Exception("GetCompleteBuildingData() could not find ContentReader.");
            }

            // Store named buildings in pool for distribution
            for (int i = 0; i < location.Exterior.BuildingCount; i++)
            {
                DFLocation.BuildingData building = location.Exterior.Buildings[i];
                if (IsNamedBuilding(building.BuildingType))
                {
                    BuildingPoolItem bpi = new BuildingPoolItem();
                    bpi.buildingData = building;
                    bpi.used         = false;
                    namedBuildingPool.Add(bpi);
                }
            }

            // Get building summary of all blocks in this location
            int width  = location.Exterior.ExteriorData.Width;
            int height = location.Exterior.ExteriorData.Height;

            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    // Get block name
                    string blockName = contentReader.BlockFileReader.CheckName(contentReader.MapFileReader.GetRmbBlockName(ref location, x, y));

                    // Get block data
                    DFBlock block;
                    if (!contentReader.GetBlock(blockName, out block))
                    {
                        throw new Exception("GetCompleteBuildingData() could not read block " + blockName);
                    }

                    // Make a copy of the building data array for our block copy since we're modifying it
                    DFLocation.BuildingData[] buildingArray = new DFLocation.BuildingData[block.RmbBlock.FldHeader.BuildingDataList.Length];
                    Array.Copy(block.RmbBlock.FldHeader.BuildingDataList, buildingArray, block.RmbBlock.FldHeader.BuildingDataList.Length);
                    block.RmbBlock.FldHeader.BuildingDataList = buildingArray;

                    // Assign building data for this block
                    BuildingReplacementData buildingReplacementData;
                    for (int i = 0; i < block.RmbBlock.SubRecords.Length; i++)
                    {
                        DFLocation.BuildingData building = block.RmbBlock.FldHeader.BuildingDataList[i];
                        if (IsNamedBuilding(building.BuildingType))
                        {
                            // Try to find next building and merge data
                            BuildingPoolItem item;
                            if (!GetNextBuildingFromPool(namedBuildingPool, building.BuildingType, out item))
                            {
                                Debug.LogFormat("End of city building list reached without finding building type {0} in location {1}.{2}", building.BuildingType, location.RegionName, location.Name);
                            }

                            // Copy found city building data to block level
                            building.NameSeed   = item.buildingData.NameSeed;
                            building.FactionId  = item.buildingData.FactionId;
                            building.Sector     = item.buildingData.Sector;
                            building.LocationId = item.buildingData.LocationId;
                            building.Quality    = item.buildingData.Quality;

                            // Check for replacement building data and use it if found
                            if (WorldDataReplacement.GetBuildingReplacementData(blockName, block.Index, i, out buildingReplacementData))
                            {
                                // Use custom building values from replacement data, but only use up pool item if factionId is zero
                                if (buildingReplacementData.FactionId != 0)
                                {
                                    // Don't use up pool item and set factionId, NameSeed, Quality from replacement data
                                    item.used          = false;
                                    building.FactionId = buildingReplacementData.FactionId;
                                    building.Quality   = buildingReplacementData.Quality;
                                    building.NameSeed  = (ushort)(buildingReplacementData.NameSeed + location.LocationIndex);   // Vary name seed by location
                                }
                                // Always override type
                                building.BuildingType = (DFLocation.BuildingTypes)buildingReplacementData.BuildingType;
                            }

                            // Matched to classic: special handling for some Order of the Raven buildings
                            if (block.RmbBlock.FldHeader.OtherNames != null &&
                                block.RmbBlock.FldHeader.OtherNames[i] == "KRAVE01.HS2")
                            {
                                building.BuildingType = DFLocation.BuildingTypes.GuildHall;
                                building.FactionId    = 414;
                            }

                            // Set whatever building data we could find
                            block.RmbBlock.FldHeader.BuildingDataList[i] = building;
                        }
                    }

                    // Save block data
                    blocks.Add(block);
                }
            }

            // Send blocks array back to caller
            blocksOut = blocks.ToArray();
        }
Beispiel #5
0
        /// <summary>
        /// Gets all RMB blocks from a location populated with building data from MAPS.BSA.
        /// This method is using "best effort" process at this point in time.
        /// However, it does yield very accurate results most of the time.
        /// Please use exception handling when calling this method for now.
        /// It will be progressed over time.
        /// </summary>
        /// <param name="location">Location to use.</param>
        /// <param name="blocksOut">Array of blocks populated with data from MAPS.BSA.</param>
        public static void GetLocationBuildingData(DFLocation location, out DFBlock[] blocksOut)
        {
            List <BuildingPoolItem> namedBuildingPool = new List <BuildingPoolItem>();
            List <DFBlock>          blocks            = new List <DFBlock>();

            // Get content reader
            ContentReader contentReader = DaggerfallUnity.Instance.ContentReader;

            if (contentReader == null)
            {
                throw new Exception("GetCompleteBuildingData() could not find ContentReader.");
            }

            // Store named buildings in pool for distribution
            for (int i = 0; i < location.Exterior.BuildingCount; i++)
            {
                DFLocation.BuildingData building = location.Exterior.Buildings[i];
                if (IsNamedBuilding(building.BuildingType))
                {
                    BuildingPoolItem bpi = new BuildingPoolItem();
                    bpi.buildingData = building;
                    bpi.used         = false;
                    namedBuildingPool.Add(bpi);
                }
            }

            // Get building summary of all blocks in this location
            int width  = location.Exterior.ExteriorData.Width;
            int height = location.Exterior.ExteriorData.Height;

            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    // Get block name
                    string blockName = contentReader.BlockFileReader.CheckName(contentReader.MapFileReader.GetRmbBlockName(ref location, x, y));

                    // Get block data
                    DFBlock block;
                    if (!contentReader.GetBlock(blockName, out block))
                    {
                        throw new Exception("GetCompleteBuildingData() could not read block " + blockName);
                    }

                    // Assign building data for this block
                    BuildingReplacementData buildingReplacementData;
                    for (int i = 0; i < block.RmbBlock.SubRecords.Length; i++)
                    {
                        DFLocation.BuildingData building = block.RmbBlock.FldHeader.BuildingDataList[i];
                        if (IsNamedBuilding(building.BuildingType))
                        {
                            // Check for replacement building data and use it if found
                            if (WorldDataReplacement.GetBuildingReplacementData(blockName, block.Index, i, out buildingReplacementData))
                            {
                                // Use custom building values from replacement data, don't use pool or maps file
                                building.NameSeed     = location.Exterior.Buildings[0].NameSeed;
                                building.FactionId    = buildingReplacementData.FactionId;
                                building.BuildingType = (DFLocation.BuildingTypes)buildingReplacementData.BuildingType;
                                building.LocationId   = location.Exterior.Buildings[0].LocationId;
                                building.Quality      = buildingReplacementData.Quality;
                            }
                            else
                            {
                                // Try to find next building and merge data
                                BuildingPoolItem item;
                                if (!GetNextBuildingFromPool(namedBuildingPool, building.BuildingType, out item))
                                {
                                    Debug.LogFormat("End of city building list reached without finding building type {0} in location {1}.{2}", building.BuildingType, location.RegionName, location.Name);
                                }
                                else
                                {
                                    // Copy found city building data to block level
                                    building.NameSeed   = item.buildingData.NameSeed;
                                    building.FactionId  = item.buildingData.FactionId;
                                    building.Sector     = item.buildingData.Sector;
                                    building.LocationId = item.buildingData.LocationId;
                                    building.Quality    = item.buildingData.Quality;
                                }
                            }
                            // Set whatever building data we could find
                            block.RmbBlock.FldHeader.BuildingDataList[i] = building;
                        }
                    }

                    // Save block data
                    blocks.Add(block);
                }
            }

            // Send blocks array back to caller
            blocksOut = blocks.ToArray();
        }
Beispiel #6
0
        private static void OnTransitionToInterior_VariantResidenceNPCsprites(PlayerEnterExit.TransitionEventArgs args)
        {
            if (villagerVarietyMod != null && villagerVarietyNumVariants == 0)
            {
                ModManager.Instance.SendModMessage(VILLAGERVARIETY_MODNAME, "getNumVariants", null, (string message, object data) => { villagerVarietyNumVariants = (int)data; });
            }

            PlayerEnterExit playerEnterExit = GameManager.Instance.PlayerEnterExit;

            DFLocation.BuildingData buildingData = playerEnterExit.Interior.BuildingData;
            if (RMBLayout.IsResidence(buildingData.BuildingType))
            {
                Races       race         = GetClimateRace();
                int         gender       = -1;
                Billboard[] dfBillboards = playerEnterExit.Interior.GetComponentsInChildren <Billboard>();
                foreach (Billboard billboard in dfBillboards)
                {
                    if (billboard.Summary.Archive == 182)
                    {
                        gender = GetGender182(billboard.Summary.Record);
                    }
                    else if (billboard.Summary.Archive == 184)
                    {
                        gender = GetGender184(billboard.Summary.Record);
                    }

                    if (gender != -1)
                    {
                        StaticNPC npc = billboard.GetComponent <StaticNPC>();
                        if (npc && npc.Data.factionID == 0)
                        {
                            int faceVariant = npc.Data.nameSeed % 29;
                            Debug.LogFormat("Replace house NPC {0}.{1} with faceVariant {2} - {3}", billboard.Summary.Archive, billboard.Summary.Record, faceVariant, faceVariant < 24);

                            if (faceVariant < 24)
                            {
                                int outfitVariant = npc.Data.nameSeed % 4;
                                int archive       = gender == (int)Genders.Male ? raceArchivesMale[race][outfitVariant] : raceArchivesFemale[race][outfitVariant];
                                int record        = 5;
                                int faceRecord    = gender == (int)Genders.Male ? raceFaceRecordMale[race][outfitVariant] : raceFaceRecordFemale[race][outfitVariant];
                                faceRecord += faceVariant;

                                bool materialSet = false;
                                if (villagerVarietyMod != null)
                                {
                                    int    variant = npc.Data.nameSeed % villagerVarietyNumVariants;
                                    string season  = "";
                                    //ModManager.Instance.SendModMessage(VILLAGERVARIETY_MODNAME, "getSeasonStr", null, (string message, object data) => { season = (string)data; });

                                    Debug.LogFormat("Replace house NPC {0}.{1} with {2}.{3}, outfit: {4} faceRecord: {5} ({6}) variant: {7} season: {8}", billboard.Summary.Archive, billboard.Summary.Record, archive, record, outfitVariant, faceRecord, faceVariant, variant, season);

                                    string imageName = null;
                                    ModManager.Instance.SendModMessage(VILLAGERVARIETY_MODNAME, "getImageName",
                                                                       new object[] { archive, record, 0, faceRecord, variant, season },
                                                                       (string message, object data) => { imageName = (string)data; });

                                    if (!string.IsNullOrEmpty(imageName) && villagerVarietyMod.HasAsset(imageName))
                                    {
                                        // Get texture and create material
                                        Texture2D texture  = villagerVarietyMod.GetAsset <Texture2D>(imageName);
                                        Material  material = MaterialReader.CreateStandardMaterial(MaterialReader.CustomBlendMode.Cutout);
                                        material.mainTexture = texture;

                                        // Apply material to mesh renderer
                                        MeshRenderer meshRenderer = billboard.GetComponent <MeshRenderer>();
                                        meshRenderer.sharedMaterial = material;

                                        // Create mesh and setup UV map for mesh filter
                                        Vector2 size;
                                        Mesh    mesh = DaggerfallUnity.Instance.MeshReader.GetBillboardMesh(new Rect(0, 0, 1, 1), archive, record, out size);
                                        mesh.uv = new Vector2[] { new Vector2(0, 1), new Vector2(1, 1), new Vector2(0, 0), new Vector2(1, 0) };
                                        MeshFilter meshFilter = billboard.GetComponent <MeshFilter>();
                                        Destroy(meshFilter.sharedMesh);
                                        meshFilter.sharedMesh = mesh;
                                        materialSet           = true;
                                    }
                                }
                                if (!materialSet)
                                {
                                    billboard.SetMaterial(archive, record);
                                    billboard.FramesPerSecond = 1;
                                }
                                GameObjectHelper.AlignBillboardToGround(billboard.gameObject, billboard.Summary.Size);

                                Dictionary <int, FlatsFile.FlatData> flatsDict = DaggerfallUnity.Instance.ContentReader.FlatsFileReader.FlatsDict;
                                int flatId = FlatsFile.GetFlatID(npc.Data.billboardArchiveIndex, npc.Data.billboardRecordIndex);
#if UNITY_EDITOR
                                Debug.LogFormat("Replacing face dict for {0} with {1} (for {2}.{3} / {4}.{5})", flatsDict[flatId].faceIndex, faceRecord, npc.Data.billboardArchiveIndex, npc.Data.billboardRecordIndex, billboard.Summary.Archive, billboard.Summary.Record);
#endif
                                flatsDict[flatId] = new FlatsFile.FlatData()
                                {
                                    archive   = billboard.Summary.Archive,
                                    record    = billboard.Summary.Record,
                                    faceIndex = faceRecord,
                                };
                            }
                        }
                    }
                }
            }
        }