Пример #1
0
        private static bool ReplaceMesh(GameObject prefab, MeshReplacement meshReplacement)
        {
            var replacees = prefab.FindAll(meshReplacement.name);

            foreach (var replacee in replacees)
            {
                // one of these two should exist
                var mf = replacee.GetComponent <MeshFilter>();
                if (mf != null)
                {
                    // if (new Regex("interior").IsMatch(meshReplacement.name))
                    // {
                    //     var renderer = replacee.GetComponent<Renderer>();
                    //     Debug.Log($"{meshReplacement.name} textures are {string.Join(", ", renderer.sharedMaterials.Select(m => $"[{string.Join(", ", new string[] { m?.GetTexture("_t1")?.name, m?.GetTexture("_t3")?.name, m?.GetTexture("_t4")?.name })}]"))}");
                    // }
                    mf.sharedMesh = meshReplacement.mesh;
                }
                var smr = replacee.GetComponent <SkinnedMeshRenderer>();
                if (smr != null)
                {
                    smr.sharedMesh = meshReplacement.mesh;
                }
            }

            return(replacees.Count > 0);
        }
        /// <summary>
        /// Add interior people flats.
        /// </summary>
        private void AddPeople()
        {
            GameObject node = new GameObject("People Flats");

            node.transform.parent = this.transform;

            // Add block flats
            foreach (DFBlock.RmbBlockPeopleRecord obj in recordData.Interior.BlockPeopleRecords)
            {
                // Calculate position
                Vector3 billboardPosition = new Vector3(obj.XPos, -obj.YPos, obj.ZPos) * MeshReader.GlobalScale;

                // Import 3D character instead of billboard
                if (MeshReplacement.ImportCustomFlatGameobject(obj.TextureArchive, obj.TextureRecord, billboardPosition, node.transform) != null)
                {
                    continue;
                }

                // Spawn billboard gameobject
                GameObject go = GameObjectHelper.CreateDaggerfallBillboardGameObject(obj.TextureArchive, obj.TextureRecord, node.transform);

                // Set position
                DaggerfallBillboard dfBillboard = go.GetComponent <DaggerfallBillboard>();
                go.transform.position  = billboardPosition;
                go.transform.position += new Vector3(0, dfBillboard.Summary.Size.y / 2, 0);

                // Add RMB data to billboard
                dfBillboard.SetRMBPeopleData(obj);

                // Add StaticNPC behaviour
                StaticNPC npc = go.AddComponent <StaticNPC>();
                npc.SetLayoutData(obj);
            }
        }
Пример #3
0
        /// <summary>
        /// Add misc block flats.
        /// Batching is conditionally supported.
        /// </summary>
        public static void AddMiscBlockFlats(
            ref DFBlock blockData,
            Transform flatsParent,
            DaggerfallBillboardBatch animalsBillboardBatch = null,
            TextureAtlasBuilder miscBillboardsAtlas        = null,
            DaggerfallBillboardBatch miscBillboardsBatch   = null)
        {
            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;

            if (!dfUnity.IsReady)
            {
                return;
            }

            // Add block flats
            foreach (DFBlock.RmbBlockFlatObjectRecord obj in blockData.RmbBlock.MiscFlatObjectRecords)
            {
                // Ignore lights as they are handled by AddLights()
                if (obj.TextureArchive == TextureReader.LightsTextureArchive)
                {
                    continue;
                }

                // Calculate position
                Vector3 billboardPosition = new Vector3(
                    obj.XPos,
                    -obj.YPos + blockFlatsOffsetY,
                    obj.ZPos + BlocksFile.RMBDimension) * MeshReader.GlobalScale;

                // Import custom 3d gameobject instead of flat
                if (MeshReplacement.ImportCustomFlatGameobject(obj.TextureArchive, obj.TextureRecord, billboardPosition, flatsParent) != null)
                {
                    continue;
                }

                // Use misc billboard atlas where available
                if (miscBillboardsAtlas != null && miscBillboardsBatch != null)
                {
                    TextureAtlasBuilder.AtlasItem item = miscBillboardsAtlas.GetAtlasItem(obj.TextureArchive, obj.TextureRecord);
                    if (item.key != -1)
                    {
                        miscBillboardsBatch.AddItem(item.rect, item.textureItem.size, item.textureItem.scale, billboardPosition);
                        continue;
                    }
                }

                // Add to batch where available
                if (obj.TextureArchive == TextureReader.AnimalsTextureArchive && animalsBillboardBatch != null)
                {
                    animalsBillboardBatch.AddItem(obj.TextureRecord, billboardPosition);
                    continue;
                }

                // Add standalone billboard gameobject
                GameObject go = GameObjectHelper.CreateDaggerfallBillboardGameObject(obj.TextureArchive, obj.TextureRecord, flatsParent);
                go.transform.position = billboardPosition;
                AlignBillboardToBase(go);
            }
        }
Пример #4
0
        /// <summary>
        /// Add interior people flats.
        /// </summary>
        private void AddPeople(PlayerGPS.DiscoveredBuilding buildingData)
        {
            GameObject node = new GameObject("People Flats");

            node.transform.parent = this.transform;
            bool isMemberOfBuildingGuild = GameManager.Instance.GuildManager.GetGuild(buildingData.factionID).IsMember();

            // Add block flats
            foreach (DFBlock.RmbBlockPeopleRecord obj in recordData.Interior.BlockPeopleRecords)
            {
                // Calculate position
                Vector3 billboardPosition = new Vector3(obj.XPos, -obj.YPos, obj.ZPos) * MeshReader.GlobalScale;

                // Import 3D character instead of billboard
                if (MeshReplacement.ImportCustomFlatGameobject(obj.TextureArchive, obj.TextureRecord, billboardPosition, node.transform) != null)
                {
                    continue;
                }

                // Spawn billboard gameobject
                GameObject go = GameObjectHelper.CreateDaggerfallBillboardGameObject(obj.TextureArchive, obj.TextureRecord, node.transform);

                // Set position
                DaggerfallBillboard dfBillboard = go.GetComponent <DaggerfallBillboard>();
                go.transform.position  = billboardPosition;
                go.transform.position += new Vector3(0, dfBillboard.Summary.Size.y / 2, 0);

                // Add RMB data to billboard
                dfBillboard.SetRMBPeopleData(obj);

                // Add StaticNPC behaviour
                StaticNPC npc = go.AddComponent <StaticNPC>();
                npc.SetLayoutData(obj, entryDoor.buildingKey);

                // Disable people if shop or building is closed
                DFLocation.BuildingTypes buildingType = buildingData.buildingType;
                if ((RMBLayout.IsShop(buildingType) && !GameManager.Instance.PlayerEnterExit.IsPlayerInsideOpenShop) ||
                    (buildingType <= DFLocation.BuildingTypes.Palace && !RMBLayout.IsShop(buildingType) && !PlayerActivate.IsBuildingOpen(buildingType)))
                {
                    go.SetActive(false);
                }
                // Disable people if player owns this house
                else if (DaggerfallBankManager.IsHouseOwned(buildingData.buildingKey))
                {
                    go.SetActive(false);
                }
                // Disable people if this is TG/DB house and player is not a member
                else if (buildingData.buildingType == DFLocation.BuildingTypes.House2 && buildingData.factionID != 0 && !isMemberOfBuildingGuild)
                {
                    go.SetActive(false);
                }
                // Disable people if they are TG spymaster, but not in a legit TG house (TODO: spot any other instances for TG/DB)
                else if (buildingData.buildingType == DFLocation.BuildingTypes.House2 && buildingData.factionID == 0 &&
                         npc.Data.factionID == (int)GuildNpcServices.TG_Spymaster)
                {
                    go.SetActive(false);
                }
            }
        }
Пример #5
0
        public void RestoreSaveData(object dataIn)
        {
            if (!loot)
            {
                return;
            }

            LootContainerData_v1 data = (LootContainerData_v1)dataIn;

            if (data.loadID != LoadID)
            {
                return;
            }

            DaggerfallBillboard billboard = loot.GetComponent <DaggerfallBillboard>();

            // Restore position
            loot.transform.position = data.currentPosition;

            // Restore appearance
            if (MeshReplacement.ImportCustomFlatGameobject(data.textureArchive, data.textureRecord, Vector3.zero, loot.transform))
            {
                // Use imported model instead of billboard
                if (billboard)
                {
                    Destroy(billboard);
                }
                Destroy(GetComponent <MeshRenderer>());
            }
            else if (billboard)
            {
                // Restore billboard appearance if present
                billboard.SetMaterial(data.textureArchive, data.textureRecord);
            }

            // Restore items
            loot.Items.DeserializeItems(data.items);

            // Restore other data
            loot.ContainerType  = data.containerType;
            loot.ContainerImage = data.containerImage;
            loot.LootTableKey   = data.lootTableKey;
            loot.TextureArchive = data.textureArchive;
            loot.TextureRecord  = data.textureRecord;
            loot.playerOwned    = data.playerOwned;
            loot.customDrop     = data.customDrop;
            loot.name           = loot.ContainerType.ToString();
            loot.entityName     = data.entityName;
            loot.isEnemyClass   = data.isEnemyClass;

            // Remove loot container if empty
            if (loot.Items.Count == 0)
            {
                GameObjectHelper.RemoveLootContainer(loot);
            }
        }
