예제 #1
0
 /// <summary>Constructor.</summary>
 public TransitionEventArgs()
 {
     TransitionType     = PlayerEnterExit.TransitionType.NotDefined;
     StaticDoor         = new StaticDoor();
     DaggerfallInterior = null;
     DaggerfallDungeon  = null;
 }
예제 #2
0
        /// <summary>
        /// Set static door data to all doors in the given building gameobject.
        /// </summary>
        /// <param name="building">The imported gameobject which provides building and doors.</param>
        /// <param name="staticDoors">The list of static doors for the vanilla building.</param>
        /// <param name="buildingKey">The key of the building that owns the doors.</param>
        /// <param name="dontCreateStaticDoors">If true, custom door components request to suppress classic doors.</param>
        public static void InitDoors(GameObject building, StaticDoor[] staticDoors, int buildingKey, out bool dontCreateStaticDoors)
        {
            dontCreateStaticDoors = false;
            // Set data to all doors in the building
            CustomDoor[] allCustomDoors = building.GetComponentsInChildren <CustomDoor>();
            for (int i = 0; i < allCustomDoors.Length; i++)
            {
                if (allCustomDoors[i].DisableClassicDoors == true)
                {
                    dontCreateStaticDoors = true;
                }

                if ((allCustomDoors[i].StaticDoorCopied < 0) || (allCustomDoors[i].StaticDoorCopied > staticDoors.Length))
                {
                    string objectName;
                    if (allCustomDoors[i].name == "default")
                    {
                        objectName = allCustomDoors[i].transform.parent.name + "\\default";
                    }
                    else
                    {
                        objectName = allCustomDoors[i].name;
                    }
                    Debug.LogErrorFormat("StaticDoorCopied for model {0} is outside the valid range for it's Static Door array. Defaulting to 0", objectName);
                    allCustomDoors[i].StaticDoorCopied = 0;
                }
                // Make data for the static door; only the common data for the building is needed.
                StaticDoor staticDoor = staticDoors[allCustomDoors[i].StaticDoorCopied];
                staticDoor.buildingKey = buildingKey;

                allCustomDoors[i].staticDoor = staticDoor;
            }
        }
        /// <summary>
        /// Transition player through a dungeon entrance door into dungeon interior.
        /// </summary>
        /// <param name="doorOwner">Parent transform owning door array.</param>
        /// <param name="door">Exterior door player clicked on.</param>
        public void TransitionDungeonInterior(Transform doorOwner, StaticDoor door, DFLocation location)
        {
            // Ensure we have component references
            if (!ReferenceComponents())
            {
                return;
            }

            // Layout dungeon
            GameObject newDungeon = GameObjectHelper.CreateDaggerfallDungeonGameObject(location, DungeonParent.transform);

            newDungeon.hideFlags = HideFlags.HideAndDontSave;
            dungeon = newDungeon.GetComponent <DaggerfallDungeon>();

            // Find start marker to position player
            if (!dungeon.StartMarker)
            {
                // Could not find a start marker
                Destroy(newDungeon);
                return;
            }

            // Cache player starting position and facing to use on exit
            dungeonEntrancePosition = transform.position;
            dungeonEntranceForward  = transform.forward;

            // Disable exterior parent
            if (ExteriorParent != null)
            {
                ExteriorParent.SetActive(false);
            }

            // Enable dungeon parent
            if (DungeonParent != null)
            {
                DungeonParent.SetActive(true);
            }

            // Set player to start position
            transform.position = dungeon.StartMarker.transform.position + Vector3.up * (controller.height * 0.6f);

            //// TODO: Find closest exit door to orient player
            //DaggerfallStaticDoors doors = newDungeon.GetComponent<DaggerfallStaticDoors>();
            //if (doors)
            //{
            //    Vector3 doorPos;
            //    int doorIndex;
            //    if (doors.FindClosestDoorToPlayer(transform.position, 0, out doorPos, out doorIndex))
            //    {
            //    }
            //}

            // Fix player standing
            SetStanding();

            // Player is now inside dungeon
            isPlayerInside        = true;
            isPlayerInsideDungeon = true;
        }
예제 #4
0
 /// <summary>Constructor helper.</summary>
 public TransitionEventArgs(TransitionType transitionType, StaticDoor staticDoor, DaggerfallInterior daggerfallInterior = null, DaggerfallDungeon daggerfallDungeon = null)
     : base()
 {
     this.TransitionType     = transitionType;
     this.StaticDoor         = staticDoor;
     this.DaggerfallInterior = daggerfallInterior;
     this.DaggerfallDungeon  = daggerfallDungeon;
 }
예제 #5
0
        protected virtual void RaiseOnTransitionInteriorEvent(StaticDoor staticDoor, DaggerfallInterior daggerfallInterior)
        {
            TransitionEventArgs args = new TransitionEventArgs(TransitionType.ToBuildingInterior, staticDoor, daggerfallInterior);

            if (OnTransitionInterior != null)
            {
                OnTransitionInterior(args);
            }
        }
예제 #6
0
        protected virtual void RaiseOnTransitionDungeonInteriorEvent(StaticDoor staticDoor, DaggerfallDungeon daggerfallDungeon)
        {
            TransitionEventArgs args = new TransitionEventArgs(TransitionType.ToDungeonInterior, staticDoor, null, daggerfallDungeon);

            if (OnTransitionDungeonInterior != null)
            {
                OnTransitionDungeonInterior(args);
            }
        }
예제 #7
0
        /// <summary>
        /// Starts player inside building with no exterior world.
        /// </summary>
        public void StartBuildingInterior(DFLocation location, StaticDoor exteriorDoor)
        {
            // Ensure we have component references
            if (!ReferenceComponents())
            {
                return;
            }

            TransitionInterior(null, exteriorDoor);
        }
예제 #8
0
        /// <summary>
        /// Starts player inside building with no exterior world.
        /// </summary>
        public void StartBuildingInterior(DFLocation location, StaticDoor exteriorDoor)
        {
            // Ensure we have component references
            if (!ReferenceComponents())
            {
                return;
            }

            // Discover building
            GameManager.Instance.PlayerGPS.DiscoverBuilding(exteriorDoor.buildingKey);

            TransitionInterior(null, exteriorDoor);
        }
예제 #9
0
        /// <summary>
        /// Set static door data to all doors in the given building gameobject.
        /// </summary>
        /// <param name="building">The imported gameobject which provides building and doors.</param>
        /// <param name="staticDoors">The list of static doors for the vanilla building.</param>
        /// <param name="buildingKey">The key of the building that owns the doors.</param>
        public static void InitDoors(GameObject building, StaticDoor[] staticDoors, int buildingKey)
        {
            // Make data for the static door; only the common data for the building is needed.
            StaticDoor staticDoor = staticDoors[0];

            staticDoor.buildingKey = buildingKey;

            // Set data to all doors in the building
            var doors = building.GetComponentsInChildren <CustomDoor>();

            for (int i = 0; i < doors.Length; i++)
            {
                doors[i].staticDoor = staticDoor;
            }
        }
예제 #10
0
        /// <summary>
        /// Transition player through a dungeon entrance door into dungeon interior.
        /// </summary>
        /// <param name="doorOwner">Parent transform owning door array.</param>
        /// <param name="door">Exterior door player clicked on.</param>
        public void TransitionDungeonInterior(Transform doorOwner, StaticDoor door, DFLocation location)
        {
            // Ensure we have component references
            if (!ReferenceComponents())
            {
                return;
            }

            // Layout dungeon
            GameObject newDungeon = GameObjectHelper.CreateDaggerfallDungeonGameObject(location, DungeonParent.transform);

            newDungeon.hideFlags = HideFlags.HideAndDontSave;
            dungeon = newDungeon.GetComponent <DaggerfallDungeon>();

            // Find start marker to position player
            if (!dungeon.StartMarker)
            {
                // Could not find a start marker
                Destroy(newDungeon);
                return;
            }

            // Cache player starting position and facing to use on exit
            dungeonEntrancePosition = transform.position;
            dungeonEntranceForward  = transform.forward;

            // Disable exterior parent
            if (ExteriorParent != null)
            {
                ExteriorParent.SetActive(false);
            }

            // Enable dungeon parent
            if (DungeonParent != null)
            {
                DungeonParent.SetActive(true);
            }

            // Set player to start position
            // Not sure how to set facing here as player transitions to a marker, not a door
            // Could always find closest exit door and use that
            transform.position = dungeon.StartMarker.transform.position + Vector3.up * (controller.height * 0.6f);
            SetStanding();

            // Player is now inside dungeon
            isPlayerInside        = true;
            isPlayerInsideDungeon = true;
        }
        /// <summary>
        /// Transition player through a dungeon entrance door into dungeon interior.
        /// </summary>
        /// <param name="doorOwner">Parent transform owning door array.</param>
        /// <param name="door">Exterior door player clicked on.</param>
        public void TransitionDungeonInterior(Transform doorOwner, StaticDoor door, DFLocation location)
        {
            // Ensure we have component references
            if (!ReferenceComponents())
            {
                return;
            }

            // Layout dungeon
            GameObject newDungeon = GameObjectHelper.CreateDaggerfallDungeonGameObject(location, DungeonParent.transform);

            newDungeon.hideFlags = HideFlags.HideAndDontSave;
            dungeon = newDungeon.GetComponent <DaggerfallDungeon>();

            // Find start marker to position player
            if (!dungeon.StartMarker)
            {
                // Could not find a start marker
                Destroy(newDungeon);
                return;
            }

            // Cache player starting position and facing to use on exit
            dungeonEntrancePosition = transform.position;
            dungeonEntranceForward  = transform.forward;

            // Disable exterior parent
            if (ExteriorParent != null)
            {
                ExteriorParent.SetActive(false);
            }

            // Enable dungeon parent
            if (DungeonParent != null)
            {
                DungeonParent.SetActive(true);
            }

            // Player is now inside dungeon
            isPlayerInside        = true;
            isPlayerInsideDungeon = true;

            // Set to start position
            MovePlayerToDungeonStart();
        }
