Beispiel #1
0
        /// <summary>
        /// Layout interior for automap based on data in exterior door and optional location for climate settings.
        /// </summary>
        /// <param name="doorOwner">Parent transform owning door array.</param>
        /// <param name="door">Exterior door player clicked on.</param>
        /// <returns>True if successful.</returns>
        public bool DoLayoutAutomap(Transform doorOwner, StaticDoor door, ClimateBases climateBase)
        {
            if (dfUnity == null)
            {
                dfUnity = DaggerfallUnity.Instance;
            }

            // Use specified climate
            this.climateBase = climateBase;

            // Save exterior information
            this.entryDoor = door;
            this.doorOwner = doorOwner;

            // Get block data
            blockData = dfUnity.ContentReader.BlockFileReader.GetBlock(door.blockIndex);
            if (blockData.Type != DFBlock.BlockTypes.Rmb)
            {
                throw new Exception(string.Format("Could not load RMB block index {0}", door.blockIndex), null);
            }

            // Get record data
            recordData = blockData.RmbBlock.SubRecords[door.recordIndex];
            if (recordData.Interior.Header.Num3dObjectRecords == 0)
            {
                throw new Exception(string.Format("No interior 3D models found for record index {0}", door.recordIndex), null);
            }

            // Layout interior data
            AddModels(mapBD);

            return(true);
        }
        /// <summary>
        /// Find closest door to player position in world space.
        /// Owner position and rotation must be set.
        /// </summary>
        /// <param name="playerPos">Player position in world space.</param>
        /// <param name="record">Door record index.</param>
        /// <param name="doorPosOut">Position of closest door in world space.</param>
        /// <param name="doorIndexOut">Door index in Doors array of closest door.</param>
        /// <returns></returns>
        public static bool FindClosestDoorToPlayer(Vector3 playerPos, StaticDoor[] doors, out Vector3 doorPosOut, out int doorIndexOut)
        {
            // Init output
            doorPosOut = playerPos;
            doorIndexOut = -1;

            // Must have door array
            if (doors == null || doors.Length == 0)
                return false;

            // Find closest door to player position
            float minDistance = float.MaxValue;
            for (int i = 0; i < doors.Length; i++)
            {
                // Get this door centre in world space
                Vector3 centre = doors[i].ownerRotation * doors[i].buildingMatrix.MultiplyPoint3x4(doors[i].centre) + doors[i].ownerPosition;

                // Check distance and save closest
                float distance = Vector3.Distance(playerPos, centre);
                if (distance < minDistance)
                {
                    doorPosOut = centre;
                    doorIndexOut = i;
                    minDistance = distance;
                }
            }

            return true;
        }
Beispiel #3
0
        /// <summary>
        /// Layout interior based on data in exterior door and optional location for climate settings.
        /// </summary>
        /// <param name="doorOwner">Parent transform owning door array.</param>
        /// <param name="door">Exterior door player clicked on.</param>
        /// <returns>True if successful.</returns>
        public bool DoLayout(Transform doorOwner, StaticDoor door, ClimateBases climateBase, PlayerGPS.DiscoveredBuilding buildingData)
        {
            if (dfUnity == null)
            {
                dfUnity = DaggerfallUnity.Instance;
            }

            // Use specified climate
            this.climateBase = climateBase;

            // Save exterior information
            this.entryDoor = door;
            this.doorOwner = doorOwner;

            AssignBlockData(door);

            // Layout interior data
            AddModels(buildingData);
            AddFlats(buildingData);
            AddPeople(buildingData);
            AddActionDoors();
            AddSpawnPoints();

            return(true);
        }