Пример #6
0
        /// <summary>
        /// Add nature billboards.
        /// </summary>
        public static void AddNatureFlats(
            ref DFBlock blockData,
            Transform flatsParent,
            DaggerfallBillboardBatch billboardBatch = null,
            ClimateNatureSets climateNature         = ClimateNatureSets.TemperateWoodland,
            ClimateSeason climateSeason             = ClimateSeason.Summer)
        {
            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;

            if (!dfUnity.IsReady)
            {
                return;
            }

            for (int y = 0; y < 16; y++)
            {
                for (int x = 0; x < 16; x++)
                {
                    // Get scenery item - ignore indices -1 (empty) and 0 (marker/waypoint of some kind)
                    DFBlock.RmbGroundScenery scenery = blockData.RmbBlock.FldHeader.GroundData.GroundScenery[x, 15 - y];
                    if (scenery.TextureRecord < 1)
                    {
                        continue;
                    }

                    // Calculate position
                    Vector3 billboardPosition = new Vector3(
                        x * BlocksFile.TileDimension,
                        natureFlatsOffsetY,
                        y * BlocksFile.TileDimension + BlocksFile.TileDimension) * MeshReader.GlobalScale;

                    // Get Archive
                    int natureArchive = ClimateSwaps.GetNatureArchive(climateNature, climateSeason);

                    // Import custom 3d gameobject instead of flat
                    if (MeshReplacement.ImportCustomFlatGameobject(natureArchive, scenery.TextureRecord, billboardPosition, flatsParent) != null)
                    {
                        continue;
                    }

                    // Add billboard to batch or standalone
                    if (billboardBatch != null)
                    {
                        billboardBatch.AddItem(scenery.TextureRecord, billboardPosition);
                    }
                    else
                    {
                        GameObject go = GameObjectHelper.CreateDaggerfallBillboardGameObject(natureArchive, scenery.TextureRecord, flatsParent);
                        go.transform.position = billboardPosition;
                        AlignBillboardToBase(go);
                    }
                }
            }
        }
Пример #7
0
        /// <summary>
        /// Adds light flats and prefabs.
        /// </summary>
        public static void AddLights(
            ref DFBlock blockData,
            Transform flatsParent,
            Transform lightsParent,
            DaggerfallBillboardBatch billboardBatch = null)
        {
            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;

            if (!dfUnity.IsReady)
            {
                return;
            }

            // Do nothing if import option not enabled or missing prefab
            if (!dfUnity.Option_ImportLightPrefabs || dfUnity.Option_CityLightPrefab == null)
            {
                return;
            }

            // Iterate block flats for lights
            foreach (DFBlock.RmbBlockFlatObjectRecord obj in blockData.RmbBlock.MiscFlatObjectRecords)
            {
                // Add point lights
                if (obj.TextureArchive == TextureReader.LightsTextureArchive)
                {
                    // Calculate position
                    Vector3 billboardPosition = new Vector3(
                        obj.XPos,
                        -obj.YPos + blockFlatsOffsetY,
                        obj.ZPos + BlocksFile.RMBDimension) * MeshReader.GlobalScale;

                    // Import custom 3d gameobject instead of flat
                    if (MeshReplacement.ImportCustomFlatGameobject(obj.TextureArchive, obj.TextureRecord, billboardPosition, flatsParent) != null)
                    {
                        continue;
                    }

                    // Add billboard to batch or standalone
                    if (billboardBatch != null)
                    {
                        billboardBatch.AddItem(obj.TextureRecord, billboardPosition);
                    }
                    else
                    {
                        GameObject go = GameObjectHelper.CreateDaggerfallBillboardGameObject(obj.TextureArchive, obj.TextureRecord, flatsParent);
                        go.transform.position = billboardPosition;
                        AlignBillboardToBase(go);
                    }

                    // Import light prefab
                    AddLight(dfUnity, obj, lightsParent);
                }
            }
        }
Пример #8
0
        /// <summary>
        /// Add interior people flats.
        /// </summary>
        private void AddPeople(PlayerGPS.DiscoveredBuilding buildingData)
        {
            GameObject node = new GameObject(peopleFlats);

            node.transform.parent = this.transform;
            IGuild guild = GameManager.Instance.GuildManager.GetGuild(buildingData.factionID);
            bool   isMemberOfBuildingGuild = guild.IsMember();

            // Add block flats
            foreach (DFBlock.RmbBlockPeopleRecord obj in recordData.Interior.BlockPeopleRecords)
            {
                // Calculate position
                Vector3 billboardPosition = new Vector3(obj.XPos, -obj.YPos, obj.ZPos) * MeshReader.GlobalScale;

                // Make person gameobject
                GameObject go = MeshReplacement.ImportCustomFlatGameobject(obj.TextureArchive, obj.TextureRecord, billboardPosition, node.transform);
                if (!go)
                {
                    // Spawn billboard gameobject
                    go = GameObjectHelper.CreateDaggerfallBillboardGameObject(obj.TextureArchive, obj.TextureRecord, node.transform);

                    // Set position
                    DaggerfallBillboard dfBillboard = go.GetComponent <DaggerfallBillboard>();
                    go.transform.position  = billboardPosition;
                    go.transform.position += new Vector3(0, dfBillboard.Summary.Size.y / 2, 0);

                    // Add RMB data to billboard
                    dfBillboard.SetRMBPeopleData(obj);
                }

                // Add StaticNPC behaviour
                StaticNPC npc = go.AddComponent <StaticNPC>();
                npc.SetLayoutData(obj, entryDoor.buildingKey);

                // Disable people if shop or building is closed
                DFLocation.BuildingTypes buildingType = buildingData.buildingType;
                if ((RMBLayout.IsShop(buildingType) && !GameManager.Instance.PlayerEnterExit.IsPlayerInsideOpenShop) ||
                    (buildingType <= DFLocation.BuildingTypes.Palace && !RMBLayout.IsShop(buildingType) &&
                     !(PlayerActivate.IsBuildingOpen(buildingType) || buildingType == DFLocation.BuildingTypes.GuildHall && guild.HallAccessAnytime())))
                {
                    go.SetActive(false);
                }
                // Disable people if player owns this house
                else if (DaggerfallBankManager.IsHouseOwned(buildingData.buildingKey))
                {
                    go.SetActive(false);
                }
                // Disable people if this is TG/DB house and player is not a member
                else if (buildingData.buildingType == DFLocation.BuildingTypes.House2 && buildingData.factionID != 0 && !isMemberOfBuildingGuild)
                {
                    go.SetActive(false);
                }
            }
        }
Пример #9
0
 internal static void Process(GameObject go, bool IsFemale)
 {
     if (!IsFemale)
     {
         return;
     }
     MeshReplacement[] componentsInChildren = go.GetComponentsInChildren <MeshReplacement>(true);
     for (int i = 0; i < (int)componentsInChildren.Length; i++)
     {
         MeshReplacement     meshReplacement = componentsInChildren[i];
         SkinnedMeshRenderer component       = meshReplacement.GetComponent <SkinnedMeshRenderer>();
         component.sharedMesh = meshReplacement.Female.sharedMesh;
         component.rootBone   = meshReplacement.Female.rootBone;
         component.bones      = meshReplacement.Female.bones;
     }
 }
Пример #10
0
        private static void AddProps(
            DaggerfallUnity dfUnity,
            ref DFBlock blockData,
            out List <StaticDoor> doorsOut,
            ModelCombiner combiner = null,
            Transform parent       = null)
        {
            doorsOut = new List <StaticDoor>();

            // Iterate through all misc records
            foreach (DFBlock.RmbBlock3dObjectRecord obj in blockData.RmbBlock.Misc3dObjectRecords)
            {
                // Get model transform
                Vector3   modelPosition = new Vector3(obj.XPos, -obj.YPos + propsOffsetY, obj.ZPos + BlocksFile.RMBDimension) * MeshReader.GlobalScale;
                Vector3   modelRotation = new Vector3(-obj.XRotation / BlocksFile.RotationDivisor, -obj.YRotation / BlocksFile.RotationDivisor, -obj.ZRotation / BlocksFile.RotationDivisor);
                Vector3   modelScale    = GetModelScaleVector(obj);
                Matrix4x4 modelMatrix   = Matrix4x4.TRS(modelPosition, Quaternion.Euler(modelRotation), modelScale);

                // Get model data
                ModelData modelData;
                dfUnity.MeshReader.GetModelData(obj.ModelIdNum, out modelData);

                // Does this model have doors?
                if (modelData.Doors != null)
                {
                    doorsOut.AddRange(GameObjectHelper.GetStaticDoors(ref modelData, blockData.Index, 0, modelMatrix));
                }

                // Import custom GameObject
                if (MeshReplacement.ImportCustomGameobject(obj.ModelIdNum, parent, modelMatrix) != null)
                {
                    continue;
                }

                // Use Daggerfall Model
                // Add or combine
                if (combiner == null || IsBulletinBoard(obj.ModelIdNum) || PlayerActivate.HasCustomActivation(obj.ModelIdNum))
                {
                    AddStandaloneModel(dfUnity, ref modelData, modelMatrix, parent);
                }
                else
                {
                    combiner.Add(ref modelData, modelMatrix);
                }
            }
        }