예제 #12
0
        /// <summary>
        /// Checks for a door hit.
        /// </summary>
        /// <param name="raycastHit">The raycast result.</param>
        /// <param name="door">The door found at hit position.</param>
        /// <returns>True if a door has been hit.</returns>
        /// <remarks>
        /// Modders should ensure that the CustomDoor component is added to the right gameobject.
        /// This allows to avoid unnecessary seeks on parent/children, which are potentially performance heavy.
        /// </remarks>
        public static bool HasHit(RaycastHit raycastHit, out StaticDoor door)
        {
            var doors = raycastHit.transform.GetComponents <CustomDoor>();

            for (int i = 0; i < doors.Length; i++)
            {
                if (doors[i].DoorTrigger.bounds.Contains(raycastHit.point))
                {
                    if (doors[i].staticDoor.HasValue)
                    {
                        door = doors[i].staticDoor.Value;
                        return(true);
                    }

                    Debug.LogErrorFormat("Static door for {0} is not set.", raycastHit.transform.name);
                }
            }

            door = new StaticDoor();
            return(false);
        }
예제 #13
0
        /// <summary>
        /// Gets static door array from door information stored in model data.
        /// </summary>
        /// <param name="modelData">Model data for doors.</param>
        /// <param name="blockIndex">Block index for RMB doors.</param>
        /// <param name="recordIndex">Record index of interior.</param>
        /// <param name="buildingMatrix">Individual building matrix.</param>
        /// <returns>Array of doors in this model data.</returns>
        public static StaticDoor[] GetStaticDoors(ref ModelData modelData, int blockIndex, int recordIndex, Matrix4x4 buildingMatrix)
        {
            // Exit if no doors
            if (modelData.Doors == null)
            {
                return(null);
            }

            // Add door triggers
            StaticDoor[] staticDoors = new StaticDoor[modelData.Doors.Length];
            for (int i = 0; i < modelData.Doors.Length; i++)
            {
                // Get door and diagonal verts
                ModelDoor door = modelData.Doors[i];
                Vector3   v0   = door.Vert0;
                Vector3   v2   = door.Vert2;

                // Get door size
                const float thickness = 0.025f;
                Vector3     size      = new Vector3(v2.x - v0.x, v2.y - v0.y, v2.z - v0.z) + door.Normal * thickness;

                // Add door to array
                StaticDoor newDoor = new StaticDoor()
                {
                    buildingMatrix = buildingMatrix,
                    doorType       = door.Type,
                    blockIndex     = blockIndex,
                    recordIndex    = recordIndex,
                    doorIndex      = door.Index,
                    centre         = (v0 + v2) / 2f,
                    normal         = door.Normal,
                    size           = size,
                };
                staticDoors[i] = newDoor;
            }

            return(staticDoors);
        }
예제 #14
0
        // Custom transition to store building data before entering building
        private void TransitionInterior(Transform doorOwner, StaticDoor door, bool doFade = false)
        {
            // Get building directory for location
            BuildingDirectory buildingDirectory = GameManager.Instance.StreamingWorld.GetCurrentBuildingDirectory();

            if (!buildingDirectory)
            {
                Debug.LogError("PlayerActivate.TransitionInterior() could not retrieve BuildingDirectory.");
                return;
            }

            // Get building discovery data - this is added when player clicks door at exterior
            PlayerGPS.DiscoveredBuilding db;
            if (!GameManager.Instance.PlayerGPS.GetDiscoveredBuilding(door.buildingKey, out db))
            {
                Debug.LogErrorFormat("PlayerActivate.TransitionInterior() could not retrieve DiscoveredBuilding for key {0}.", door.buildingKey);
                return;
            }

            // Perform transition
            playerEnterExit.BuildingDiscoveryData = db;
            playerEnterExit.TransitionInterior(doorOwner, door, doFade);
        }
예제 #15
0
        /// <summary>
        /// Transition player through an exterior door into building interior.
        /// </summary>
        /// <param name="doorOwner">Parent transform owning door array.</param>
        /// <param name="door">Exterior door player clicked on.</param>
        public void TransitionInterior(Transform doorOwner, StaticDoor door)
        {
            // Ensure we have component references
            if (!ReferenceComponents())
                return;

            // Raise event
            RaiseOnPreTransitionEvent(TransitionType.ToBuildingInterior, door);

            // Get climate
            ClimateBases climateBase = ClimateBases.Temperate;
            if (OverrideLocation)
            {
                climateBase = OverrideLocation.Summary.Climate;
            }
            else if (playerGPS)
            {
                climateBase = ClimateSwaps.FromAPIClimateBase(playerGPS.ClimateSettings.ClimateType);
            }

            // Layout interior
            // This needs to be done first so we know where the enter markers are
            GameObject newInterior = new GameObject(string.Format("DaggerfallInterior [Block={0}, Record={1}]", door.blockIndex, door.recordIndex));
            newInterior.hideFlags = HideFlags.HideAndDontSave;
            interior = newInterior.AddComponent<DaggerfallInterior>();
            interior.DoLayout(doorOwner, door, climateBase);

            // Position interior directly inside of exterior
            // This helps with finding closest enter/exit point relative to player position
            interior.transform.position = doorOwner.position + (Vector3)door.buildingMatrix.GetColumn(3);
            interior.transform.rotation = GameObjectHelper.QuaternionFromMatrix(door.buildingMatrix);

            // Position player above closest enter marker
            Vector3 marker;
            if (!interior.FindClosestEnterMarker(transform.position, out marker))
            {
                // Could not find an enter marker, probably not a valid interior
                Destroy(newInterior);
                return;
            }

            // Assign new interior to parent
            if (InteriorParent != null)
                newInterior.transform.parent = InteriorParent.transform;

            // Disable exterior parent
            if (ExteriorParent != null)
                ExteriorParent.SetActive(false);

            // Enable interior parent
            if (InteriorParent != null)
                InteriorParent.SetActive(true);

            // Cache some information about this interior
            buildingType = interior.BuildingData.BuildingType;

            // Set player to marker position
            // Not sure how to set facing here as player transitions to a marker, not a door
            // Could always find closest door and use that
            transform.position = marker + Vector3.up * (controller.height * 0.6f);
            SetStanding();

            // Player is now inside building
            isPlayerInside = true;

            // Raise event
            RaiseOnTransitionInteriorEvent(door, interior);
        }
    /// <summary>
    /// Prints debug buttons for editor at bottom.
    /// </summary>
    void PrintDebugEditorButtons()
    {
        EditorGUILayout.BeginVertical(GUILayout.ExpandWidth(false));

        float buttonWidth  = 400;
        float buttonHeight = 30;

        // Map Tile Location, or Interior or Dungeon  Tabs

        // Two options: Select then Replace/Insert
        // This zooms map to locations or blocks and allows user to replace or add entry to a location


        // Dungeon Layout
        // Dungeon Block
        // Door
        // Model / Flat / Event

        // Option 2: Import Location - Bring up the area first, then pick where to insert it
        // If Dungeon
        // Replace existing location or add new location
        // Add new location loads a dungeon layout, must have exit(s) the lead to location(s), but with
        // If add new location needs an above ground entrance with a map tile or keyed door
        // Verifies all features that need to be in area.  Modifies prefab

        // Mod adds interruption in between specific location doors or when streaming a tile

        // Dungeon
        // Data for dungeon
        // Dropdown on how to access it
        // Override existing place (with mod)
        // key a specific door
        // Scripted command (Dialog, falling down a pit, or if you have another area that will reference it later)
        // Key to a generated location
        // backup area to send person to if it doesn't work.

        //DFLocation
        // DaggerfallLocation
        // RUNTIME
        // May be in DaggerFall unity during runtime
        // Playerenterexit has a location override
        // Dungeon --> DaggerfallDungeon  monobehaviour
        // chidren have list of dungeon blocks and enemies
        // has location textures
        // When dungeon is gone it is removed from the dungeon branch
        // Outdoor locations have list of doors, which are automaticlaly mapped onto the terrain
        // DaggerfallStaticDoors

        // Location contains a dungeon
        // Has a block index in the static doors list - Block index in BLOCKS.BSA
        // Record index is for a specific interior (like shop or home)
        // each location(site) is marked on the world map.  Each site can have a number of exterior blocks, and
        // a dungeon attached to it.
        // Everything for transport is in player enter exit
        // DFLocation.RegionMapTable
        //locationdungeon
        // Has array of dungeonblock
        // !! Must overwrite a normal dungeon block with a more base form.
        // That must simulate any features a normal dungeon would have for compatibility.
        // LocationIndex?

        // ?? Where is the index of locations you can intercept for mods? Based on GPS?
        // Can you intercept a transition request event?
        // Requests to Maps.bsa
        // DFValidator:152  // Supports alternate MAPS.BSA from Resources if available


        // MODIFY THE LOCATIONS INDEX
        // Have our own data file that has overwrites for regions already.
        // Each data point is driven by a mod.  Use the mod's loading order and existing locations to ensure no overwrites
        // Have the "final" modified version of the additional map data parsed.
        // 1.) Wait until the maps file is loaded.
        // Use the start mod events unless better are found.
        // 2.) Then edit the maps file index in memory
        // 3.) Then reload the existing area if needed
        // ?? Content Reader Get Location is used, how to overwrite that?  Does it mandate use of the data file?


        // Modify mapsfile.cs  region record add the new region index in or change it

        if (GUILayout.Button("Teleport Player to test dungeon area", GUILayout.Width(buttonWidth), GUILayout.Height(buttonHeight)))
        {
            // Test if game is running
            if (IsGameRunning() == false)
            {
                return;
            }

            Transform  doorOwner = null;
            StaticDoor door      = new StaticDoor();
            DFLocation location  = new DFLocation();

            // Assign an override location

            // Grab player and use their PlayerEnterExit
            // TransitionDungeonInterior
            GameManager.Instance.PlayerEnterExit.TransitionDungeonInterior(doorOwner, door, location);
        }



        if (GUILayout.Button("Do other thing", GUILayout.Width(buttonWidth), GUILayout.Height(buttonHeight)))
        {
            EditorUtility.SetDirty(soData);
        }

        PrintLocationInformation();

        EditorGUILayout.EndHorizontal();
    }