Beispiel #4
0
        /// <summary>
        /// Set block data corresponding to interior.
        /// </summary>
        private void AssignBlockData(StaticDoor door)
        {
            // Get block data
            DFLocation location = GameManager.Instance.PlayerGPS.CurrentLocation;

            DFBlock[] blocks;
            RMBLayout.GetLocationBuildingData(location, out blocks);
            bool foundBlock = false;

            for (int index = 0; index < blocks.Length && !foundBlock; ++index)
            {
                if (blocks[index].Index == door.blockIndex)
                {
                    this.blockData = blocks[index];
                    foundBlock     = true;
                }
            }

            if (!foundBlock || this.blockData.Type != DFBlock.BlockTypes.Rmb)
            {
                throw new Exception(string.Format("Could not load RMB block index {0}", door.blockIndex), null);
            }

            // Get record data
            recordData = blockData.RmbBlock.SubRecords[door.recordIndex];
            if (recordData.Interior.Header.Num3dObjectRecords == 0)
            {
                throw new Exception(string.Format("No interior 3D models found for record index {0}", door.recordIndex), null);
            }
        }
        /// <summary>
        /// Check for a door hit in world space.
        /// </summary>
        /// <param name="point">Hit point from ray test in world space.</param>
        /// <param name="doorOut">StaticDoor out if hit found.</param>
        /// <returns>True if point hits a static door.</returns>
        public bool HasHit(Vector3 point, out StaticDoor doorOut)
        {
            doorOut = new StaticDoor();
            if (Doors == null)
            {
                return(false);
            }

            // Using a single hidden trigger created when testing door positions
            // This avoids problems with AABBs as trigger rotates nicely with model transform
            // A trigger is also more useful for debugging as its drawn by editor
            GameObject go = new GameObject();

            go.hideFlags        = HideFlags.HideAndDontSave;
            go.transform.parent = transform;
            BoxCollider c = go.AddComponent <BoxCollider>();

            c.isTrigger = true;

            // Test each door in array
            bool found = false;

            for (int i = 0; i < Doors.Length; i++)
            {
                Quaternion buildingRotation = GameObjectHelper.QuaternionFromMatrix(Doors[i].buildingMatrix);
                Vector3    doorNormal       = buildingRotation * Doors[i].normal;
                Quaternion facingRotation   = Quaternion.LookRotation(doorNormal, Vector3.up);

                // Setup single trigger position and size over each door in turn
                // This method plays nice with transforms
                c.size = Doors[i].size;
                go.transform.parent    = transform;
                go.transform.position  = transform.rotation * Doors[i].buildingMatrix.MultiplyPoint3x4(Doors[i].centre);
                go.transform.position += transform.position;
                go.transform.rotation  = facingRotation;

                // Check if hit was inside trigger
                if (c.bounds.Contains(point))
                {
                    found   = true;
                    doorOut = Doors[i];
                    if (doorOut.doorType == DoorTypes.DungeonExit)
                    {
                        break;
                    }
                }
            }

            // Remove temp trigger
            if (go)
            {
                Destroy(go);
            }

            return(found);
        }
        /// <summary>
        /// Check for a door hit in world space.
        /// </summary>
        /// <param name="point">Hit point from ray test in world space.</param>
        /// <param name="doorOut">StaticDoor out if hit found.</param>
        /// <returns>True if point hits a static door.</returns>
        public bool HasHit(Vector3 point, out StaticDoor doorOut)
        {
            doorOut = new StaticDoor();
            if (Doors == null)
            {
                return(false);
            }

            // Using a single hidden trigger created when testing door positions
            // This avoids problems with AABBs as trigger rotates nicely with model transform
            // A trigger is also more useful for debugging as its drawn by editor
            GameObject go = new GameObject();

            go.hideFlags        = HideFlags.HideAndDontSave;
            go.transform.parent = transform;
            BoxCollider c = go.AddComponent <BoxCollider>();

            c.isTrigger = true;

            // Test each door in array
            bool found = false;

            for (int i = 0; i < Doors.Length; i++)
            {
                // Setup single trigger position and size over each door in turn
                // This method plays nice with transforms
                c.size = GameObjectHelper.QuaternionFromMatrix(Doors[i].buildingMatrix) * Doors[i].size;
                go.transform.position  = transform.rotation * Doors[i].buildingMatrix.MultiplyPoint3x4(Doors[i].centre);
                go.transform.position += transform.position;
                go.transform.rotation  = transform.rotation;

                // Sometimes doors injected from mods don't trigger because hit point is not exactly
                // on the plane calculated from classic door data so we ensure the collider has some depth
                if (c.size.x < 1)
                {
                    c.size = new Vector3(1, c.size.y, c.size.z);
                }

                // Check if hit was inside trigger
                if (c.bounds.Contains(point))
                {
                    found   = true;
                    doorOut = Doors[i];
                    break;
                }
            }

            // Remove temp trigger
            if (go)
            {
                Destroy(go);
            }

            return(found);
        }