Пример #11
0
        private static void PlaceWagon(bool fromSave = false)
        {
            if (fromSave == false)
            {
                WagonMapPixel = GameManager.Instance.PlayerGPS.CurrentMapPixel;
                if (!transportManager.HasHorse())
                {
                    SetWagonPositionAndRotation(true);
                    DaggerfallUI.MessageBox("You have no horse to pull your wagon.");
                    ItemCollection playerItems = GameManager.Instance.PlayerEntity.Items;
                    for (int i = 0; i < playerItems.Count; i++)
                    {
                        DaggerfallUnityItem item = playerItems.GetItem(i);
                        if (item != null && item.IsOfTemplate(ItemGroups.Transportation, (int)Transportation.Small_cart))
                        {
                            playerItems.RemoveItem(item);
                        }
                    }
                }
                else
                {
                    SetWagonPositionAndRotation();
                }
            }
            else
            {
                PlaceWagonOnGround();
            }
            Wagon = MeshReplacement.ImportCustomGameobject(wagonModelID, null, WagonMatrix);
            if (Wagon == null)
            {
                Wagon = GameObjectHelper.CreateDaggerfallMeshGameObject(wagonModelID, null);
            }

            Wagon.transform.SetPositionAndRotation(WagonPosition, WagonRotation);
            if (GameManager.Instance.PlayerEnterExit.IsPlayerInsideDungeon)
            {
                Wagon.SetActive(false);
            }
            else
            {
                Wagon.SetActive(true);
            }
            WagonDeployed = true;
        }
Пример #12
0
 private static void DeployTent(bool fromSave = false)
 {
     if (fromSave == false)
     {
         TentMapPixel = GameManager.Instance.PlayerGPS.CurrentMapPixel;
         SetTentPositionAndRotation();
     }
     //Attempt to load a model replacement
     Tent = MeshReplacement.ImportCustomGameobject(tentModelID, null, TentMatrix);
     if (Tent == null)
     {
         Tent = GameObjectHelper.CreateDaggerfallMeshGameObject(tentModelID, null);
     }
     //Set the model's position in the world
     Tent.transform.SetPositionAndRotation(TentPosition, TentRotation);
     Tent.SetActive(true);
     TentDeployed = true;
 }
        /// <summary>
        /// Add interior flats.
        /// </summary>
        private void AddFlats()
        {
            GameObject node = new GameObject("Interior Flats");

            node.transform.parent = this.transform;

            // Add block flats
            markers.Clear();
            foreach (DFBlock.RmbBlockFlatObjectRecord obj in recordData.Interior.BlockFlatObjectRecords)
            {
                // Calculate position
                Vector3 billboardPosition = new Vector3(obj.XPos, -obj.YPos, obj.ZPos) * MeshReader.GlobalScale;

                // Import custom 3d gameobject instead of flat
                if (MeshReplacement.ImportCustomFlatGameobject(obj.TextureArchive, obj.TextureRecord, billboardPosition, node.transform) != null)
                {
                    continue;
                }

                // Spawn billboard gameobject
                GameObject go = GameObjectHelper.CreateDaggerfallBillboardGameObject(obj.TextureArchive, obj.TextureRecord, node.transform);

                // Set position
                DaggerfallBillboard dfBillboard = go.GetComponent <DaggerfallBillboard>();
                go.transform.position  = billboardPosition;
                go.transform.position += new Vector3(0, dfBillboard.Summary.Size.y / 2, 0);

                // Add editor markers to list
                if (obj.TextureArchive == TextureReader.EditorFlatsTextureArchive)
                {
                    InteriorEditorMarker marker = new InteriorEditorMarker();
                    marker.type       = (InteriorMarkerTypes)obj.TextureRecord;
                    marker.gameObject = go;
                    markers.Add(marker);
                }

                // Add point lights
                if (obj.TextureArchive == TextureReader.LightsTextureArchive)
                {
                    AddLight(obj, go.transform);
                }
            }
        }
        /// <summary>
        /// Add interior flats.
        /// </summary>
        private void AddFlats()
        {
            GameObject node = new GameObject("Interior Flats");

            node.transform.parent = this.transform;

            // Add block flats
            markers.Clear();
            foreach (DFBlock.RmbBlockFlatObjectRecord obj in recordData.Interior.BlockFlatObjectRecords)
            {
                // Calculate position
                Vector3 billboardPosition = new Vector3(obj.XPos, -obj.YPos, obj.ZPos) * MeshReader.GlobalScale;

                // Import custom 3d gameobject instead of flat
                if (MeshReplacement.ImportCustomFlatGameobject(obj.TextureArchive, obj.TextureRecord, billboardPosition, node.transform) != null)
                {
                    continue;
                }

                // Spawn billboard gameobject
                GameObject go = GameObjectHelper.CreateDaggerfallBillboardGameObject(obj.TextureArchive, obj.TextureRecord, node.transform);

                // Set position
                DaggerfallBillboard dfBillboard = go.GetComponent <DaggerfallBillboard>();
                go.transform.position  = billboardPosition;
                go.transform.position += new Vector3(0, dfBillboard.Summary.Size.y / 2, 0);

                // Add to enter marker list, which is TEXTURE.199, index 8.
                // Sometimes marker 199.4 is used where the 199.8 enter marker should be
                // Being a little forgiving and also accepting 199.4 as enter marker
                // Will add more of these cases if I find them
                if (obj.TextureArchive == TextureReader.EditorFlatsTextureArchive && (obj.TextureRecord == 8 || obj.TextureRecord == 4))
                {
                    markers.Add(go);
                }

                // Add point lights
                if (obj.TextureArchive == TextureReader.LightsTextureArchive)
                {
                    AddLight(obj, go.transform);
                }
            }
        }