예제 #17
0
        protected virtual void RaiseOnPreTransitionEvent(TransitionType transitionType, StaticDoor staticDoor)
        {
            TransitionEventArgs args = new TransitionEventArgs(TransitionType.ToBuildingInterior, staticDoor);

            if (OnPreTransition != null)
            {
                OnPreTransition(args);
            }
        }
예제 #18
0
 protected virtual void RaiseOnTransitionDungeonInteriorEvent(StaticDoor staticDoor, DaggerfallDungeon daggerfallDungeon)
 {
     TransitionEventArgs args = new TransitionEventArgs(TransitionType.ToDungeonInterior, staticDoor, null, daggerfallDungeon);
     if (OnTransitionDungeonInterior != null)
         OnTransitionDungeonInterior(args);
 }
예제 #19
0
        /// <summary>
        /// Transition player through a dungeon entrance door into dungeon interior.
        /// </summary>
        /// <param name="doorOwner">Parent transform owning door array.</param>
        /// <param name="door">Exterior door player clicked on.</param>
        public void TransitionDungeonInterior(Transform doorOwner, StaticDoor door, DFLocation location)
        {
            // Ensure we have component references
            if (!ReferenceComponents())
                return;

            // Override location if specified
            if (OverrideLocation != null)
            {
                DFLocation overrideLocation = dfUnity.ContentReader.MapFileReader.GetLocation(OverrideLocation.Summary.RegionName, OverrideLocation.Summary.LocationName);
                if (overrideLocation.Loaded)
                    location = overrideLocation;
            }

            // Raise event
            RaiseOnPreTransitionEvent(TransitionType.ToDungeonInterior, door);

            // Layout dungeon
            GameObject newDungeon = GameObjectHelper.CreateDaggerfallDungeonGameObject(location, DungeonParent.transform);
            newDungeon.hideFlags = HideFlags.HideAndDontSave;
            dungeon = newDungeon.GetComponent<DaggerfallDungeon>();

            // Find start marker to position player
            if (!dungeon.StartMarker)
            {
                // Could not find a start marker
                Destroy(newDungeon);
                return;
            }

            // Cache player starting position and facing to use on exit
            dungeonEntrancePosition = transform.position;
            dungeonEntranceForward = transform.forward;

            // Disable exterior parent
            if (ExteriorParent != null)
                ExteriorParent.SetActive(false);

            // Enable dungeon parent
            if (DungeonParent != null)
                DungeonParent.SetActive(true);

            // Player is now inside dungeon
            isPlayerInside = true;
            isPlayerInsideDungeon = true;

            // Set to start position
            MovePlayerToDungeonStart();

            // Raise event
            RaiseOnTransitionDungeonInteriorEvent(door, dungeon);
        }
예제 #20
0
        /// <summary>
        /// Instantiate base RMB block by DFBlock data.
        /// </summary>
        /// <param name="blockData">Block data.</param>
        /// <param name="layoutX">X coordinate in parent map layout.</param>
        /// /// <param name="layoutY">Y coordinate in parent map layout.</param>
        /// <param name="cloneFrom">Prefab to clone from.</param>
        /// <returns>Block GameObject.</returns>
        public static GameObject CreateBaseGameObject(ref DFBlock blockData, int layoutX, int layoutY, DaggerfallRMBBlock cloneFrom = null)
        {
            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;

            if (!dfUnity.IsReady)
            {
                return(null);
            }

            // Create gameobject
            GameObject go;
            string     name = string.Format("DaggerfallBlock [{0}]", blockData.Name);

            if (cloneFrom != null)
            {
                go = GameObjectHelper.InstantiatePrefab(cloneFrom.gameObject, name, null, Vector3.zero);
            }
            else
            {
                go = new GameObject(name);
            }

            // Setup combiner
            ModelCombiner combiner = null;

            if (dfUnity.Option_CombineRMB)
            {
                combiner = new ModelCombiner();
            }

            // Lists to receive any doors found in this block
            List <StaticDoor>     modelDoors;
            List <StaticDoor>     propDoors;
            List <StaticBuilding> modelBuildings;

            // Add models and static props
            GameObject modelsNode = new GameObject("Models");

            modelsNode.transform.parent = go.transform;
            AddModels(dfUnity, layoutX, layoutY, ref blockData, out modelDoors, out modelBuildings, combiner, modelsNode.transform);
            AddProps(dfUnity, ref blockData, out propDoors, combiner, modelsNode.transform);

            // Combine list of doors found in models and props
            List <StaticDoor> allDoors = new List <StaticDoor>();

            if (modelDoors.Count > 0)
            {
                allDoors.AddRange(modelDoors);
            }
            if (propDoors.Count > 0)
            {
                allDoors.AddRange(propDoors);
            }

            // Assign building key to each door
            for (int i = 0; i < allDoors.Count; i++)
            {
                StaticDoor door = allDoors[i];
                door.buildingKey = BuildingDirectory.MakeBuildingKey((byte)layoutX, (byte)layoutY, (byte)door.recordIndex);
                allDoors[i]      = door;
            }

            // Assign building key to each building
            for (int i = 0; i < modelBuildings.Count; i++)
            {
                StaticBuilding building = modelBuildings[i];
                building.buildingKey = BuildingDirectory.MakeBuildingKey((byte)layoutX, (byte)layoutY, (byte)building.recordIndex);
                modelBuildings[i]    = building;
            }

            // Add static doors component
            if (allDoors.Count > 0)
            {
                AddStaticDoors(allDoors.ToArray(), go);
            }

            // Add static buildings component
            if (modelBuildings.Count > 0)
            {
                AddStaticBuildings(modelBuildings.ToArray(), go);
            }

            // Apply combiner
            if (combiner != null)
            {
                if (combiner.VertexCount > 0)
                {
                    combiner.Apply();
                    GameObjectHelper.CreateCombinedMeshGameObject(
                        combiner,
                        "CombinedModels",
                        modelsNode.transform,
                        dfUnity.Option_SetStaticFlags);
                }
            }

            return(go);
        }
예제 #21
0
        /// <summary>
        /// Transition player through a dungeon entrance door into dungeon interior.
        /// </summary>
        /// <param name="doorOwner">Parent transform owning door array.</param>
        /// <param name="door">Exterior door player clicked on.</param>
        public void TransitionDungeonInterior(Transform doorOwner, StaticDoor door, DFLocation location, bool doFade = false)
        {
            // Ensure we have component references
            if (!ReferenceComponents())
                return;

            // Override location if specified
            if (OverrideLocation != null)
            {
                DFLocation overrideLocation = dfUnity.ContentReader.MapFileReader.GetLocation(OverrideLocation.Summary.RegionName, OverrideLocation.Summary.LocationName);
                if (overrideLocation.Loaded)
                    location = overrideLocation;
            }

            // Raise event
            RaiseOnPreTransitionEvent(TransitionType.ToDungeonInterior, door);

            // Layout dungeon
            GameObject newDungeon = GameObjectHelper.CreateDaggerfallDungeonGameObject(location, DungeonParent.transform);
            newDungeon.hideFlags = defaultHideFlags;
            dungeon = newDungeon.GetComponent<DaggerfallDungeon>();

            // Find start marker to position player
            if (!dungeon.StartMarker)
            {
                // Could not find a start marker
                Destroy(newDungeon);
                return;
            }

            EnableDungeonParent();

            // Set to start position
            MovePlayerToMarker(dungeon.StartMarker);

            // Find closest dungeon exit door to orient player
            StaticDoor[] doors = DaggerfallStaticDoors.FindDoorsInCollections(dungeon.StaticDoorCollections, DoorTypes.DungeonExit);
            if (doors != null && doors.Length > 0)
            {
                Vector3 doorPos;
                int doorIndex;
                if (DaggerfallStaticDoors.FindClosestDoorToPlayer(transform.position, doors, out doorPos, out doorIndex))
                {
                    // Set player facing away from door
                    PlayerMouseLook playerMouseLook = GameManager.Instance.PlayerMouseLook;
                    if (playerMouseLook)
                    {
                        Vector3 normal = DaggerfallStaticDoors.GetDoorNormal(doors[doorIndex]);
                        playerMouseLook.SetFacing(normal);
                    }
                }
            }

            // Raise event
            RaiseOnTransitionDungeonInteriorEvent(door, dungeon);

            // Fade in from black
            if (doFade)
                DaggerfallUI.Instance.FadeHUDFromBlack();
        }