Beispiel #7
0
        /// <summary>
        /// Check for a door hit in world space.
        /// </summary>
        /// <param name="point">Hit point from ray test in world space.</param>
        /// <param name="doorOut">StaticDoor out if hit found.</param>
        /// <returns>True if point hits a static door.</returns>
        public bool HasHit(Vector3 point, out StaticDoor doorOut)
        {
            doorOut = new StaticDoor();
            if (Doors == null)
            {
                return(false);
            }

            // Using a single hidden trigger created when testing door positions
            // This avoids problems with AABBs as trigger rotates nicely with model transform
            // A trigger is also more useful for debugging as its drawn by editor
            GameObject go = new GameObject();

            go.hideFlags        = HideFlags.HideAndDontSave;
            go.transform.parent = transform;
            BoxCollider c = go.AddComponent <BoxCollider>();

            c.isTrigger = true;

            // Test each door in array
            bool found = false;

            for (int i = 0; i < Doors.Length; i++)
            {
                // Setup single trigger position and size over each door in turn
                // This method plays nice with transforms
                go.transform.position = transform.rotation * Doors[i].buildingMatrix.MultiplyPoint3x4(Doors[i].centre);
                c.size = GameObjectHelper.QuaternionFromMatrix(Doors[i].buildingMatrix) * Doors[i].size;
                go.transform.position += transform.position;
                go.transform.rotation  = transform.rotation;

                // Deprecated: Bounds checking method.
                //Vector3 centre = transform.rotation * Doors[i].buildingMatrix.MultiplyPoint3x4(Doors[i].centre) + transform.position;
                //Vector3 size = new Vector3(50, 90, 50) * MeshReader.GlobalScale; // Native door fit
                //Bounds bounds = new Bounds(centre, size);

                // Check if hit was inside trigger
                if (c.bounds.Contains(point))
                {
                    found   = true;
                    doorOut = Doors[i];
                    break;
                }
            }

            // Remove temp trigger
            if (go)
            {
                Destroy(go);
            }

            return(found);
        }
        /// <summary>
        /// Finds all doors of type across multiple door collections.
        /// </summary>
        /// <param name="doorCollections">Door collections.</param>
        /// <param name="type">Type of door to search for.</param>
        /// <returns>Array of matching doors.</returns>
        public static StaticDoor[] FindDoorsInCollections(DaggerfallStaticDoors[] doorCollections, DoorTypes type)
        {
            List <StaticDoor> doorsOut = new List <StaticDoor>();

            foreach (var collection in doorCollections)
            {
                for (int i = 0; i < collection.Doors.Length; i++)
                {
                    if (collection.Doors[i].doorType == type)
                    {
                        StaticDoor newDoor = collection.Doors[i];
                        newDoor.ownerPosition = collection.transform.position;
                        newDoor.ownerRotation = collection.transform.rotation;
                        doorsOut.Add(newDoor);
                    }
                }
            }

            return(doorsOut.ToArray());
        }