Пример #15
0
        public static void DeployTent(bool fromSave = false)
        {
            if (fromSave == false)
            {
                CampMapPixel = GameManager.Instance.PlayerGPS.CurrentMapPixel;
                SetTentPositionAndRotation();
                DaggerfallUI.MessageBox("You set up camp");
            }
            else
            {
                PlaceTentOnGround();
            }
            //Attempt to load a model replacement
            Tent = MeshReplacement.ImportCustomGameobject(tentModelID, null, TentMatrix);
            Fire = GameObjectHelper.CreateDaggerfallBillboardGameObject(210, 1, null);
            if (Tent == null)
            {
                Tent = GameObjectHelper.CreateDaggerfallMeshGameObject(tentModelID, null);
            }
            //Set the model's position in the world

            Tent.transform.SetPositionAndRotation(TentPosition, TentRotation);
            if (GameManager.Instance.PlayerEnterExit.IsPlayerInsideDungeon)
            {
                FirePosition = Tent.transform.position + (Tent.transform.up * 0.8f);
                Tent.SetActive(false);
            }
            else
            {
                FirePosition = Tent.transform.position + (Tent.transform.forward * 3) + (Tent.transform.up * 0.8f);
                Tent.SetActive(true);
            }

            Fire.transform.SetPositionAndRotation(FirePosition, TentRotation);
            Fire.SetActive(true);
            AddTorchAudioSource(Fire);
            GameObject lightsNode = new GameObject("Lights");

            lightsNode.transform.parent = Fire.transform;
            AddLight(DaggerfallUnity.Instance, Fire, lightsNode.transform);
            CampDeployed = true;
            FireLit      = true;
        }
        public static GameObject AddFlatObject(DFBlock.RdbObject obj)
        {
            int archive = obj.Resources.FlatResource.TextureArchive;
            int record  = obj.Resources.FlatResource.TextureRecord;

            // Add GameObject to scene
            Vector3    targetPosition = new Vector3(obj.XPos, -obj.YPos, obj.ZPos) * MeshReader.GlobalScale;
            GameObject go             = MeshReplacement.ImportCustomFlatGameobject(archive, record, targetPosition, null, true);

            if (!go)
            {
                // Setup standard billboard and assign RDB data
                go = GameObjectHelper.CreateDaggerfallBillboardGameObject(archive, record, null);
                go.transform.position = targetPosition;
                Billboard dfBillboard = go.GetComponent <Billboard>();
                dfBillboard.SetRDBResourceData(obj.Resources.FlatResource);
            }
            return(go);
        }
        private void Display3dModelSelection(int selectedIdx)
        {
            if (goModel)
            {
                Object.Destroy(goModel);
                goModel = null;
            }

            // Position camera and set model id
            uint modelId = 0;

            if (housesForSale == null)
            {
                camera.transform.position = new Vector3(0, 12, DaggerfallBankManager.GetShipCameraDist((ShipType)selectedIdx));
                modelId = DaggerfallBankManager.GetShipModelId((ShipType)selectedIdx);
            }
            else
            {
                camera.transform.position = new Vector3(0, 3, -20);
                BuildingSummary house = housesForSale[selectedIdx];
                modelId = house.ModelID;
            }

            // Inject custom GameObject if available else create standard mesh game object for the model
            goModel = MeshReplacement.ImportCustomGameobject(modelId, goBankPurchase.transform, new Matrix4x4());
            if (goModel == null)
            {
                goModel = GameObjectHelper.CreateDaggerfallMeshGameObject(modelId, goBankPurchase.transform);
            }

            goModel.layer = layer;

            // Apply current climate
            ClimateBases   climateBase = ClimateSwaps.FromAPIClimateBase(GameManager.Instance.PlayerGPS.ClimateSettings.ClimateType);
            ClimateSeason  season      = (DaggerfallUnity.WorldTime.Now.SeasonValue == DaggerfallDateTime.Seasons.Winter) ? ClimateSeason.Winter : ClimateSeason.Summer;
            DaggerfallMesh dfMesh      = goModel.GetComponent <DaggerfallMesh>();

            dfMesh.SetClimate(climateBase, season, WindowStyle.Day);
        }
        public static GameObject Add3dObject(DFBlock.RdbObject obj, ref DFBlock.RdbModelReference[] modelReferenceList)
        {
            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;

            // Get model reference index and id
            int  modelReference = obj.Resources.ModelResource.ModelIndex;
            uint modelId        = modelReferenceList[modelReference].ModelIdNum;

            // Get matrix
            Vector3   modelRotation = new Vector3(-obj.Resources.ModelResource.XRotation / BlocksFile.RotationDivisor, -obj.Resources.ModelResource.YRotation / BlocksFile.RotationDivisor, -obj.Resources.ModelResource.ZRotation / BlocksFile.RotationDivisor);
            Vector3   modelPosition = new Vector3(obj.XPos, -obj.YPos, obj.ZPos) * MeshReader.GlobalScale;
            Matrix4x4 modelMatrix   = Matrix4x4.TRS(modelPosition, Quaternion.Euler(modelRotation), Vector3.one);

            // Get model data
            ModelData modelData;

            dfUnity.MeshReader.GetModelData(modelId, out modelData);

            // Get GameObject
            GameObject modelGO = MeshReplacement.ImportCustomGameobject(modelId, null, modelMatrix, false);

            if (modelGO == null)
            {
                if (modelData.DFMesh.TotalVertices != 0)
                {
                    modelGO = GameObjectHelper.CreateDaggerfallMeshGameObject(modelId, null);
                    modelGO.transform.position   = modelMatrix.GetColumn(3);
                    modelGO.transform.rotation   = modelMatrix.rotation;
                    modelGO.transform.localScale = modelMatrix.lossyScale;
                }
                else
                {
                    Debug.LogError("Custom model not found for modelId " + modelId);
                }
            }
            return(modelGO);
        }
Пример #19
0
        /// <summary>
        /// Add action doors to parent transform.
        /// </summary>
        private void AddActionDoors()
        {
            // Using 9000-9005 here but identical door models are also found at 900x, 910x, through to 980x
            // They seem to be duplicate models but can have different model origins so not all ranges are suitable
            const int doorModelBaseId = 9000;

            GameObject actionDoorsNode = new GameObject("Action Doors");

            actionDoorsNode.transform.parent = this.transform;

            foreach (DFBlock.RmbBlockDoorRecord obj in recordData.Interior.BlockDoorRecords)
            {
                // Create unique LoadID for save sytem
                ulong loadID = (ulong)(blockData.Position + obj.Position);

                // Get model transform
                Vector3 modelRotation = new Vector3(0, -obj.YRotation / BlocksFile.RotationDivisor, 0);
                Vector3 modelPosition = new Vector3(obj.XPos, -obj.YPos, obj.ZPos) * MeshReader.GlobalScale;

                // Instantiate door prefab and add model - DoorModelIndex is modulo to known-good range just in case
                // A custom prefab can be provided by mods and must include DaggerfallActionDoor component with all requirements.
                uint       modelId = (uint)(doorModelBaseId + obj.DoorModelIndex % 5);
                GameObject go      = MeshReplacement.ImportCustomGameobject(modelId, actionDoorsNode.transform, Matrix4x4.identity);
                if (!go)
                {
                    go = GameObjectHelper.InstantiatePrefab(dfUnity.Option_InteriorDoorPrefab.gameObject, string.Empty, actionDoorsNode.transform, Vector3.zero);
                    GameObjectHelper.CreateDaggerfallMeshGameObject(modelId, actionDoorsNode.transform, false, go, true);

                    // Resize box collider to new mesh bounds
                    BoxCollider  boxCollider  = go.GetComponent <BoxCollider>();
                    MeshRenderer meshRenderer = go.GetComponent <MeshRenderer>();
                    if (boxCollider != null && meshRenderer != null)
                    {
                        boxCollider.center = meshRenderer.bounds.center;
                        boxCollider.size   = meshRenderer.bounds.size;
                    }

                    // Update climate
                    DaggerfallMesh dfMesh = go.GetComponent <DaggerfallMesh>();
                    dfMesh.SetClimate(climateBase, climateSeason, WindowStyle.Disabled);
                }

                // Apply transforms
                go.transform.rotation = Quaternion.Euler(modelRotation);
                go.transform.position = modelPosition;

                // Get action door script
                DaggerfallActionDoor actionDoor = go.GetComponent <DaggerfallActionDoor>();

                // Assign loadID
                if (actionDoor)
                {
                    actionDoor.LoadID = loadID;
                }

                if (SaveLoadManager.Instance != null)
                {
                    go.AddComponent <SerializableActionDoor>();
                }
            }
        }