예제 #22
0
        /// <summary>
        /// Transition player through an exterior door into building interior.
        /// </summary>
        /// <param name="doorOwner">Parent transform owning door array..</param>
        /// <param name="door">Exterior door player clicked on.</param>
        public void TransitionInterior(Transform doorOwner, StaticDoor door, bool doFade = false)
        {
            // Ensure we have component references
            if (!ReferenceComponents())
            {
                return;
            }

            // Copy owner position to door
            // This ensures the door itself is all we need to reposition interior
            // Useful when loading a save and doorOwner is null (as outside world does not exist)
            if (doorOwner)
            {
                door.ownerPosition = doorOwner.position;
                door.ownerRotation = doorOwner.rotation;
            }

            // Raise event
            RaiseOnPreTransitionEvent(TransitionType.ToBuildingInterior, door);

            // Get climate
            ClimateBases climateBase = ClimateBases.Temperate;

            if (OverrideLocation)
            {
                climateBase = OverrideLocation.Summary.Climate;
            }
            else if (playerGPS)
            {
                climateBase = ClimateSwaps.FromAPIClimateBase(playerGPS.ClimateSettings.ClimateType);
            }

            // Layout interior
            // This needs to be done first so we know where the enter markers are
            GameObject newInterior = new GameObject(string.Format("DaggerfallInterior [Block={0}, Record={1}]", door.blockIndex, door.recordIndex));

            newInterior.hideFlags = defaultHideFlags;
            interior = newInterior.AddComponent <DaggerfallInterior>();

            // Try to layout interior
            // If we fail for any reason, use that old chestnut "this house has nothing of value"
            try
            {
                interior.DoLayout(doorOwner, door, climateBase);
            }
            catch
            {
                DaggerfallUI.AddHUDText(UserInterfaceWindows.HardStrings.thisHouseHasNothingOfValue);
                Destroy(newInterior);
                return;
            }

            // Position interior directly inside of exterior
            // This helps with finding closest enter/exit point relative to player position
            interior.transform.position = door.ownerPosition + (Vector3)door.buildingMatrix.GetColumn(3);
            interior.transform.rotation = GameObjectHelper.QuaternionFromMatrix(door.buildingMatrix);

            // Position player above closest enter marker
            Vector3 marker;

            if (!interior.FindClosestEnterMarker(transform.position, out marker))
            {
                // Could not find an enter marker, probably not a valid interior
                Destroy(newInterior);
                return;
            }

            // Enumerate all exterior doors belonging to this building
            DaggerfallStaticDoors exteriorStaticDoors = interior.ExteriorDoors;

            if (exteriorStaticDoors && doorOwner)
            {
                List <StaticDoor> buildingDoors = new List <StaticDoor>();
                for (int i = 0; i < exteriorStaticDoors.Doors.Length; i++)
                {
                    if (exteriorStaticDoors.Doors[i].recordIndex == door.recordIndex)
                    {
                        StaticDoor newDoor = exteriorStaticDoors.Doors[i];
                        newDoor.ownerPosition = doorOwner.position;
                        newDoor.ownerRotation = doorOwner.rotation;
                        buildingDoors.Add(newDoor);
                    }
                }
                SetExteriorDoors(buildingDoors.ToArray());
            }

            // Assign new interior to parent
            if (InteriorParent != null)
            {
                newInterior.transform.parent = InteriorParent.transform;
            }

            // Cache some information about this interior
            buildingType = interior.BuildingData.BuildingType;

            // Set player to marker position
            // TODO: Find closest door for player facing
            transform.position = marker + Vector3.up * (controller.height * 0.6f);
            SetStanding();

            EnableInteriorParent();

            // Raise event
            RaiseOnTransitionInteriorEvent(door, interior);

            // Fade in from black
            if (doFade)
            {
                DaggerfallUI.Instance.FadeHUDFromBlack();
            }
        }
예제 #23
0
        /// <summary>
        /// Transition player through an exterior door into building interior.
        /// </summary>
        /// <param name="doorOwner">Parent transform owning door array..</param>
        /// <param name="door">Exterior door player clicked on.</param>
        public void TransitionInterior(Transform doorOwner, StaticDoor door, bool doFade = false, bool start = true)
        {
            // Ensure we have component references
            if (!ReferenceComponents())
            {
                return;
            }

            // Copy owner position to door
            // This ensures the door itself is all we need to reposition interior
            // Useful when loading a save and doorOwner is null (as outside world does not exist)
            if (doorOwner)
            {
                door.ownerPosition = doorOwner.position;
                door.ownerRotation = doorOwner.rotation;
            }

            if (!start)
            {
                // Update scene cache from serializable state for exterior->interior transition
                SaveLoadManager.CacheScene(world.SceneName);
                // Explicitly deregister all stateful objects since exterior isn't destroyed
                SaveLoadManager.DeregisterAllSerializableGameObjects(true);
                // Clear all stateful objects from world loose object tracking
                world.ClearStatefulLooseObjects();
            }

            // Raise event
            RaiseOnPreTransitionEvent(TransitionType.ToBuildingInterior, door);

            // Ensure expired rooms are removed
            GameManager.Instance.PlayerEntity.RemoveExpiredRentedRooms();

            // Get climate
            ClimateBases climateBase = ClimateBases.Temperate;

            if (OverrideLocation)
            {
                climateBase = OverrideLocation.Summary.Climate;
            }
            else if (playerGPS)
            {
                climateBase = ClimateSwaps.FromAPIClimateBase(playerGPS.ClimateSettings.ClimateType);
            }

            // Layout interior
            // This needs to be done first so we know where the enter markers are
            GameObject newInterior = new GameObject(DaggerfallInterior.GetSceneName(playerGPS.CurrentLocation, door));

            newInterior.hideFlags = defaultHideFlags;
            interior = newInterior.AddComponent <DaggerfallInterior>();

            // Try to layout interior
            // If we fail for any reason, use that old chestnut "this house has nothing of value"
            try
            {
                interior.DoLayout(doorOwner, door, climateBase, buildingDiscoveryData);
            }
            catch
            {
                DaggerfallUI.AddHUDText(HardStrings.thisHouseHasNothingOfValue);
                Destroy(newInterior);
                return;
            }

            // Position interior directly inside of exterior
            // This helps with finding closest enter/exit point relative to player position
            interior.transform.position = door.ownerPosition + (Vector3)door.buildingMatrix.GetColumn(3);
            interior.transform.rotation = GameObjectHelper.QuaternionFromMatrix(door.buildingMatrix);

            // Position player above closest enter marker
            Vector3 marker;

            if (!interior.FindClosestEnterMarker(transform.position, out marker))
            {
                // Could not find an enter marker, probably not a valid interior
                Destroy(newInterior);
                return;
            }

            // Enumerate all exterior doors belonging to this building
            DaggerfallStaticDoors exteriorStaticDoors = interior.ExteriorDoors;

            if (exteriorStaticDoors && doorOwner)
            {
                List <StaticDoor> buildingDoors = new List <StaticDoor>();
                for (int i = 0; i < exteriorStaticDoors.Doors.Length; i++)
                {
                    if (exteriorStaticDoors.Doors[i].recordIndex == door.recordIndex)
                    {
                        StaticDoor newDoor = exteriorStaticDoors.Doors[i];
                        newDoor.ownerPosition = doorOwner.position;
                        newDoor.ownerRotation = doorOwner.rotation;
                        buildingDoors.Add(newDoor);
                    }
                }
                SetExteriorDoors(buildingDoors.ToArray());
            }

            // Assign new interior to parent
            if (InteriorParent != null)
            {
                newInterior.transform.parent = InteriorParent.transform;
            }

            // Cache some information about this interior
            buildingType = interior.BuildingData.BuildingType;
            factionID    = interior.BuildingData.FactionId;

            // Set player to marker position
            // TODO: Find closest door for player facing
            transform.position = marker + Vector3.up * (controller.height * 0.6f);
            SetStanding();

            EnableInteriorParent();

            // Add quest resources
            GameObjectHelper.AddQuestResourceObjects(SiteTypes.Building, interior.transform, interior.EntryDoor.buildingKey);

            // Update serializable state from scene cache for exterior->interior transition (unless new/load game)
            if (!start)
            {
                SaveLoadManager.RestoreCachedScene(interior.name);
            }

            // Raise event
            RaiseOnTransitionInteriorEvent(door, interior);

            // Fade in from black
            if (doFade)
            {
                DaggerfallUI.Instance.FadeHUDFromBlack();
            }
        }