Beispiel #9
0
        /// <summary>
        /// Layout interior for automap based on data in exterior door and optional location for climate settings.
        /// </summary>
        /// <param name="doorOwner">Parent transform owning door array.</param>
        /// <param name="door">Exterior door player clicked on.</param>
        /// <returns>True if successful.</returns>
        public bool DoLayoutAutomap(Transform doorOwner, StaticDoor door, ClimateBases climateBase)
        {
            if (dfUnity == null)
            {
                dfUnity = DaggerfallUnity.Instance;
            }

            // Use specified climate
            this.climateBase = climateBase;

            // Save exterior information
            this.entryDoor = door;
            this.doorOwner = doorOwner;

            AssignBlockData(door);

            // Layout interior data
            AddModels(mapBD);

            return(true);
        }
        public StaticDoor[] Doors; // Array of doors attached this building or group of buildings

        #endregion Fields

        #region Methods

        /// <summary>
        /// Finds closest door in any array of static doors.
        /// Owner position and rotation must be set.
        /// </summary>
        /// <param name="position">Position to find closest door to.</param>
        /// <param name="doors">Door array.</param>
        /// <returns>Position of closest door in world space.</returns>
        public static Vector3 FindClosestDoor(Vector3 position, StaticDoor[] doors, out StaticDoor closestDoorOut)
        {
            closestDoorOut = new StaticDoor();
            Vector3 closestDoorPos = position;
            float minDistance = float.MaxValue;
            for (int i = 0; i < doors.Length; i++)
            {
                // Get this door centre in world space
                Vector3 centre = doors[i].ownerRotation * doors[i].buildingMatrix.MultiplyPoint3x4(doors[i].centre) + doors[i].ownerPosition;

                // Check distance and store closest
                float distance = Vector3.Distance(position, centre);
                if (distance < minDistance)
                {
                    closestDoorPos = centre;
                    minDistance = distance;
                    closestDoorOut = doors[i];
                }
            }

            return closestDoorPos;
        }
        /// <summary>
        /// Finds closest door in any array of static doors.
        /// Owner position and rotation must be set.
        /// </summary>
        /// <param name="position">Position to find closest door to.</param>
        /// <param name="doors">Door array.</param>
        /// <returns>Position of closest door in world space.</returns>
        public static Vector3 FindClosestDoor(Vector3 position, StaticDoor[] doors, out StaticDoor closestDoorOut)
        {
            closestDoorOut = new StaticDoor();
            Vector3 closestDoorPos = position;
            float   minDistance    = float.MaxValue;

            for (int i = 0; i < doors.Length; i++)
            {
                // Get this door centre in world space
                Vector3 centre = doors[i].ownerRotation * doors[i].buildingMatrix.MultiplyPoint3x4(doors[i].centre) + doors[i].ownerPosition;

                // Check distance and store closest
                float distance = Vector3.Distance(position, centre);
                if (distance < minDistance)
                {
                    closestDoorPos = centre;
                    minDistance    = distance;
                    closestDoorOut = doors[i];
                }
            }

            return(closestDoorPos);
        }
        /// <summary>
        /// Check for a door hit in world space.
        /// </summary>
        /// <param name="point">Hit point from ray test in world space.</param>
        /// <param name="doorOut">StaticDoor out if hit found.</param>
        /// <returns>True if point hits a static door.</returns>
        public bool HasHit(Vector3 point, out StaticDoor doorOut)
        {
            doorOut = new StaticDoor();
            if (Doors == null)
                return false;

            // Using a single hidden trigger created when testing door positions
            // This avoids problems with AABBs as trigger rotates nicely with model transform
            // A trigger is also more useful for debugging as its drawn by editor
            GameObject go = new GameObject();
            go.hideFlags = HideFlags.HideAndDontSave;
            go.transform.parent = transform;
            BoxCollider c = go.AddComponent<BoxCollider>();
            c.isTrigger = true;

            // Test each door in array
            bool found = false;
            for (int i = 0; i < Doors.Length; i++)
            {
                // Setup single trigger position and size over each door in turn
                // This method plays nice with transforms
                c.size = GameObjectHelper.QuaternionFromMatrix(Doors[i].buildingMatrix) * Doors[i].size;
                go.transform.position = transform.rotation * Doors[i].buildingMatrix.MultiplyPoint3x4(Doors[i].centre);
                go.transform.position += transform.position;
                go.transform.rotation = transform.rotation;

                // Check if hit was inside trigger
                if (c.bounds.Contains(point))
                {
                    found = true;
                    doorOut = Doors[i];
                    break;
                }
            }

            // Remove temp trigger
            if (go)
                Destroy(go);

            return found;
        }
 /// <summary>
 /// Gets door normal in world space.
 /// Owner position and rotation must be set.
 /// </summary>
 /// <param name="door">Door to calculate normal for.</param>
 /// <returns>Normal pointing away from door in world.</returns>
 public static Vector3 GetDoorNormal(StaticDoor door)
 {
     return(Vector3.Normalize(door.ownerRotation * door.buildingMatrix.MultiplyVector(door.normal)));
 }
        /// <summary>
        /// Gets door position in world space.
        /// Owner position and rotation must be set.
        /// </summary>
        /// <param name="index">Door index.</param>
        /// <returns>Door position in world space.</returns>
        public static Vector3 GetDoorPosition(StaticDoor door)
        {
            Vector3 centre = door.ownerRotation * door.buildingMatrix.MultiplyPoint3x4(door.centre) + door.ownerPosition;

            return(centre);
        }
        /// <summary>
        /// Gets door position in world space.
        /// Owner position and rotation must be set.
        /// </summary>
        /// <param name="index">Door index.</param>
        /// <returns>Door position in world space.</returns>
        public static Vector3 GetDoorPosition(StaticDoor door)
        {
            Vector3 centre = door.ownerRotation * door.buildingMatrix.MultiplyPoint3x4(door.centre) + door.ownerPosition;

            return centre;
        }
        /// <summary>
        /// Layout interior based on data in exterior door and optional location for climate settings.
        /// </summary>
        /// <param name="doorOwner">Parent transform owning door array.</param>
        /// <param name="door">Exterior door player clicked on.</param>
        /// <returns>True if successful.</returns>
        public bool DoLayout(Transform doorOwner, StaticDoor door, ClimateBases climateBase)
        {
            if (dfUnity == null)
                dfUnity = DaggerfallUnity.Instance;

            // Use specified climate
            this.climateBase = climateBase;

            // Save exterior information
            this.entryDoor = door;
            this.doorOwner = doorOwner;

            // Get block data
            blockData = dfUnity.ContentReader.BlockFileReader.GetBlock(door.blockIndex);
            if (blockData.Type != DFBlock.BlockTypes.Rmb)
                throw new Exception(string.Format("Could not load RMB block index {0}", door.blockIndex), null);

            // Get record data
            recordData = blockData.RmbBlock.SubRecords[door.recordIndex];
            if (recordData.Interior.Header.Num3dObjectRecords == 0)
                throw new Exception(string.Format("No interior 3D models found for record index {0}", door.recordIndex), null);

            // Layout interior data
            AddModels();
            AddFlats();
            AddPeople();
            AddActionDoors();

            return true;
        }
 void InitWhenInInteriorOrDungeon(StaticDoor? door = null, bool initFromLoadingSave = false)
 {
     if ((GameManager.Instance.IsPlayerInsideBuilding) && (door.HasValue))
     {
         createIndoorGeometryForAutomap(door.Value);
         restoreStateAutomapDungeon(true);
         resetAutomapSettingsFromExternalScript = true; // set flag so external script (DaggerfallAutomapWindow) can pull flag and reset automap values on next window push
         gameobjectGeometry.SetActive(false);
         gameobjectBeacons.SetActive(false);
     }
     else if ((GameManager.Instance.IsPlayerInsideDungeon) || (GameManager.Instance.IsPlayerInsidePalace))
     {
         createDungeonGeometryForAutomap();
         restoreStateAutomapDungeon(!initFromLoadingSave); // if a save game was loaded, do not reset the revisited state (don't set parameter forceNotVisitedInThisRun to true)
         resetAutomapSettingsFromExternalScript = true; // set flag so external script (DaggerfallAutomapWindow) can pull flag and reset automap values on next window push
         gameobjectGeometry.SetActive(false);
         gameobjectBeacons.SetActive(false);
     }
     else
     {
         Debug.LogError("Error in function InitWhenInInteriorOrDungeon: reached forbidden control flow point");
     }
 }
        /// <summary>
        /// creates the indoor geometry used for automap rendering
        /// </summary>
        /// <param name="args"> the static door for loading the correct interior </param>
        private void createIndoorGeometryForAutomap(StaticDoor door)
        {
            String newGeometryName = string.Format("DaggerfallInterior [Block={0}, Record={1}]", door.blockIndex, door.recordIndex);

            if (gameobjectGeometry != null)
            {
                UnityEngine.Object.Destroy(gameobjectGeometry);
                gameobjectGeometry = null;
            }

            gameobjectGeometry = new GameObject("GeometryAutomap (Interior)");

            foreach (Transform elem in GameManager.Instance.InteriorParent.transform)
            {
                if (elem.name.Contains("DaggerfallInterior"))
                {
                    // Get climate
                    ClimateBases climateBase = ClimateBases.Temperate;
                    climateBase = ClimateSwaps.FromAPIClimateBase(GameManager.Instance.PlayerGPS.ClimateSettings.ClimateType);

                    // Layout interior
                    GameObject gameobjectInterior = new GameObject(newGeometryName);
                    DaggerfallInterior interior = gameobjectInterior.AddComponent<DaggerfallInterior>();

                    // automap layout is a simplified layout in contrast to normal layout (less objects)
                    interior.DoLayoutAutomap(null, door, climateBase);

                    gameobjectInterior.transform.SetParent(gameobjectGeometry.transform);

                    // copy position and rotation from real level geometry
                    gameobjectGeometry.transform.position = elem.transform.position;
                    gameobjectGeometry.transform.rotation = elem.transform.rotation;

                    // do this (here in createIndoorGeometryForAutomap()) analog in the same way and the same place like in createDungeonGeometryForAutomap()
                    setupBeacons();
                }
            }

            // put all objects inside gameobjectGeometry in layer "Automap"
            SetLayerRecursively(gameobjectGeometry, layerAutomap);
            gameobjectGeometry.transform.SetParent(gameobjectAutomap.transform);

            // inject all materials of automap geometry with automap shader and reset MeshRenderer enabled state (this is used for the discovery mechanism)
            injectMeshAndMaterialProperties();

            //oldGeometryName = newGeometryName;
        }
Beispiel #19
0
 /// <summary>
 /// Gets the scene name for the interior behind the given door.
 /// </summary>
 public static string GetSceneName(DFLocation location, StaticDoor door)
 {
     return(GetSceneName(location.MapTableData.MapId, door.buildingKey));
 }
 /// <summary>
 /// Gets door normal in world space.
 /// Owner position and rotation must be set.
 /// </summary>
 /// <param name="door">Door to calculate normal for.</param>
 /// <returns>Normal pointing away from door in world.</returns>
 public static Vector3 GetDoorNormal(StaticDoor door)
 {
     return Vector3.Normalize(door.ownerRotation * door.buildingMatrix.MultiplyVector(door.normal));
 }