Пример #20
0
        private static void AddModels(
            DaggerfallUnity dfUnity,
            int layoutX,
            int layoutY,
            ref DFBlock blockData,
            out List <StaticDoor> doorsOut,
            out List <StaticBuilding> buildingsOut,
            ModelCombiner combiner = null,
            Transform parent       = null)
        {
            doorsOut     = new List <StaticDoor>();
            buildingsOut = new List <StaticBuilding>();

            // Iterate through all subrecords
            int recordCount = 0;

            foreach (DFBlock.RmbSubRecord subRecord in blockData.RmbBlock.SubRecords)
            {
                // Get subrecord transform
                Vector3   subRecordPosition = new Vector3(subRecord.XPos, 0, BlocksFile.RMBDimension - subRecord.ZPos) * MeshReader.GlobalScale;
                Vector3   subRecordRotation = new Vector3(0, -subRecord.YRotation / BlocksFile.RotationDivisor, 0);
                Matrix4x4 subRecordMatrix   = Matrix4x4.TRS(subRecordPosition, Quaternion.Euler(subRecordRotation), Vector3.one);

                // Iterate through models in this subrecord
                bool firstModel = true;
                foreach (DFBlock.RmbBlock3dObjectRecord obj in subRecord.Exterior.Block3dObjectRecords)
                {
                    // Get model transform
                    Vector3   modelPosition = new Vector3(obj.XPos, -obj.YPos, obj.ZPos) * MeshReader.GlobalScale;
                    Vector3   modelRotation = new Vector3(-obj.XRotation / BlocksFile.RotationDivisor, -obj.YRotation / BlocksFile.RotationDivisor, -obj.ZRotation / BlocksFile.RotationDivisor);
                    Vector3   modelScale    = GetModelScaleVector(obj);
                    Matrix4x4 modelMatrix   = subRecordMatrix * Matrix4x4.TRS(modelPosition, Quaternion.Euler(modelRotation), modelScale);

                    // Get model data
                    ModelData modelData;
                    dfUnity.MeshReader.GetModelData(obj.ModelIdNum, out modelData);

                    // Does this model have doors?
                    StaticDoor[] staticDoors = null;
                    if (modelData.Doors != null)
                    {
                        staticDoors = GameObjectHelper.GetStaticDoors(ref modelData, blockData.Index, recordCount, modelMatrix);
                    }

                    // Store building information for first model of record
                    // First model is main record structure, others are attachments like posts
                    // Only main structure is needed to resolve building after hit-test
                    int buildingKey = 0;
                    if (firstModel)
                    {
                        // Create building key for this record - considered experimental for now
                        buildingKey = BuildingDirectory.MakeBuildingKey((byte)layoutX, (byte)layoutY, (byte)recordCount);

                        StaticBuilding staticBuilding = new StaticBuilding();
                        staticBuilding.modelMatrix = modelMatrix;
                        staticBuilding.recordIndex = recordCount;
                        staticBuilding.centre      = new Vector3(modelData.DFMesh.Centre.X, modelData.DFMesh.Centre.Y, modelData.DFMesh.Centre.Z) * MeshReader.GlobalScale;
                        staticBuilding.size        = new Vector3(modelData.DFMesh.Size.X, modelData.DFMesh.Size.Y, modelData.DFMesh.Size.Z) * MeshReader.GlobalScale;
                        buildingsOut.Add(staticBuilding);
                        firstModel = false;
                    }

                    bool dontCreateStaticDoors = false;

                    // Import custom GameObject or use Daggerfall Model
                    GameObject go;
                    if (go = MeshReplacement.ImportCustomGameobject(obj.ModelIdNum, parent, modelMatrix))
                    {
                        // Find doors
                        if (staticDoors != null && staticDoors.Length > 0)
                        {
                            CustomDoor.InitDoors(go, staticDoors, buildingKey, out dontCreateStaticDoors);
                        }
                    }
                    else if (combiner == null || IsCityGate(obj.ModelIdNum) || IsBulletinBoard(obj.ModelIdNum) || PlayerActivate.HasCustomActivation(obj.ModelIdNum))
                    {
                        AddStandaloneModel(dfUnity, ref modelData, modelMatrix, parent);
                    }
                    else
                    {
                        combiner.Add(ref modelData, modelMatrix);
                    }

                    if (modelData.Doors != null && !dontCreateStaticDoors)
                    {
                        doorsOut.AddRange(staticDoors);
                    }
                }

                // Increment record count
                recordCount++;
            }
        }
        /// <summary>
        /// Add interior models.
        /// </summary>
        private void AddModels()
        {
            List <StaticDoor> doors     = new List <StaticDoor>();
            GameObject        node      = new GameObject("Models");
            GameObject        doorsNode = new GameObject("Doors");

            node.transform.parent      = this.transform;
            doorsNode.transform.parent = this.transform;

            // Iterate through models in this subrecord
            combiner.NewCombiner();
            foreach (DFBlock.RmbBlock3dObjectRecord obj in recordData.Interior.Block3dObjectRecords)
            {
                // Get model data
                ModelData modelData;
                dfUnity.MeshReader.GetModelData(obj.ModelIdNum, out modelData);

                // Get model position by type (3 seems to indicate props/clutter)
                Vector3 modelPosition;
                if (obj.ObjectType == 3)
                {
                    // Props axis needs to be transformed to lowest Y point
                    Vector3 bottom = modelData.Vertices[0];
                    for (int i = 0; i < modelData.Vertices.Length; i++)
                    {
                        if (modelData.Vertices[i].y < bottom.y)
                        {
                            bottom = modelData.Vertices[i];
                        }
                    }
                    modelPosition  = new Vector3(obj.XPos, obj.YPos, obj.ZPos) * MeshReader.GlobalScale;
                    modelPosition += new Vector3(0, -bottom.y, 0);
                }
                else
                {
                    modelPosition = new Vector3(obj.XPos, -obj.YPos, obj.ZPos) * MeshReader.GlobalScale;
                }

                // Get model transform
                Vector3   modelRotation = new Vector3(0, -obj.YRotation / BlocksFile.RotationDivisor, 0);
                Matrix4x4 modelMatrix   = Matrix4x4.TRS(modelPosition, Quaternion.Euler(modelRotation), Vector3.one);

                // Does this model have doors?
                if (modelData.Doors != null)
                {
                    doors.AddRange(GameObjectHelper.GetStaticDoors(ref modelData, entryDoor.blockIndex, entryDoor.recordIndex, modelMatrix));
                }

                // Get GameObject
                if (MeshReplacement.ImportCustomGameobject(obj.ModelIdNum, node.transform, modelMatrix) == null)
                {
                    // Use Daggerfall Mesh: Combine or add
                    if (dfUnity.Option_CombineRMB)
                    {
                        combiner.Add(ref modelData, modelMatrix);
                    }
                    else
                    {
                        // Add GameObject
                        GameObject go = GameObjectHelper.CreateDaggerfallMeshGameObject(obj.ModelIdNum, node.transform, dfUnity.Option_SetStaticFlags);
                        go.transform.position = modelMatrix.GetColumn(3);
                        go.transform.rotation = GameObjectHelper.QuaternionFromMatrix(modelMatrix);

                        // Update climate
                        DaggerfallMesh dfMesh = go.GetComponent <DaggerfallMesh>();
                        dfMesh.SetClimate(climateBase, climateSeason, WindowStyle.Disabled);
                    }
                }
            }

            // Add combined GameObject
            if (dfUnity.Option_CombineRMB)
            {
                if (combiner.VertexCount > 0)
                {
                    combiner.Apply();
                    GameObject go = GameObjectHelper.CreateCombinedMeshGameObject(combiner, "CombinedModels", node.transform, dfUnity.Option_SetStaticFlags);

                    // Update climate
                    DaggerfallMesh dfMesh = go.GetComponent <DaggerfallMesh>();
                    dfMesh.SetClimate(climateBase, climateSeason, WindowStyle.Disabled);
                }
            }

            // Add static doors component
            DaggerfallStaticDoors c = this.gameObject.AddComponent <DaggerfallStaticDoors>();

            c.Doors = doors.ToArray();
        }
Пример #22
0
        /// <summary>
        /// Add misc block flats.
        /// Batching is conditionally supported.
        /// </summary>
        public static void AddMiscBlockFlats(
            ref DFBlock blockData,
            Transform flatsParent,
            DaggerfallBillboardBatch animalsBillboardBatch = null,
            TextureAtlasBuilder miscBillboardsAtlas        = null,
            DaggerfallBillboardBatch miscBillboardsBatch   = null)
        {
            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;

            if (!dfUnity.IsReady)
            {
                return;
            }

            // Add block flats
            foreach (DFBlock.RmbBlockFlatObjectRecord obj in blockData.RmbBlock.MiscFlatObjectRecords)
            {
                // Ignore lights as they are handled by AddLights()
                if (obj.TextureArchive == TextureReader.LightsTextureArchive)
                {
                    continue;
                }

                // Calculate position
                Vector3 billboardPosition = new Vector3(
                    obj.XPos,
                    -obj.YPos + blockFlatsOffsetY,
                    obj.ZPos + BlocksFile.RMBDimension) * MeshReader.GlobalScale;

                // Import custom 3d gameobject instead of flat
                if (MeshReplacement.ImportCustomFlatGameobject(obj.TextureArchive, obj.TextureRecord, billboardPosition, flatsParent) != null)
                {
                    continue;
                }

                //// Use misc billboard atlas where available
                //if (miscBillboardsAtlas != null && miscBillboardsBatch != null)
                //{
                //    TextureAtlasBuilder.AtlasItem item = miscBillboardsAtlas.GetAtlasItem(obj.TextureArchive, obj.TextureRecord);
                //    if (item.key != -1)
                //    {
                //        miscBillboardsBatch.AddItem(item.rect, item.textureItem.size, item.textureItem.scale, billboardPosition);
                //        continue;
                //    }
                //}

                // Add to batch where available
                //if (obj.TextureArchive == TextureReader.AnimalsTextureArchive && animalsBillboardBatch != null)
                //{
                //    animalsBillboardBatch.AddItem(obj.TextureRecord, billboardPosition);
                //    continue;
                //}

                // Add standalone billboard gameobject
                GameObject go = GameObjectHelper.CreateDaggerfallBillboardGameObject(obj.TextureArchive, obj.TextureRecord, flatsParent);
                go.transform.position = billboardPosition;
                AlignBillboardToBase(go);

                // Add animal sound
                if (obj.TextureArchive == TextureReader.AnimalsTextureArchive)
                {
                    AddAnimalAudioSource(go);
                }

                // If flat record has a non-zero faction id, then it's an exterior NPC
                if (obj.FactionID != 0)
                {
                    // Add RMB data to billboard
                    DaggerfallBillboard dfBillboard = go.GetComponent <DaggerfallBillboard>();
                    dfBillboard.SetRMBPeopleData(obj.FactionID, obj.Flags, obj.Position);

                    // Add StaticNPC behaviour
                    StaticNPC npc = go.AddComponent <StaticNPC>();
                    npc.SetLayoutData(obj);
                }
            }
        }
Пример #23
0
        /// <summary>
        /// Add misc block flats.
        /// Batching is conditionally supported.
        /// </summary>
        public static void AddMiscBlockFlats(
            ref DFBlock blockData,
            Transform flatsParent,
            int mapId,
            int locationIndex,
            DaggerfallBillboardBatch animalsBillboardBatch = null,
            TextureAtlasBuilder miscBillboardsAtlas        = null,
            DaggerfallBillboardBatch miscBillboardsBatch   = null)
        {
            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;

            if (!dfUnity.IsReady)
            {
                return;
            }

            // Add block flats
            foreach (DFBlock.RmbBlockFlatObjectRecord obj in blockData.RmbBlock.MiscFlatObjectRecords)
            {
                // Ignore lights as they are handled by AddLights()
                if (obj.TextureArchive == TextureReader.LightsTextureArchive)
                {
                    continue;
                }

                // Calculate position
                Vector3 billboardPosition = new Vector3(
                    obj.XPos,
                    -obj.YPos + blockFlatsOffsetY,
                    obj.ZPos + BlocksFile.RMBDimension) * MeshReader.GlobalScale;

                GameObject go = MeshReplacement.ImportCustomFlatGameobject(obj.TextureArchive, obj.TextureRecord, billboardPosition, flatsParent);
                if (go == null)
                {
                    // Add standalone billboard gameobject
                    go = GameObjectHelper.CreateDaggerfallBillboardGameObject(obj.TextureArchive, obj.TextureRecord, flatsParent);
                    go.transform.position = billboardPosition;
                    AlignBillboardToBase(go);
                }

                // Add animal sound
                if (obj.TextureArchive == TextureReader.AnimalsTextureArchive)
                {
                    AddAnimalAudioSource(go, obj.TextureRecord);
                }

                // If flat record has a non-zero faction id, then it's an exterior NPC
                if (obj.FactionID != 0)
                {
                    // Add RMB data to billboard
                    Billboard dfBillboard = go.GetComponent <Billboard>();
                    if (dfBillboard != null)
                    {
                        dfBillboard.SetRMBPeopleData(obj.FactionID, obj.Flags, obj.Position);
                    }

                    // Add StaticNPC behaviour
                    StaticNPC npc = go.AddComponent <StaticNPC>();
                    npc.SetLayoutData(obj, mapId, locationIndex);
                }
            }
        }