예제 #24
0
        /// <summary>
        /// Transition player through an exterior door into building interior.
        /// </summary>
        /// <param name="doorOwner">Parent transform owning door array..</param>
        /// <param name="door">Exterior door player clicked on.</param>
        public void TransitionInterior(Transform doorOwner, StaticDoor door, bool doFade = false)
        {
            // Ensure we have component references
            if (!ReferenceComponents())
                return;

            // Copy owner position to door
            // This ensures the door itself is all we need to reposition interior
            // Useful when loading a save and doorOwner is null (as outside world does not exist)
            if (doorOwner)
            {
                door.ownerPosition = doorOwner.position;
                door.ownerRotation = doorOwner.rotation;
            }

            // Raise event
            RaiseOnPreTransitionEvent(TransitionType.ToBuildingInterior, door);

            // Get climate
            ClimateBases climateBase = ClimateBases.Temperate;
            if (OverrideLocation)
                climateBase = OverrideLocation.Summary.Climate;
            else if (playerGPS)
                climateBase = ClimateSwaps.FromAPIClimateBase(playerGPS.ClimateSettings.ClimateType);

            // Layout interior
            // This needs to be done first so we know where the enter markers are
            GameObject newInterior = new GameObject(string.Format("DaggerfallInterior [Block={0}, Record={1}]", door.blockIndex, door.recordIndex));
            newInterior.hideFlags = defaultHideFlags;
            interior = newInterior.AddComponent<DaggerfallInterior>();

            // Try to layout interior
            // If we fail for any reason, use that old chestnut "this house has nothing of value"
            try
            {
                interior.DoLayout(doorOwner, door, climateBase);
            }
            catch
            {
                DaggerfallUI.AddHUDText(UserInterfaceWindows.HardStrings.thisHouseHasNothingOfValue);
                Destroy(newInterior);
                return;
            }

            // Position interior directly inside of exterior
            // This helps with finding closest enter/exit point relative to player position
            interior.transform.position = door.ownerPosition + (Vector3)door.buildingMatrix.GetColumn(3);
            interior.transform.rotation = GameObjectHelper.QuaternionFromMatrix(door.buildingMatrix);

            // Position player above closest enter marker
            Vector3 marker;
            if (!interior.FindClosestEnterMarker(transform.position, out marker))
            {
                // Could not find an enter marker, probably not a valid interior
                Destroy(newInterior);
                return;
            }

            // Enumerate all exterior doors belonging to this building
            DaggerfallStaticDoors exteriorStaticDoors = interior.ExteriorDoors;
            if (exteriorStaticDoors && doorOwner)
            {
                List<StaticDoor> buildingDoors = new List<StaticDoor>();
                for (int i = 0; i < exteriorStaticDoors.Doors.Length; i++)
                {
                    if (exteriorStaticDoors.Doors[i].recordIndex == door.recordIndex)
                    {
                        StaticDoor newDoor = exteriorStaticDoors.Doors[i];
                        newDoor.ownerPosition = doorOwner.position;
                        newDoor.ownerRotation = doorOwner.rotation;
                        buildingDoors.Add(newDoor);
                    }
                }
                exteriorDoors = buildingDoors.ToArray();
            }

            // Assign new interior to parent
            if (InteriorParent != null)
                newInterior.transform.parent = InteriorParent.transform;

            // Cache some information about this interior
            buildingType = interior.BuildingData.BuildingType;

            // Set player to marker position
            // TODO: Find closest door for player facing
            transform.position = marker + Vector3.up * (controller.height * 0.6f);
            SetStanding();

            EnableInteriorParent();

            // Raise event
            RaiseOnTransitionInteriorEvent(door, interior);

            // Fade in from black
            if (doFade)
                DaggerfallUI.Instance.FadeHUDFromBlack();
        }
예제 #25
0
 /// <summary>Constructor helper.</summary>
 public TransitionEventArgs(TransitionType transitionType, StaticDoor staticDoor, DaggerfallInterior daggerfallInterior = null, DaggerfallDungeon daggerfallDungeon = null)
     : base()
 {
     this.TransitionType = transitionType;
     this.StaticDoor = staticDoor;
     this.DaggerfallInterior = daggerfallInterior;
     this.DaggerfallDungeon = daggerfallDungeon;
 }
예제 #26
0
 /// <summary>Constructor.</summary>
 public TransitionEventArgs()
 {
     TransitionType = PlayerEnterExit.TransitionType.NotDefined;
     StaticDoor = new StaticDoor();
     DaggerfallInterior = null;
     DaggerfallDungeon = null;
 }
예제 #27
0
 protected virtual void RaiseOnTransitionInteriorEvent(StaticDoor staticDoor, DaggerfallInterior daggerfallInterior)
 {
     TransitionEventArgs args = new TransitionEventArgs(TransitionType.ToBuildingInterior, staticDoor, daggerfallInterior);
     if (OnTransitionInterior != null)
         OnTransitionInterior(args);
 }
        /// <summary>
        /// Gets static door array from door information stored in model data.
        /// </summary>
        /// <param name="modelData">Model data for doors.</param>
        /// <param name="blockIndex">Block index for RMB doors.</param>
        /// <param name="recordIndex">Record index of interior.</param>
        /// <param name="buildingMatrix">Individual building matrix.</param>
        /// <returns>Array of doors in this model data.</returns>
        public static StaticDoor[] GetStaticDoors(ref ModelData modelData, int blockIndex, int recordIndex, Matrix4x4 buildingMatrix)
        {
            // Exit if no doors
            if (modelData.Doors == null)
                return null;

            // Add door triggers
            StaticDoor[] staticDoors = new StaticDoor[modelData.Doors.Length];
            for (int i = 0; i < modelData.Doors.Length; i++)
            {
                // Get door and diagonal verts
                ModelDoor door = modelData.Doors[i];
                Vector3 v0 = door.Vert0;
                Vector3 v2 = door.Vert2;

                // Get door size
                const float thickness = 0.05f;
                Vector3 size = new Vector3(v2.x - v0.x, v2.y - v0.y, v2.z - v0.z) + door.Normal * thickness;

                // Add door to array
                StaticDoor newDoor = new StaticDoor()
                {
                    buildingMatrix = buildingMatrix,
                    doorType = door.Type,
                    blockIndex = blockIndex,
                    recordIndex = recordIndex,
                    doorIndex = door.Index,
                    centre = (v0 + v2) / 2f,
                    normal = door.Normal,
                    size = size,
                };
                staticDoors[i] = newDoor;
            }

            return staticDoors;
        }
예제 #29
0
        /// <summary>
        /// Transition player through a dungeon entrance door into dungeon interior.
        /// </summary>
        /// <param name="doorOwner">Parent transform owning door array.</param>
        /// <param name="door">Exterior door player clicked on.</param>
        public void TransitionDungeonInterior(Transform doorOwner, StaticDoor door, DFLocation location, bool doFade = false)
        {
            // Ensure we have component references
            if (!ReferenceComponents())
            {
                return;
            }

            // Reset dungeon block on entering dungeon
            lastPlayerDungeonBlockIndex = -1;
            playerDungeonBlockData      = new DFLocation.DungeonBlock();

            // Override location if specified
            if (OverrideLocation != null)
            {
                DFLocation overrideLocation = dfUnity.ContentReader.MapFileReader.GetLocation(OverrideLocation.Summary.RegionName, OverrideLocation.Summary.LocationName);
                if (overrideLocation.Loaded)
                {
                    location = overrideLocation;
                }
            }

            // Raise event
            RaiseOnPreTransitionEvent(TransitionType.ToDungeonInterior, door);

            // Layout dungeon
            GameObject newDungeon = GameObjectHelper.CreateDaggerfallDungeonGameObject(location, DungeonParent.transform);

            newDungeon.hideFlags = defaultHideFlags;
            dungeon = newDungeon.GetComponent <DaggerfallDungeon>();

            // Find start marker to position player
            if (!dungeon.StartMarker)
            {
                // Could not find a start marker
                Destroy(newDungeon);
                return;
            }

            EnableDungeonParent();

            // Set to start position
            MovePlayerToMarker(dungeon.StartMarker);

            // Find closest dungeon exit door to orient player
            StaticDoor[] doors = DaggerfallStaticDoors.FindDoorsInCollections(dungeon.StaticDoorCollections, DoorTypes.DungeonExit);
            if (doors != null && doors.Length > 0)
            {
                Vector3 doorPos;
                int     doorIndex;
                if (DaggerfallStaticDoors.FindClosestDoorToPlayer(transform.position, doors, out doorPos, out doorIndex))
                {
                    // Set player facing away from door
                    PlayerMouseLook playerMouseLook = GameManager.Instance.PlayerMouseLook;
                    if (playerMouseLook)
                    {
                        Vector3 normal = DaggerfallStaticDoors.GetDoorNormal(doors[doorIndex]);
                        playerMouseLook.SetFacing(normal);
                    }
                }
            }

            // Raise event
            RaiseOnTransitionDungeonInteriorEvent(door, dungeon);

            // Fade in from black
            if (doFade)
            {
                DaggerfallUI.Instance.FadeHUDFromBlack();
            }
        }