Пример #24
0
        // Drops nature flats based on random chance scaled by simple rules
        public static void LayoutNatureBillboards(DaggerfallTerrain dfTerrain, DaggerfallBillboardBatch dfBillboardBatch, float terrainScale, int terrainDist)
        {
            const float maxSteepness      = 50f;        // 50
            const float slopeSinkRatio    = 70f;        // Sink flats slightly into ground as slope increases to prevent floaty trees.
            const float baseChanceOnDirt  = 0.2f;       // 0.2
            const float baseChanceOnGrass = 0.9f;       // 0.4
            const float baseChanceOnStone = 0.05f;      // 0.05

            // Location Rect is expanded slightly to give extra clearance around locations
            const int natureClearance = 4;
            Rect      rect            = dfTerrain.MapData.locationRect;

            if (rect.x > 0 && rect.y > 0)
            {
                rect.xMin -= natureClearance;
                rect.xMax += natureClearance;
                rect.yMin -= natureClearance;
                rect.yMax += natureClearance;
            }
            // Chance scaled based on map pixel height
            // This tends to produce sparser lowlands and denser highlands
            // Adjust or remove clamp range to influence nature generation
            float elevationScale = (dfTerrain.MapData.worldHeight / 128f);

            elevationScale = Mathf.Clamp(elevationScale, 0.4f, 1.0f);

            // Chance scaled by base climate type
            float climateScale = 1.0f;

            DFLocation.ClimateSettings climate = MapsFile.GetWorldClimateSettings(dfTerrain.MapData.worldClimate);
            switch (climate.ClimateType)
            {
            case DFLocation.ClimateBaseType.Desert:             // Just lower desert for now
                climateScale = 0.25f;
                break;
            }
            float chanceOnDirt  = baseChanceOnDirt * elevationScale * climateScale;
            float chanceOnGrass = baseChanceOnGrass * elevationScale * climateScale;
            float chanceOnStone = baseChanceOnStone * elevationScale * climateScale;

            // Get terrain
            Terrain terrain = dfTerrain.gameObject.GetComponent <Terrain>();

            if (!terrain)
            {
                return;
            }

            // Get terrain data
            TerrainData terrainData = terrain.terrainData;

            if (!terrainData)
            {
                return;
            }

            // Remove exiting billboards
            dfBillboardBatch.Clear();
            MeshReplacement.ClearNatureGameObjects(terrain);

            // Seed random with terrain key
            Random.InitState(MakeTerrainKey(dfTerrain.MapPixelX, dfTerrain.MapPixelY));

            // Just layout some random flats spread evenly across entire map pixel area
            // Flats are aligned with tiles, max 16129 billboards per batch
            Vector2 tilePos          = Vector2.zero;
            int     tDim             = MapsFile.WorldMapTileDim;
            int     hDim             = DaggerfallUnity.Instance.TerrainSampler.HeightmapDimension;
            float   scale            = terrainData.heightmapScale.x * (float)hDim / (float)tDim;
            float   maxTerrainHeight = DaggerfallUnity.Instance.TerrainSampler.MaxTerrainHeight;
            float   beachLine        = DaggerfallUnity.Instance.TerrainSampler.BeachElevation;

            for (int y = 0; y < tDim; y++)
            {
                for (int x = 0; x < tDim; x++)
                {
                    // Reject based on steepness
                    float steepness = terrainData.GetSteepness((float)x / tDim, (float)y / tDim);
                    if (steepness > maxSteepness)
                    {
                        continue;
                    }

                    // Reject if inside location rect (expanded slightly to give extra clearance around locations)
                    tilePos.x = x;
                    tilePos.y = y;
                    if (rect.x > 0 && rect.y > 0 && rect.Contains(tilePos))
                    {
                        continue;
                    }

                    // Chance also determined by tile type
                    int tile = dfTerrain.MapData.tilemapSamples[x, y] & 0x3F;
                    if (tile == 1)
                    {   // Dirt
                        if (Random.Range(0f, 1f) > chanceOnDirt)
                        {
                            continue;
                        }
                    }
                    else if (tile == 2)
                    {   // Grass
                        if (Random.Range(0f, 1f) > chanceOnGrass)
                        {
                            continue;
                        }
                    }
                    else if (tile == 3)
                    {   // Stone
                        if (Random.Range(0f, 1f) > chanceOnStone)
                        {
                            continue;
                        }
                    }
                    else
                    {   // Anything else
                        continue;
                    }

                    int   hx     = (int)Mathf.Clamp(hDim * ((float)x / (float)tDim), 0, hDim - 1);
                    int   hy     = (int)Mathf.Clamp(hDim * ((float)y / (float)tDim), 0, hDim - 1);
                    float height = dfTerrain.MapData.heightmapSamples[hy, hx] * maxTerrainHeight;  // x & y swapped in heightmap for TerrainData.SetHeights()

                    // Reject if too close to water
                    if (height < beachLine)
                    {
                        continue;
                    }

                    // Sample height and position billboard
                    Vector3 pos     = new Vector3(x * scale, 0, y * scale);
                    float   height2 = terrain.SampleHeight(pos + terrain.transform.position);
                    pos.y = height2 - (steepness / slopeSinkRatio);

                    // Add to batch unless a mesh replacement is found
                    int record = Random.Range(1, 32);
                    if (terrainDist > 1 || !MeshReplacement.ImportNatureGameObject(dfBillboardBatch.TextureArchive, record, terrain, x, y))
                    {
                        dfBillboardBatch.AddItem(record, pos);
                    }
                    else if (!NatureMeshUsed)
                    {
                        NatureMeshUsed = true;  // Signal that nature mesh has been used to initiate extra terrain updates
                    }
                }
            }

            // Apply new batch
            dfBillboardBatch.Apply();
        }
Пример #25
0
        /// <summary>
        /// Add subrecord (building) exterior block flats.
        /// </summary>
        public static void AddExteriorBlockFlats(
            ref DFBlock blockData,
            Transform flatsParent,
            Transform lightsParent,
            int mapId,
            int locationIndex,
            ClimateNatureSets climateNature = ClimateNatureSets.TemperateWoodland,
            ClimateSeason climateSeason     = ClimateSeason.Summer)
        {
            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;

            if (!dfUnity.IsReady)
            {
                return;
            }

            // Get Nature Archive
            int natureArchive = ClimateSwaps.GetNatureArchive(climateNature, climateSeason);

            foreach (DFBlock.RmbSubRecord subRecord in blockData.RmbBlock.SubRecords)
            {
                Vector3 subRecordPosition = new Vector3(subRecord.XPos, 0, -subRecord.ZPos) * MeshReader.GlobalScale;

                foreach (DFBlock.RmbBlockFlatObjectRecord obj in subRecord.Exterior.BlockFlatObjectRecords)
                {
                    // Don't add building exterior editor flats since they can't be used by any DFU systems
                    int archive = obj.TextureArchive;
                    if (archive == TextureReader.EditorFlatsTextureArchive)
                    {
                        continue;
                    }

                    // Calculate position
                    Vector3 billboardPosition = new Vector3(
                        obj.XPos,
                        -obj.YPos + blockFlatsOffsetY,
                        obj.ZPos + BlocksFile.RMBDimension) * MeshReader.GlobalScale;

                    billboardPosition += subRecordPosition;

                    // Add natures using correct climate set archive
                    if (archive >= (int)DFLocation.ClimateTextureSet.Nature_RainForest && archive <= (int)DFLocation.ClimateTextureSet.Nature_Mountains_Snow)
                    {
                        archive             = natureArchive;
                        billboardPosition.z = natureFlatsOffsetY;
                    }

                    GameObject go         = MeshReplacement.ImportCustomFlatGameobject(archive, obj.TextureRecord, billboardPosition, flatsParent);
                    bool       isImported = go != null;
                    if (!isImported)
                    {
                        // Add standalone billboard gameobject
                        go = GameObjectHelper.CreateDaggerfallBillboardGameObject(archive, obj.TextureRecord, flatsParent);
                        go.transform.position = billboardPosition;
                        AlignBillboardToBase(go);
                    }

                    // Add animal sound
                    if (archive == TextureReader.AnimalsTextureArchive)
                    {
                        AddAnimalAudioSource(go, obj.TextureRecord);
                    }

                    // If flat record has a non-zero faction id, then it's an exterior NPC
                    if (obj.FactionID != 0)
                    {
                        // Add RMB data to billboard
                        Billboard dfBillboard = go.GetComponent <Billboard>();
                        if (dfBillboard != null)
                        {
                            dfBillboard.SetRMBPeopleData(obj.FactionID, obj.Flags, obj.Position);
                        }

                        // Add StaticNPC behaviour
                        StaticNPC npc = go.AddComponent <StaticNPC>();
                        npc.SetLayoutData(obj, mapId, locationIndex);
                    }

                    // If this is a light flat, import light prefab
                    if (archive == TextureReader.LightsTextureArchive && !isImported)
                    {
                        if (dfUnity.Option_CityLightPrefab == null)
                        {
                            return;
                        }

                        Vector2 size     = dfUnity.MeshReader.GetScaledBillboardSize(210, obj.TextureRecord);
                        Vector3 position = new Vector3(
                            obj.XPos,
                            -obj.YPos + size.y,
                            obj.ZPos + BlocksFile.RMBDimension) * MeshReader.GlobalScale;
                        position += subRecordPosition;

                        GameObjectHelper.InstantiatePrefab(dfUnity.Option_CityLightPrefab.gameObject, string.Empty, lightsParent, position);
                    }
                }
            }
        }
Пример #26
0
        /// <summary>
        /// Add interior models.
        /// </summary>
        private void AddModels(PlayerGPS.DiscoveredBuilding buildingData)
        {
            List <StaticDoor> doors     = new List <StaticDoor>();
            GameObject        node      = new GameObject("Models");
            GameObject        doorsNode = new GameObject("Doors");

            node.transform.parent      = this.transform;
            doorsNode.transform.parent = this.transform;

            // Iterate through models in this subrecord
            combiner.NewCombiner();
            foreach (DFBlock.RmbBlock3dObjectRecord obj in recordData.Interior.Block3dObjectRecords)
            {
                bool stopCombine = false;

                // Get model data
                ModelData modelData;
                dfUnity.MeshReader.GetModelData(obj.ModelIdNum, out modelData);

                // Get model position by type (3 seems to indicate props/clutter)
                // Also stop these from being combined as some may carry a loot container
                Vector3 modelPosition;
                if (obj.ObjectType == propModelType)
                {
                    // Props axis needs to be transformed to lowest Y point
                    Vector3 bottom = modelData.Vertices[0];
                    for (int i = 0; i < modelData.Vertices.Length; i++)
                    {
                        if (modelData.Vertices[i].y < bottom.y)
                        {
                            bottom = modelData.Vertices[i];
                        }
                    }
                    modelPosition  = new Vector3(obj.XPos, obj.YPos, obj.ZPos) * MeshReader.GlobalScale;
                    modelPosition += new Vector3(0, -bottom.y, 0);
                    stopCombine    = true;
                }
                else
                {
                    modelPosition = new Vector3(obj.XPos, -obj.YPos, obj.ZPos) * MeshReader.GlobalScale;
                }

                // Stop special object from being combined
                if (obj.ModelIdNum == ladderModelId)
                {
                    stopCombine = true;
                }

                // Get model transform
                Vector3   modelRotation = new Vector3(0, -obj.YRotation / BlocksFile.RotationDivisor, 0);
                Matrix4x4 modelMatrix   = Matrix4x4.TRS(modelPosition, Quaternion.Euler(modelRotation), Vector3.one);

                // Does this model have doors?
                if (modelData.Doors != null)
                {
                    doors.AddRange(GameObjectHelper.GetStaticDoors(ref modelData, entryDoor.blockIndex, entryDoor.recordIndex, modelMatrix));
                }

                // Inject custom GameObject if available
                GameObject go = MeshReplacement.ImportCustomGameobject(obj.ModelIdNum, node.transform, modelMatrix);

                // Otherwise use Daggerfall mesh - combine or add
                if (!go)
                {
                    if (dfUnity.Option_CombineRMB && !stopCombine)
                    {
                        combiner.Add(ref modelData, modelMatrix);
                    }
                    else
                    {
                        // Add individual GameObject
                        go = GameObjectHelper.CreateDaggerfallMeshGameObject(obj.ModelIdNum, node.transform, dfUnity.Option_SetStaticFlags);
                        go.transform.position = modelMatrix.GetColumn(3);
                        go.transform.rotation = GameObjectHelper.QuaternionFromMatrix(modelMatrix);

                        // Update climate
                        DaggerfallMesh dfMesh = go.GetComponent <DaggerfallMesh>();
                        dfMesh.SetClimate(climateBase, climateSeason, WindowStyle.Disabled);
                    }
                }

                // Make ladder collider convex
                if (obj.ModelIdNum == ladderModelId)
                {
                    var meshCollider = go.GetComponent <MeshCollider>();
                    if (meshCollider)
                    {
                        meshCollider.convex = true;
                    }
                    go.AddComponent <DaggerfallLadder>();
                }

                // Optionally add action objects to specific furniture items (e.g. loot containers), except when laying out map (buildingType=AllValid)
                if (obj.ObjectType == propModelType && buildingData.buildingType != DFLocation.BuildingTypes.AllValid)
                {
                    AddFurnitureAction(obj, go, buildingData);
                }
            }

            // Add combined GameObject
            if (dfUnity.Option_CombineRMB)
            {
                if (combiner.VertexCount > 0)
                {
                    combiner.Apply();
                    GameObject go = GameObjectHelper.CreateCombinedMeshGameObject(combiner, "CombinedModels", node.transform, dfUnity.Option_SetStaticFlags);

                    // Update climate
                    DaggerfallMesh dfMesh = go.GetComponent <DaggerfallMesh>();
                    dfMesh.SetClimate(climateBase, climateSeason, WindowStyle.Disabled);
                }
            }

            // Add static doors component
            DaggerfallStaticDoors c = this.gameObject.AddComponent <DaggerfallStaticDoors>();

            c.Doors = doors.ToArray();
        }
Пример #27
0
        /// <summary>
        /// Add interior flats.
        /// </summary>
        private void AddFlats(PlayerGPS.DiscoveredBuilding buildingData)
        {
            GameObject node = new GameObject("Interior Flats");

            node.transform.parent = this.transform;

            // Add block flats
            markers.Clear();
            foreach (DFBlock.RmbBlockFlatObjectRecord obj in recordData.Interior.BlockFlatObjectRecords)
            {
                // Calculate position
                Vector3 billboardPosition = new Vector3(obj.XPos, -obj.YPos, obj.ZPos) * MeshReader.GlobalScale;

                // Import custom 3d gameobject instead of flat
                if (MeshReplacement.ImportCustomFlatGameobject(obj.TextureArchive, obj.TextureRecord, billboardPosition, node.transform) != null)
                {
                    continue;
                }

                // Spawn billboard gameobject
                GameObject go = GameObjectHelper.CreateDaggerfallBillboardGameObject(obj.TextureArchive, obj.TextureRecord, node.transform);

                // Set position
                DaggerfallBillboard dfBillboard = go.GetComponent <DaggerfallBillboard>();
                go.transform.position  = billboardPosition;
                go.transform.position += new Vector3(0, dfBillboard.Summary.Size.y / 2, 0);

                // Add editor markers to list
                if (obj.TextureArchive == TextureReader.EditorFlatsTextureArchive)
                {
                    InteriorEditorMarker marker = new InteriorEditorMarker();
                    marker.type       = (InteriorMarkerTypes)obj.TextureRecord;
                    marker.gameObject = go;
                    markers.Add(marker);

                    // Add loot containers for treasure markers (always use pile of clothes icon)
                    if (marker.type == InteriorMarkerTypes.Treasure)
                    {
                        // Create unique LoadID for save system, using 9 lsb and the sign bit from each coord pos int
                        ulong loadID = ((ulong)buildingData.buildingKey) << 30 |
                                       (uint)(obj.XPos << 1 & posMask) << 20 |
                                       (uint)(obj.YPos << 1 & posMask) << 10 |
                                       (uint)(obj.ZPos << 1 & posMask);

                        DaggerfallLoot loot = GameObjectHelper.CreateLootContainer(
                            LootContainerTypes.RandomTreasure,
                            InventoryContainerImages.Chest,
                            billboardPosition,
                            node.transform,
                            DaggerfallLootDataTables.clothingArchive,
                            0, loadID);

                        if (!LootTables.GenerateLoot(loot, (int)GameManager.Instance.PlayerGPS.CurrentLocationType))
                        {
                            DaggerfallUnity.LogMessage(string.Format("DaggerfallInterior: Location type {0} is out of range or unknown.", GameManager.Instance.PlayerGPS.CurrentLocationType), true);
                        }
                    }
                }

                // Add point lights
                if (obj.TextureArchive == TextureReader.LightsTextureArchive)
                {
                    AddLight(obj, go.transform);
                }
            }
        }