예제 #30
0
        void Update()
        {
            if (mainCamera == null)
            {
                return;
            }

            // Change activate mode
            if (InputManager.Instance.ActionStarted(InputManager.Actions.StealMode))
            {
                ChangeInteractionMode(PlayerActivateModes.Steal);
            }
            else if (InputManager.Instance.ActionStarted(InputManager.Actions.GrabMode))
            {
                ChangeInteractionMode(PlayerActivateModes.Grab);
            }
            else if (InputManager.Instance.ActionStarted(InputManager.Actions.InfoMode))
            {
                ChangeInteractionMode(PlayerActivateModes.Info);
            }
            else if (InputManager.Instance.ActionStarted(InputManager.Actions.TalkMode))
            {
                ChangeInteractionMode(PlayerActivateModes.Talk);
            }

            // Fire ray into scene
            if (InputManager.Instance.ActionStarted(InputManager.Actions.ActivateCenterObject))
            {
                // TODO: Clean all this up and support mobile enemy info-clicks

                // Using RaycastAll as hits can be blocked by decorations or other models
                // When this happens activation feels unresponsive to player
                // Also processing hit detection in order of priority
                Ray          ray = new Ray(mainCamera.transform.position, mainCamera.transform.forward);
                RaycastHit[] hits;
                hits = Physics.RaycastAll(ray, RayDistance);
                if (hits != null)
                {
                    // Check each hit in range for action, exit on first valid action processed
                    bool           hitBuilding = false;
                    StaticBuilding building    = new StaticBuilding();
                    for (int i = 0; i < hits.Length; i++)
                    {
                        #region Hit Checks

                        // Check for a static building hit
                        Transform buildingOwner;
                        DaggerfallStaticBuildings buildings = GetBuildings(hits[i].transform, out buildingOwner);
                        if (buildings)
                        {
                            if (buildings.HasHit(hits[i].point, out building))
                            {
                                hitBuilding = true;

                                // Show building info
                                if (currentMode == PlayerActivateModes.Info)
                                {
                                    PresentBuildingInfo(building);
                                }
                            }
                        }

                        // Check for a static door hit
                        Transform             doorOwner;
                        DaggerfallStaticDoors doors = GetDoors(hits[i].transform, out doorOwner);
                        if (doors && playerEnterExit)
                        {
                            StaticDoor door;
                            if (doors.HasHit(hits[i].point, out door))
                            {
                                if (door.doorType == DoorTypes.Building && !playerEnterExit.IsPlayerInside)
                                {
                                    // If entering a shop let player know the quality level
                                    if (hitBuilding)
                                    {
                                        DaggerfallMessageBox mb = PresentShopQuality(building);
                                        if (mb != null)
                                        {
                                            // Defer transition to interior to after user closes messagebox
                                            deferredInteriorDoorOwner = doorOwner;
                                            deferredInteriorDoor      = door;
                                            mb.OnClose += ShopQualityPopup_OnClose;
                                            return;
                                        }
                                    }

                                    // Hit door while outside, transition inside
                                    playerEnterExit.TransitionInterior(doorOwner, door, true);
                                    return;
                                }
                                else if (door.doorType == DoorTypes.Building && playerEnterExit.IsPlayerInside)
                                {
                                    // Hit door while inside, transition outside
                                    playerEnterExit.TransitionExterior(true);
                                    return;
                                }
                                else if (door.doorType == DoorTypes.DungeonEntrance && !playerEnterExit.IsPlayerInside)
                                {
                                    if (playerGPS)
                                    {
                                        // Hit dungeon door while outside, transition inside
                                        playerEnterExit.TransitionDungeonInterior(doorOwner, door, playerGPS.CurrentLocation, true);
                                        return;
                                    }
                                }
                                else if (door.doorType == DoorTypes.DungeonExit && playerEnterExit.IsPlayerInside)
                                {
                                    // Hit dungeon exit while inside, transition outside
                                    playerEnterExit.TransitionDungeonExterior(true);
                                    return;
                                }
                            }
                        }

                        // Check for an action door hit
                        DaggerfallActionDoor actionDoor;
                        if (ActionDoorCheck(hits[i], out actionDoor))
                        {
                            if (currentMode == PlayerActivateModes.Steal && actionDoor.IsLocked)
                            {
                                if (actionDoor.IsNoLongerPickable)
                                {
                                    return;
                                }
                                else
                                {
                                    actionDoor.AttemptLockpicking();
                                }
                            }
                            else
                            {
                                actionDoor.ToggleDoor();
                            }
                        }

                        // Check for action record hit
                        DaggerfallAction action;
                        if (ActionCheck(hits[i], out action))
                        {
                            action.Receive(this.gameObject, DaggerfallAction.TriggerTypes.Direct);
                        }

                        // Check for lootable object hit
                        DaggerfallLoot loot;
                        if (LootCheck(hits[i], out loot))
                        {
                            // For bodies, check has treasure first
                            if (loot.ContainerType == LootContainerTypes.CorpseMarker && loot.Items.Count == 0)
                            {
                                DaggerfallUI.AddHUDText(HardStrings.theBodyHasNoTreasure);
                                return;
                            }

                            // Open inventory window with loot as remote target
                            DaggerfallUI.Instance.InventoryWindow.LootTarget = loot;
                            DaggerfallUI.PostMessage(DaggerfallUIMessages.dfuiOpenInventoryWindow);
                        }

                        // Check for static NPC hit
                        StaticNPC npc;
                        if (NPCCheck(hits[i], out npc))
                        {
                            switch (currentMode)
                            {
                            case PlayerActivateModes.Info:
                                PresentNPCInfo(npc);
                                break;

                            case PlayerActivateModes.Grab:
                            case PlayerActivateModes.Talk:
                                SpecialNPCClick(npc);
                                QuestorCheck(npc);
                                break;
                            }
                        }

                        // Trigger general quest resource behaviour click
                        // Note: This will cause a second click on special NPCs, look into a way to unify this handling
                        QuestResourceBehaviour questResourceBehaviour;
                        if (QuestResourceBehaviourCheck(hits[i], out questResourceBehaviour))
                        {
                            TriggerQuestResourceBehaviourClick(questResourceBehaviour);
                        }

                        #endregion
                    }
                }
            }
        }
예제 #31
0
        /// <summary>
        /// Starts player inside building with no exterior world.
        /// </summary>
        public void StartBuildingInterior(DFLocation location, StaticDoor exteriorDoor)
        {
            // Ensure we have component references
            if (!ReferenceComponents())
                return;

            TransitionInterior(null, exteriorDoor);
        }