Пример #28
0
        private static void AddModels(
            DaggerfallUnity dfUnity,
            ref DFBlock blockData,
            out List <StaticDoor> doorsOut,
            out List <StaticBuilding> buildingsOut,
            ModelCombiner combiner = null,
            Transform parent       = null)
        {
            doorsOut     = new List <StaticDoor>();
            buildingsOut = new List <StaticBuilding>();

            // Iterate through all subrecords
            int recordCount = 0;

            foreach (DFBlock.RmbSubRecord subRecord in blockData.RmbBlock.SubRecords)
            {
                // Get subrecord transform
                Vector3   subRecordPosition = new Vector3(subRecord.XPos, 0, BlocksFile.RMBDimension - subRecord.ZPos) * MeshReader.GlobalScale;
                Vector3   subRecordRotation = new Vector3(0, -subRecord.YRotation / BlocksFile.RotationDivisor, 0);
                Matrix4x4 subRecordMatrix   = Matrix4x4.TRS(subRecordPosition, Quaternion.Euler(subRecordRotation), Vector3.one);

                // Iterate through models in this subrecord
                bool firstModel = true;
                foreach (DFBlock.RmbBlock3dObjectRecord obj in subRecord.Exterior.Block3dObjectRecords)
                {
                    // Get model transform
                    Vector3   modelPosition = new Vector3(obj.XPos, -obj.YPos, obj.ZPos) * MeshReader.GlobalScale;
                    Vector3   modelRotation = new Vector3(0, -obj.YRotation / BlocksFile.RotationDivisor, 0);
                    Matrix4x4 modelMatrix   = subRecordMatrix * Matrix4x4.TRS(modelPosition, Quaternion.Euler(modelRotation), Vector3.one);

                    // Get model data
                    ModelData modelData;
                    dfUnity.MeshReader.GetModelData(obj.ModelIdNum, out modelData);

                    // Does this model have doors?
                    if (modelData.Doors != null)
                    {
                        doorsOut.AddRange(GameObjectHelper.GetStaticDoors(ref modelData, blockData.Index, recordCount, modelMatrix));
                    }

                    // Store building information for first model of record
                    // First model is main record structure, others are attachments like posts
                    // Only main structure is needed to resolve building after hit-test
                    if (firstModel)
                    {
                        StaticBuilding staticBuilding = new StaticBuilding();
                        staticBuilding.modelMatrix = modelMatrix;
                        staticBuilding.recordIndex = recordCount;
                        staticBuilding.centre      = new Vector3(modelData.DFMesh.Centre.X, modelData.DFMesh.Centre.Y, modelData.DFMesh.Centre.Z) * MeshReader.GlobalScale;
                        staticBuilding.size        = new Vector3(modelData.DFMesh.Size.X, modelData.DFMesh.Size.Y, modelData.DFMesh.Size.Z) * MeshReader.GlobalScale;
                        buildingsOut.Add(staticBuilding);
                        firstModel = false;
                    }

                    // Import custom GameObject
                    if (MeshReplacement.ImportCustomGameobject(obj.ModelIdNum, parent, modelMatrix) != null)
                    {
                        continue;
                    }

                    // Use Daggerfall Model
                    // Add or combine
                    if (combiner == null || IsCityGate(obj.ModelIdNum))
                    {
                        AddStandaloneModel(dfUnity, ref modelData, modelMatrix, parent);
                    }
                    else
                    {
                        combiner.Add(ref modelData, modelMatrix);
                    }
                }

                // Increment record count
                recordCount++;
            }
        }
Пример #29
0
        public static GameObject CreatePlacedObject(PlacedObjectData_v2 data, Transform parent, bool previewGo = false)
        {
            // Custom models like Handpainted Models have insanley different scales (< 0.0 to 200+) Set all models as a child to a parent, so
            // EditMode can uniformly scale properly.

            GameObject parentGo = new GameObject();
            GameObject childGo;

            parentGo.transform.parent = parent;

            if (data.modelID == 0)
            {
                childGo = MeshReplacement.ImportCustomFlatGameobject(data.archive, data.record, Vector3.zero, parentGo.transform);

                if (childGo == null)
                {
                    childGo = GameObjectHelper.CreateDaggerfallBillboardGameObject(data.archive, data.record, parentGo.transform);
                }
            }
            else
            {
                Matrix4x4 matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3.one);

                childGo = MeshReplacement.ImportCustomGameobject(data.modelID, parentGo.transform, matrix);

                if (childGo == null)
                {
                    childGo = GameObjectHelper.CreateDaggerfallMeshGameObject(data.modelID, parentGo.transform);
                }
            }

            parentGo.transform.eulerAngles = Vector3.zero;
            childGo.transform.eulerAngles  = Vector3.zero;

            if (previewGo)
            {
                data.isLight = true;
            }

            BoxCollider parentCollider = parentGo.AddComponent <BoxCollider>();
            BoxCollider childCollider;


            //Expanding collider a little gives better hit detection.
            float buffer = 0.02f;

            // Some custom models have a box collider and are made of multiple smaller models. Get the parent collider size.
            if (childCollider = childGo.GetComponent <BoxCollider>())
            {
                parentCollider.size = new Vector3((childCollider.size.x * childGo.transform.localScale.x) + buffer,
                                                  (childCollider.size.y * childGo.transform.localScale.y) + buffer,
                                                  (childCollider.size.z * childGo.transform.localScale.z) + buffer);

                parentCollider.center = new Vector3(childCollider.center.x * childGo.transform.localScale.x,
                                                    childCollider.center.y * childGo.transform.localScale.y,
                                                    childCollider.center.z * childGo.transform.localScale.z);

                // Child colliders screw with EditMode.
                GameObject.Destroy(childCollider);
            }
            else
            {
                Bounds childBounds = childGo.GetComponent <MeshFilter>().sharedMesh.bounds;

                parentCollider.size = new Vector3((childBounds.size.x * childGo.transform.localScale.x) + buffer,
                                                  (childBounds.size.y * childGo.transform.localScale.y) + buffer,
                                                  (childBounds.size.z * childGo.transform.localScale.z) + buffer);

                parentCollider.center = new Vector3(childBounds.center.x * childGo.transform.localScale.x,
                                                    childBounds.center.y * childGo.transform.localScale.y,
                                                    childBounds.center.z * childGo.transform.localScale.z);
            }

            parentCollider.isTrigger = true;

            parentGo.AddComponent <PlacedObject>();
            SetPlacedObject(data, parentGo);

            return(parentGo);
        }
        public void RestoreSaveData(object dataIn)
        {
            if (!loot)
            {
                return;
            }

            LootContainerData_v1 data = (LootContainerData_v1)dataIn;

            if (data.loadID != LoadID)
            {
                return;
            }

            // Restore billboard only if this is a billboard-based loot container
            if (loot.ContainerType == LootContainerTypes.RandomTreasure ||
                loot.ContainerType == LootContainerTypes.CorpseMarker ||
                loot.ContainerType == LootContainerTypes.DroppedLoot)
            {
                DaggerfallBillboard billboard = loot.GetComponent <DaggerfallBillboard>();

                // Interiors and exteriors need special handling to ensure loot is always placed correctly for pre and post floating y saves
                // Dungeons are not involved with floating y and don't need any changes
                WorldContext lootContext = GetLootWorldContext(loot);
                if (lootContext == WorldContext.Interior)
                {
                    RestoreInteriorPositionHandler(loot, data, lootContext);
                }
                else if (lootContext == WorldContext.Exterior)
                {
                    RestoreExteriorPositionHandler(loot, data, lootContext);
                }
                else
                {
                    loot.transform.position = data.currentPosition;
                }

                // Restore appearance
                if (MeshReplacement.SwapCustomFlatGameobject(data.textureArchive, data.textureRecord, loot.transform, Vector3.zero, lootContext == WorldContext.Dungeon))
                {
                    // Use imported model instead of billboard
                    if (billboard)
                    {
                        Destroy(billboard);
                    }
                    Destroy(GetComponent <MeshRenderer>());
                }
                else if (billboard)
                {
                    // Restore billboard appearance if present
                    billboard.SetMaterial(data.textureArchive, data.textureRecord);
                }
            }

            // Restore items
            loot.Items.DeserializeItems(data.items);

            // Restore other data
            loot.ContainerType  = data.containerType;
            loot.ContainerImage = data.containerImage;
            loot.TextureArchive = data.textureArchive;
            loot.TextureRecord  = data.textureRecord;
            loot.stockedDate    = data.stockedDate;
            loot.playerOwned    = data.playerOwned;
            loot.customDrop     = data.customDrop;
            loot.entityName     = data.entityName;
            loot.isEnemyClass   = data.isEnemyClass;

            // Remove loot container if empty
            if (loot.Items.Count == 0)
            {
                GameObjectHelper.RemoveLootContainer(loot);
            }
        }