예제 #32
0
        void Update()
        {
            if (mainCamera == null)
            {
                return;
            }

            // Change activate mode
            if (InputManager.Instance.ActionStarted(InputManager.Actions.StealMode))
            {
                ChangeInteractionMode(PlayerActivateModes.Steal);
            }
            else if (InputManager.Instance.ActionStarted(InputManager.Actions.GrabMode))
            {
                ChangeInteractionMode(PlayerActivateModes.Grab);
            }
            else if (InputManager.Instance.ActionStarted(InputManager.Actions.InfoMode))
            {
                ChangeInteractionMode(PlayerActivateModes.Info);
            }
            else if (InputManager.Instance.ActionStarted(InputManager.Actions.TalkMode))
            {
                ChangeInteractionMode(PlayerActivateModes.Talk);
            }

            // Fire ray into scene
            if (InputManager.Instance.ActionStarted(InputManager.Actions.ActivateCenterObject))
            {
                // TODO: Clean all this up

                // Ray origin is slightly below camera height to ensure it originates inside player's own collider
                // This prevents ray from intersecting with player's own collider and blocking looting or low triggers
                Ray        ray = new Ray(transform.position + Vector3.up * 0.7f, mainCamera.transform.forward);
                RaycastHit hit;
                RayDistance = 75f; // Approximates classic at full view distance (default setting). Classic seems to do raycasts for as far as it can render objects.
                bool hitSomething = Physics.Raycast(ray, out hit, RayDistance);
                if (hitSomething)
                {
                    bool hitBuilding      = false;
                    bool buildingUnlocked = false;
                    DFLocation.BuildingTypes buildingType = DFLocation.BuildingTypes.AllValid;
                    StaticBuilding           building     = new StaticBuilding();

                    #region Hit Checks

                    // Trigger quest resource behaviour click on anything but NPCs
                    QuestResourceBehaviour questResourceBehaviour;
                    if (QuestResourceBehaviourCheck(hit, out questResourceBehaviour))
                    {
                        if (!(questResourceBehaviour.TargetResource is Person))
                        {
                            if (hit.distance > (DefaultActivationDistance * MeshReader.GlobalScale))
                            {
                                DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                                return;
                            }

                            // Only trigger click when not in info mode
                            if (currentMode != PlayerActivateModes.Info)
                            {
                                TriggerQuestResourceBehaviourClick(questResourceBehaviour);
                            }
                        }
                    }

                    // Check for a static building hit
                    Transform buildingOwner;
                    DaggerfallStaticBuildings buildings = GetBuildings(hit.transform, out buildingOwner);
                    if (buildings)
                    {
                        if (buildings.HasHit(hit.point, out building))
                        {
                            hitBuilding = true;

                            // Get building directory for location
                            BuildingDirectory buildingDirectory = GameManager.Instance.StreamingWorld.GetCurrentBuildingDirectory();
                            if (!buildingDirectory)
                            {
                                return;
                            }

                            // Get detailed building data from directory
                            BuildingSummary buildingSummary;
                            if (!buildingDirectory.GetBuildingSummary(building.buildingKey, out buildingSummary))
                            {
                                return;
                            }

                            // Check if door is unlocked
                            buildingUnlocked = BuildingIsUnlocked(buildingSummary);

                            // Store building type
                            buildingType = buildingSummary.BuildingType;

                            if (currentMode == PlayerActivateModes.Info)
                            {
                                // Discover building
                                GameManager.Instance.PlayerGPS.DiscoverBuilding(building.buildingKey);

                                // Get discovered building
                                PlayerGPS.DiscoveredBuilding db;
                                if (GameManager.Instance.PlayerGPS.GetDiscoveredBuilding(building.buildingKey, out db))
                                {
                                    // TODO: Check against quest system for an overriding quest-assigned display name for this building
                                    DaggerfallUI.AddHUDText(db.displayName);

                                    if (!buildingUnlocked && buildingType < DFLocation.BuildingTypes.Temple &&
                                        buildingType != DFLocation.BuildingTypes.HouseForSale)
                                    {
                                        string storeClosedMessage = HardStrings.storeClosed;
                                        storeClosedMessage = storeClosedMessage.Replace("%d1", openHours[(int)buildingType].ToString());
                                        storeClosedMessage = storeClosedMessage.Replace("%d2", closeHours[(int)buildingType].ToString());
                                        DaggerfallUI.Instance.PopupMessage(storeClosedMessage);
                                    }
                                }
                            }
                        }
                    }

                    // Check for a static door hit
                    Transform             doorOwner;
                    DaggerfallStaticDoors doors = GetDoors(hit.transform, out doorOwner);
                    if (doors && playerEnterExit)
                    {
                        StaticDoor door;
                        if (doors.HasHit(hit.point, out door))
                        {
                            // Check if close enough to activate
                            if (hit.distance > (DoorActivationDistance * MeshReader.GlobalScale))
                            {
                                DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                                return;
                            }

                            if (door.doorType == DoorTypes.Building && !playerEnterExit.IsPlayerInside)
                            {
                                // Discover building
                                GameManager.Instance.PlayerGPS.DiscoverBuilding(building.buildingKey);

                                // TODO: Implement lockpicking and door bashing for exterior doors
                                // For now, any locked building door can be entered by using steal mode
                                if (!buildingUnlocked)
                                {
                                    if (currentMode != PlayerActivateModes.Steal)
                                    {
                                        string Locked = "Locked.";
                                        DaggerfallUI.Instance.PopupMessage(Locked);
                                        return;
                                    }
                                    else     // Breaking into building
                                    {
                                        PlayerEntity player = GameManager.Instance.PlayerEntity;
                                        //player.TallyCrimeGuildRequirements(true, 1);
                                    }
                                }

                                // If entering a shop let player know the quality level
                                // If entering an open home, show greeting
                                if (hitBuilding)
                                {
                                    const int houseGreetingsTextId = 256;

                                    DaggerfallMessageBox mb;

                                    if (buildingUnlocked && buildingType >= DFLocation.BuildingTypes.House1 &&
                                        buildingType <= DFLocation.BuildingTypes.House4)
                                    {
                                        string greetingText = DaggerfallUnity.Instance.TextProvider.GetRandomText(houseGreetingsTextId);
                                        mb = DaggerfallUI.MessageBox(greetingText);
                                    }
                                    else
                                    {
                                        mb = PresentShopQuality(building);
                                    }

                                    if (mb != null)
                                    {
                                        // Defer transition to interior to after user closes messagebox
                                        deferredInteriorDoorOwner = doorOwner;
                                        deferredInteriorDoor      = door;
                                        mb.OnClose += Popup_OnClose;
                                        return;
                                    }
                                }

                                // Hit door while outside, transition inside
                                TransitionInterior(doorOwner, door, true);
                                return;
                            }
                            else if (door.doorType == DoorTypes.Building && playerEnterExit.IsPlayerInside)
                            {
                                // Hit door while inside, transition outside
                                playerEnterExit.TransitionExterior(true);
                                return;
                            }
                            else if (door.doorType == DoorTypes.DungeonEntrance && !playerEnterExit.IsPlayerInside)
                            {
                                if (playerGPS)
                                {
                                    // Hit dungeon door while outside, transition inside
                                    playerEnterExit.TransitionDungeonInterior(doorOwner, door, playerGPS.CurrentLocation, true);
                                    return;
                                }
                            }
                            else if (door.doorType == DoorTypes.DungeonExit && playerEnterExit.IsPlayerInside)
                            {
                                // Hit dungeon exit while inside, ask if access wagon or transition outside
                                if (GameManager.Instance.PlayerEntity.Items.Contains(ItemGroups.Transportation, (int)Transportation.Small_cart))
                                {
                                    DaggerfallMessageBox messageBox = new DaggerfallMessageBox(DaggerfallUI.UIManager, DaggerfallMessageBox.CommonMessageBoxButtons.YesNo, 38, DaggerfallUI.UIManager.TopWindow);
                                    messageBox.OnButtonClick += DungeonWagonAccess_OnButtonClick;
                                    DaggerfallUI.UIManager.PushWindow(messageBox);
                                    return;
                                }
                                else
                                {
                                    playerEnterExit.TransitionDungeonExterior(true);
                                }
                            }
                        }
                    }

                    // Check for an action door hit
                    DaggerfallActionDoor actionDoor;
                    if (ActionDoorCheck(hit, out actionDoor))
                    {
                        // Check if close enough to activate
                        if (hit.distance > (DoorActivationDistance * MeshReader.GlobalScale))
                        {
                            DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                            return;
                        }

                        if (currentMode == PlayerActivateModes.Steal && actionDoor.IsLocked && !actionDoor.IsOpen)
                        {
                            actionDoor.AttemptLockpicking();
                        }
                        else
                        {
                            actionDoor.ToggleDoor(true);
                        }
                    }

                    // Check for action record hit
                    DaggerfallAction action;
                    if (ActionCheck(hit, out action))
                    {
                        if (hit.distance <= (DefaultActivationDistance * MeshReader.GlobalScale))
                        {
                            action.Receive(this.gameObject, DaggerfallAction.TriggerTypes.Direct);
                        }
                    }

                    // Check for lootable object hit
                    DaggerfallLoot loot;
                    if (LootCheck(hit, out loot))
                    {
                        switch (currentMode)
                        {
                        case PlayerActivateModes.Info:
                            if (loot.ContainerType == LootContainerTypes.CorpseMarker && !string.IsNullOrEmpty(loot.entityName))
                            {
                                string message = string.Empty;
                                if (loot.isEnemyClass)
                                {
                                    message = HardStrings.youSeeADeadPerson;
                                }
                                else
                                {
                                    message = HardStrings.youSeeADead;
                                    message = message.Replace("%s", loot.entityName);
                                }
                                DaggerfallUI.Instance.PopupMessage(message);
                            }
                            break;

                        case PlayerActivateModes.Grab:
                        case PlayerActivateModes.Talk:
                        case PlayerActivateModes.Steal:
                            // Check if close enough to activate
                            if (loot.ContainerType == LootContainerTypes.CorpseMarker)
                            {
                                if (hit.distance > CorpseActivationDistance * MeshReader.GlobalScale)
                                {
                                    DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                                    break;
                                }
                            }
                            else if (hit.distance > TreasureActivationDistance * MeshReader.GlobalScale)
                            {
                                DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                                break;
                            }

                            // For bodies, check has treasure first
                            if (loot.ContainerType == LootContainerTypes.CorpseMarker && loot.Items.Count == 0)
                            {
                                DaggerfallUI.AddHUDText(HardStrings.theBodyHasNoTreasure);
                                break;
                            }

                            // Open inventory window with loot as remote target
                            DaggerfallUI.Instance.InventoryWindow.LootTarget = loot;
                            DaggerfallUI.PostMessage(DaggerfallUIMessages.dfuiOpenInventoryWindow);
                            break;
                        }
                    }

                    // Check for static NPC hit
                    StaticNPC npc;
                    if (NPCCheck(hit, out npc))
                    {
                        switch (currentMode)
                        {
                        case PlayerActivateModes.Info:
                            PresentNPCInfo(npc);
                            break;

                        case PlayerActivateModes.Grab:
                        case PlayerActivateModes.Talk:
                        case PlayerActivateModes.Steal:
                            if (hit.distance > (StaticNPCActivationDistance * MeshReader.GlobalScale))
                            {
                                DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                                break;
                            }
                            StaticNPCClick(npc);
                            break;
                        }
                    }

                    // Check for mobile NPC hit
                    MobilePersonNPC mobileNpc = null;
                    if (MobilePersonMotorCheck(hit, out mobileNpc))
                    {
                        switch (currentMode)
                        {
                        case PlayerActivateModes.Info:
                        case PlayerActivateModes.Grab:
                        case PlayerActivateModes.Talk:
                            if (hit.distance > (MobileNPCActivationDistance * MeshReader.GlobalScale))
                            {
                                DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                                break;
                            }
                            GameManager.Instance.TalkManager.TalkToMobileNPC(mobileNpc);
                            break;

                        case PlayerActivateModes.Steal:
                            if (!mobileNpc.PickpocketByPlayerAttempted)
                            {
                                if (hit.distance > (PickpocketDistance * MeshReader.GlobalScale))
                                {
                                    DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                                    break;
                                }
                                mobileNpc.PickpocketByPlayerAttempted = true;
                                Pickpocket();
                            }
                            break;
                        }
                    }

                    // Check for mobile enemy hit
                    DaggerfallEntityBehaviour mobileEnemyBehaviour;
                    if (MobileEnemyCheck(hit, out mobileEnemyBehaviour))
                    {
                        EnemyEntity enemyEntity = mobileEnemyBehaviour.Entity as EnemyEntity;
                        switch (currentMode)
                        {
                        case PlayerActivateModes.Info:
                        case PlayerActivateModes.Grab:
                        case PlayerActivateModes.Talk:
                            if (enemyEntity != null)
                            {
                                MobileEnemy mobileEnemy     = enemyEntity.MobileEnemy;
                                bool        startsWithVowel = "aeiouAEIOU".Contains(mobileEnemy.Name[0].ToString());
                                string      message;
                                if (startsWithVowel)
                                {
                                    message = HardStrings.youSeeAn;
                                }
                                else
                                {
                                    message = HardStrings.youSeeA;
                                }
                                message = message.Replace("%s", mobileEnemy.Name);
                                DaggerfallUI.Instance.PopupMessage(message);
                            }
                            break;

                        case PlayerActivateModes.Steal:
                            // Classic allows pickpocketing of NPC mobiles and enemy mobiles.
                            // In early versions the only enemy mobiles that can be pickpocketed are classes,
                            // but patch 1.07.212 allows pickpocketing of creatures.
                            // For now, the only enemy mobiles being allowed by DF Unity are classes.
                            if (mobileEnemyBehaviour && (mobileEnemyBehaviour.EntityType != EntityTypes.EnemyClass))
                            {
                                break;
                            }
                            // Classic doesn't set any flag when pickpocketing enemy mobiles, so infinite attempts are possible
                            if (enemyEntity != null && !enemyEntity.PickpocketByPlayerAttempted)
                            {
                                if (hit.distance > (PickpocketDistance * MeshReader.GlobalScale))
                                {
                                    DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                                    break;
                                }
                                enemyEntity.PickpocketByPlayerAttempted = true;
                                Pickpocket(mobileEnemyBehaviour);
                            }
                            break;
                        }
                    }

                    // Trigger ladder hit
                    DaggerfallLadder ladder = hit.transform.GetComponent <DaggerfallLadder>();
                    if (ladder)
                    {
                        if (hit.distance > (DefaultActivationDistance * MeshReader.GlobalScale))
                        {
                            DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                            return;
                        }

                        ladder.ClimbLadder();
                    }

                    #endregion
                }
            }
        }
예제 #33
0
        /// <summary>
        /// Respawn player at the specified world coordinates, optionally inside dungeon or building.
        /// Player can be forced to respawn to closest start marker or origin.
        /// </summary>
        public void RespawnPlayer(
            int worldX,
            int worldZ,
            bool insideDungeon,
            bool insideBuilding,
            StaticDoor[] exteriorDoors = null,
            bool forceReposition = false)
        {
            // Mark any existing world data for destruction
            if (dungeon)
            {
                Destroy(dungeon.gameObject);
            }
            if (interior)
            {
                Destroy(interior.gameObject);
            }

            // Deregister all serializable objects
            SaveLoadManager.DeregisterAllSerializableGameObjects();

            // Start respawn process
            isRespawning = true;
            this.exteriorDoors = exteriorDoors;
            StartCoroutine(Respawner(worldX, worldZ, insideDungeon, insideBuilding, forceReposition));
        }
        /// <summary>
        /// Transition player through an exterior door into building interior.
        /// </summary>
        /// <param name="doorOwner">Parent transform owning door array.</param>
        /// <param name="door">Exterior door player clicked on.</param>
        public void TransitionInterior(Transform doorOwner, StaticDoor door)
        {
            // Ensure we have component references
            if (!ReferenceComponents())
            {
                return;
            }

            // Get current climate
            ClimateBases climateBase = ClimateBases.Temperate;

            if (playerGPS)
            {
                climateBase = ClimateSwaps.FromAPIClimateBase(playerGPS.ClimateSettings.ClimateType);
            }

            // Layout interior
            // This needs to be done first so we know where the enter markers are
            GameObject newInterior = new GameObject(string.Format("DaggerfallInterior [Block={0}, Record={1}]", door.blockIndex, door.recordIndex));

            newInterior.hideFlags = HideFlags.HideAndDontSave;
            interior = newInterior.AddComponent <DaggerfallInterior>();
            interior.DoLayout(doorOwner, door, climateBase);

            // Position interior directly inside of exterior
            // This helps with finding closest enter/exit point relative to player position
            interior.transform.position = doorOwner.position + (Vector3)door.buildingMatrix.GetColumn(3);
            interior.transform.rotation = GameObjectHelper.QuaternionFromMatrix(door.buildingMatrix);

            // Position player above closest enter marker
            Vector3 marker;

            if (!interior.FindClosestEnterMarker(transform.position, out marker))
            {
                // Could not find an enter marker, probably not a valid interior
                Destroy(newInterior);
                return;
            }

            // Assign new interior to parent
            if (InteriorParent != null)
            {
                newInterior.transform.parent = InteriorParent.transform;
            }

            // Disable exterior parent
            if (ExteriorParent != null)
            {
                ExteriorParent.SetActive(false);
            }

            // Enable interior parent
            if (InteriorParent != null)
            {
                InteriorParent.SetActive(true);
            }

            // Cache some information about this interior
            buildingType = interior.BuildingData.BuildingType;

            // Set player to marker position
            // Not sure how to set facing here as player transitions to a marker, not a door
            // Could always find closest door and use that
            transform.position = marker + Vector3.up * (controller.height * 0.6f);
            SetStanding();

            // Player is now inside building
            isPlayerInside = true;
        }
예제 #35
0
        /// <summary>
        /// Transition player through a dungeon entrance door into dungeon interior.
        /// </summary>
        /// <param name="doorOwner">Parent transform owning door array.</param>
        /// <param name="door">Exterior door player clicked on.</param>
        public void TransitionDungeonInterior(Transform doorOwner, StaticDoor door, DFLocation location)
        {
            // Ensure we have component references
            if (!ReferenceComponents())
            {
                return;
            }

            // Override location if specified
            if (OverrideLocation != null)
            {
                DFLocation overrideLocation = dfUnity.ContentReader.MapFileReader.GetLocation(OverrideLocation.Summary.RegionName, OverrideLocation.Summary.LocationName);
                if (overrideLocation.Loaded)
                {
                    location = overrideLocation;
                }
            }

            // Raise event
            RaiseOnPreTransitionEvent(TransitionType.ToDungeonInterior, door);

            // Layout dungeon
            GameObject newDungeon = GameObjectHelper.CreateDaggerfallDungeonGameObject(location, DungeonParent.transform);

            newDungeon.hideFlags = HideFlags.HideAndDontSave;
            dungeon = newDungeon.GetComponent <DaggerfallDungeon>();

            // Find start marker to position player
            if (!dungeon.StartMarker)
            {
                // Could not find a start marker
                Destroy(newDungeon);
                return;
            }

            // Cache player starting position and facing to use on exit
            dungeonEntrancePosition = transform.position;
            dungeonEntranceForward  = transform.forward;

            // Disable exterior parent
            if (ExteriorParent != null)
            {
                ExteriorParent.SetActive(false);
            }

            // Enable dungeon parent
            if (DungeonParent != null)
            {
                DungeonParent.SetActive(true);
            }

            // Player is now inside dungeon
            isPlayerInside        = true;
            isPlayerInsideDungeon = true;

            // Set to start position
            MovePlayerToDungeonStart();

            // Raise event
            RaiseOnTransitionDungeonInteriorEvent(door, dungeon);
        }
예제 #36
0
 private static void AddStaticDoors(StaticDoor[] doors, GameObject target)
 {
     DaggerfallStaticDoors c = target.GetComponent<DaggerfallStaticDoors>();
     if (c == null)
         c = target.AddComponent<DaggerfallStaticDoors>();
     if (doors != null && target != null)
         c.Doors = doors;
 }
예제 #37
0
 protected virtual void RaiseOnPreTransitionEvent(TransitionType transitionType, StaticDoor staticDoor)
 {
     TransitionEventArgs args = new TransitionEventArgs(TransitionType.ToBuildingInterior, staticDoor);
     if (OnPreTransition != null)
         OnPreTransition(args);
 }