Beispiel #1
0
        private AudioClip PlayLoop(SoundClips clip, float volumeScale)
        {
            AudioClip loopClip = dfAudioSource.GetAudioClip((int)clip);

            loopAudioSource.loop         = true;
            loopAudioSource.spatialBlend = 0;
            loopAudioSource.PlayWhenReady(loopClip, volumeScale);
            return(loopClip);
        }
        // Update is called once per frame
        void Update()
        {
            // Handle horse & cart riding animation & sounds.
            if (mode == TransportModes.Horse || mode == TransportModes.Cart)
            {
                // refresh audio volume to reflect global changes
                ridingAudioSource.volume = RidingVolumeScale * DaggerfallUnity.Settings.SoundVolume;
                if (playerMotor.IsStandingStill || !playerMotor.IsGrounded || GameManager.IsGamePaused)
                {   // Stop animation frames and sound playing.
                    lastFrameTime = 0;
                    frameIndex    = 0;
                    ridingTexture = ridingTexures[0];
                    ridingAudioSource.Stop();
                }
                else
                {   // Update Animation frame?
                    if (lastFrameTime == 0)
                    {
                        lastFrameTime = Time.time;
                    }
                    else if (Time.time > lastFrameTime + animFrameTime)
                    {
                        lastFrameTime = Time.time;
                        frameIndex    = (frameIndex == 3) ? 0 : frameIndex + 1;
                        ridingTexture = ridingTexures[frameIndex];
                    }
                    // Get appropriate hoof sound for horse
                    if (mode == TransportModes.Horse)
                    {
                        if (!wasMovingLessThanHalfSpeed && playerMotor.IsMovingLessThanHalfSpeed)
                        {
                            wasMovingLessThanHalfSpeed = true;
                            ridingAudioSource.clip     = dfAudioSource.GetAudioClip((int)horseRidingSound1);
                        }
                        else if (wasMovingLessThanHalfSpeed && !playerMotor.IsMovingLessThanHalfSpeed)
                        {
                            wasMovingLessThanHalfSpeed = false;
                            ridingAudioSource.clip     = dfAudioSource.GetAudioClip((int)horseRidingSound2);
                        }
                    }
                    ridingAudioSource.pitch = playerMotor.IsRunning ? 1.2f : 1f;

                    if (!ridingAudioSource.isPlaying)
                    {
                        ridingAudioSource.volume = RidingVolumeScale * DaggerfallUnity.Settings.SoundVolume;
                        ridingAudioSource.Play();
                    }
                }
                // Time for a whinney?
                if (neighTime < Time.time)
                {
                    dfAudioSource.AudioSource.PlayOneShot(neighClip, RidingVolumeScale * DaggerfallUnity.Settings.SoundVolume);
                    neighTime = Time.time + Random.Range(2, 40);
                }
            }
        }
        void Update()
        {
            // Change sound presets
            if (Presets != lastPresets)
            {
                // Clear settings
                lastPresets  = Presets;
                rainLoop     = null;
                cricketsLoop = null;

                // Stop playing any loops
                if (dfAudioSource.AudioSource.isPlaying)
                {
                    dfAudioSource.AudioSource.Stop();
                    dfAudioSource.AudioSource.clip = null;
                    dfAudioSource.AudioSource.loop = false;
                }

                ApplyPresets();
                StartWaiting();
            }

            // Start rain loop if not running
            if ((Presets == AmbientSoundPresets.Rain || Presets == AmbientSoundPresets.Storm) && rainLoop == null)
            {
                rainLoop = dfAudioSource.GetAudioClip((int)SoundClips.AmbientRaining);
                dfAudioSource.AudioSource.clip         = rainLoop;
                dfAudioSource.AudioSource.loop         = true;
                dfAudioSource.AudioSource.spatialBlend = 0;
                dfAudioSource.AudioSource.Play();
            }

            // Start crickets loop if not running
            if ((Presets == AmbientSoundPresets.ClearNight) && cricketsLoop == null)
            {
                cricketsLoop = dfAudioSource.GetAudioClip((int)SoundClips.AmbientCrickets);
                dfAudioSource.AudioSource.clip         = cricketsLoop;
                dfAudioSource.AudioSource.loop         = true;
                dfAudioSource.AudioSource.spatialBlend = 0;
                dfAudioSource.AudioSource.Play();
            }

            // Tick counter
            waitCounter += Time.deltaTime;
            if (waitCounter > waitTime)
            {
                PlayEffects();
                StartWaiting();
            }
        }
Beispiel #4
0
        void Update()
        {
            // Change sound presets
            if (Presets != lastPresets)
            {
                lastPresets = Presets;
                rainLoop    = null;
                ApplyPresets();
                StartWaiting();
            }

            // Start rain loop if not running
            if ((Presets == AmbientSoundPresets.Rain || Presets == AmbientSoundPresets.Storm) && rainLoop == null)
            {
                rainLoop = dfAudioSource.GetAudioClip((int)SoundClips.AmbientRaining, false);
                dfAudioSource.AudioSource.clip = rainLoop;
                dfAudioSource.AudioSource.loop = true;
                dfAudioSource.AudioSource.Play();
            }

            // Tick counter
            waitCounter += Time.deltaTime;
            if (waitCounter > waitTime)
            {
                PlayEffects();
                StartWaiting();
            }
        }
        // Initialise.
        void Start()
        {
            playerMotor = GetComponent <PlayerMotor>();
            if (!playerMotor)
            {
                throw new Exception("PlayerMotor not found.");
            }

            transportManager = GetComponent <TransportManager>();
            if (!transportManager)
            {
                throw new Exception("TransportManager not found.");
            }
            transportManager.DrawHorse = false;

            playerMouseLook = GameManager.Instance.PlayerMouseLook;
            if (!playerMouseLook)
            {
                throw new Exception("PlayerMouseLook not found.");
            }

            dfAudioSource = GetComponent <DaggerfallAudioSource>();
            if (!dfAudioSource)
            {
                throw new Exception("DaggerfallAudioSource not found.");
            }

            trampleMaleClip   = dfAudioSource.GetAudioClip((int)trampleMale);
            trampleFemaleClip = dfAudioSource.GetAudioClip((int)trampleFemale);

            GameManager.Instance.SpeedChanger.CanRun = CanRunUnlessRidingCart;

            // Setup appropriate neck textures if availiable.
            for (int i = 0; i < 4; i++)
            {
                TextureReplacement.TryImportCifRci(horseNeckTextureName, 0, i, false, out horseNeckTextures[i].texture);
            }
            for (int i = 0; i < 4; i++)
            {
                TextureReplacement.TryImportCifRci(cartNeckTextureName, 0, i, false, out cartNeckTextures[i].texture);
            }
        }
Beispiel #6
0
        void FixedUpdate()
        {
            // Load clip
            // Check this here as dynamic clip may need to be reloaded
            if (clip == null)
            {
                clip = dfAudioSource.GetAudioClip((int)FootstepSound, false);
            }

            // Check if player is grounded
            if (!IsGrounded())
            {
                // Player has lost grounding
                distance      = 0f;
                lostGrounding = true;
                return;
            }
            else
            {
                // Player is grounded but we might need to reset after losing grounding
                if (lostGrounding)
                {
                    distance      = 0f;
                    lastPosition  = GetHorizontalPosition();
                    lostGrounding = false;
                    return;
                }
            }

            // Get distance player travelled horizontally
            Vector3 position = GetHorizontalPosition();

            distance    += Vector3.Distance(position, lastPosition);
            lastPosition = position;

            // Get threshold
            float threshold = WalkStepInterval;

            if (playerMotor)
            {
                threshold = (playerMotor.IsRunning) ? RunStepInterval : WalkStepInterval;
            }

            // Play sound if over distance threshold
            if (distance > threshold && customAudioSource && clip)
            {
                // Set a random pitch so footsteps don't sound too mechanical
                customAudioSource.pitch = Random.Range(1f - PitchVariance, 1f + PitchVariance);
                customAudioSource.PlayOneShot(clip, FootstepVolumeScale);
                distance = 0f;
            }
        }
Beispiel #7
0
        private bool IsReady()
        {
            if (dfAudioSource == null)
            {
                return(false);
            }

            if (!moveClip)
            {
                moveClip = dfAudioSource.GetAudioClip((int)MoveSound);
            }
            if (!barkClip)
            {
                barkClip = dfAudioSource.GetAudioClip((int)BarkSound);
            }
            if (!attackClip)
            {
                attackClip = dfAudioSource.GetAudioClip((int)AttackSound);
            }

            return(true);
        }
Beispiel #8
0
        // Use this for initialization
        void Start()
        {
            dfAudioSource = GetComponent <DaggerfallAudioSource>();
            playerMotor   = GetComponent <PlayerMotor>();

            // Use custom audio source as we don't want to affect other sounds while riding.
            ridingAudioSource              = gameObject.AddComponent <AudioSource>();
            ridingAudioSource.hideFlags    = HideFlags.HideInInspector;
            ridingAudioSource.playOnAwake  = false;
            ridingAudioSource.loop         = false;
            ridingAudioSource.dopplerLevel = 0f;
            ridingAudioSource.spatialBlend = 0f;
            ridingAudioSource.volume       = RidingVolumeScale * DaggerfallUnity.Settings.SoundVolume;

            neighClip = dfAudioSource.GetAudioClip((int)horseSound);

            // Init event listener for transitions.
            PlayerEnterExit.OnPreTransition += new PlayerEnterExit.OnPreTransitionEventHandler(HandleTransition);
        }
        public AudioClip GetRandomClip(DaggerfallAudioSource source)
        {
            int max = soundClips.Count + audioClips.Count;

            if (max == 0)
            {
                return(null);
            }

            int rand = Random.Range(0, soundClips.Count + audioClips.Count);

            if (rand < soundClips.Count)
            {
                return(source.GetAudioClip((int)soundClips[rand]));
            }
            else
            {
                return(audioClips[rand]);
            }
        }
        void Update()
        {
            // Change sound presets
            if (Presets != lastPresets)
            {
                // Clear settings
                lastPresets  = Presets;
                rainLoop     = null;
                cricketsLoop = null;

                // Stop playing any loops
                if (dfAudioSource.AudioSource.isPlaying)
                {
                    dfAudioSource.AudioSource.Stop();
                    dfAudioSource.AudioSource.clip = null;
                    dfAudioSource.AudioSource.loop = false;
                }

                ApplyPresets();
                StartWaiting();
            }

            // Start rain loop if not running
            if ((Presets == AmbientSoundPresets.Rain || Presets == AmbientSoundPresets.Storm) && rainLoop == null)
            {
                rainLoop = dfAudioSource.GetAudioClip((int)SoundClips.AmbientRaining);
                dfAudioSource.AudioSource.clip         = rainLoop;
                dfAudioSource.AudioSource.loop         = true;
                dfAudioSource.AudioSource.spatialBlend = 0;
                dfAudioSource.AudioSource.Play();
            }

            // Start crickets loop if not running
            if ((Presets == AmbientSoundPresets.ClearNight) && cricketsLoop == null)
            {
                cricketsLoop = dfAudioSource.GetAudioClip((int)SoundClips.AmbientCrickets);
                dfAudioSource.AudioSource.clip         = cricketsLoop;
                dfAudioSource.AudioSource.loop         = true;
                dfAudioSource.AudioSource.spatialBlend = 0;
                dfAudioSource.AudioSource.Play();
            }

            // Tick counters
            waitCounter      += Time.deltaTime;
            waterWaitCounter += Time.deltaTime;
            if (waitCounter > waitTime)
            {
                PlayEffects();
                StartWaiting();
            }

            // Play water sound effects. Timing and position based on classic behavior.
            // TODO: Make sound follow player's X and Z movement but play from Y coordinate of dungeon water, for a more dynamically 3d sound.
            // Currently the sound is a volume adjustment based on vertical distance from the water.
            if (waterWaitCounter > waterSoundWaitTime)
            {
                if (playerEnterExit == null)
                {
                    playerEnterExit = GameManager.Instance.PlayerEnterExit;
                }
                if (playerEnterExit)
                {
                    if (playerEnterExit.blockWaterLevel != 10000)
                    {
                        Entity.DaggerfallEntityBehaviour player = GameManager.Instance.PlayerEntityBehaviour;
                        // Chance to play gentle water sound based on vertical distance between player and water surface
                        if (DFRandom.rand() < 50)
                        {
                            float waterHeightInDFUnityUnits = (playerEnterExit.blockWaterLevel * -1 * MeshReader.GlobalScale);
                            float volumeScale = Mathf.Clamp(1 - (Mathf.Abs(player.transform.position.y - waterHeightInDFUnityUnits) / 9), 0, 1);
                            dfAudioSource.PlayOneShot((int)SoundClips.WaterGentle, 0, volumeScale);
                        }

                        // Chance to play underwater bubbling noise if player is underwater
                        if (playerEnterExit.IsPlayerSubmerged)
                        {
                            if (DFRandom.rand() < 100)
                            {
                                dfAudioSource.PlayOneShot((int)SoundClips.AmbientWaterBubbles, 0);
                            }
                        }
                    }
                }
                waterWaitCounter = 0;
            }
        }
Beispiel #11
0
        void FixedUpdate()
        {
            // Get player inside flag
            // Can only do this when PlayerEnterExit is available, otherwise default to true
            bool playerInside = (playerEnterExit == null) ? true : playerEnterExit.IsPlayerInside;

            // Change footstep sounds between winter/summer variants or when player enters/exits an interior space
            if (dfUnity.WorldTime.Now.SeasonValue != currentSeason || isInside != playerInside)
            {
                currentSeason = dfUnity.WorldTime.Now.SeasonValue;
                isInside      = playerInside;
                if (currentSeason == DaggerfallDateTime.Seasons.Winter && !isInside)
                {
                    currentFootstepSound = FootstepSoundSnow;
                }
                else
                {
                    currentFootstepSound = FootstepSoundNormal;
                }

                clip = null;
            }

            // Reload clip if needed
            if (clip == null)
            {
                clip = dfAudioSource.GetAudioClip((int)currentFootstepSound);
            }

            // Check if player is grounded
            if (!IsGrounded())
            {
                // Player has lost grounding
                distance      = 0f;
                lostGrounding = true;
                return;
            }
            else
            {
                // Player is grounded but we might need to reset after losing grounding
                if (lostGrounding)
                {
                    distance      = 0f;
                    lastPosition  = GetHorizontalPosition();
                    lostGrounding = false;
                    return;
                }
            }

            // Get distance player travelled horizontally
            Vector3 position = GetHorizontalPosition();

            distance    += Vector3.Distance(position, lastPosition);
            lastPosition = position;

            // Get threshold
            float threshold = WalkStepInterval;

            if (playerMotor)
            {
                threshold = (playerMotor.IsRunning) ? RunStepInterval : WalkStepInterval;
            }

            // Play sound if over distance threshold
            if (distance > threshold && customAudioSource && clip)
            {
                // Set a random pitch so footsteps don't sound too mechanical
                customAudioSource.pitch = Random.Range(1f - PitchVariance, 1f + PitchVariance);
                customAudioSource.PlayOneShot(clip, FootstepVolumeScale);
                distance = 0f;
            }
        }
Beispiel #12
0
 public AudioClip GetAudioClip(SoundClips clip)
 {
     return(dfAudioSource.GetAudioClip((int)clip));
 }
        void FixedUpdate()
        {
            DaggerfallDateTime.Seasons playerSeason = dfUnity.WorldTime.Now.SeasonValue;
            int playerClimateIndex = GameManager.Instance.PlayerGPS.CurrentClimateIndex;

            // Get player inside flag
            // Can only do this when PlayerEnterExit is available, otherwise default to true
            bool playerInside     = (playerEnterExit == null) ? true : playerEnterExit.IsPlayerInside;
            bool playerInBuilding = (playerEnterExit == null) ? false : playerEnterExit.IsPlayerInsideBuilding;

            // Play splash footsteps whether player is walking on or swimming in exterior water
            bool playerOnExteriorWater = (GameManager.Instance.PlayerMotor.OnExteriorWater == PlayerMotor.OnExteriorWaterMethod.Swimming || GameManager.Instance.PlayerMotor.OnExteriorWater == PlayerMotor.OnExteriorWaterMethod.WaterWalking);

            // Change footstep sounds between winter/summer variants or when player enters/exits an interior space
            if (playerSeason != currentSeason || playerClimateIndex != currentClimateIndex || isInside != playerInside || playerOnExteriorWater != isInOutsideWater)
            {
                currentSeason       = playerSeason;
                currentClimateIndex = playerClimateIndex;
                isInside            = playerInside;
                isInOutsideWater    = playerOnExteriorWater;
                if (!isInside)
                {
                    if (currentSeason == DaggerfallDateTime.Seasons.Winter && !WeatherManager.IsSnowFreeClimate(currentClimateIndex))
                    {
                        currentFootstepSound1 = FootstepSoundSnow1;
                        currentFootstepSound2 = FootstepSoundSnow2;
                    }
                    else
                    {
                        currentFootstepSound1 = FootstepSoundOutside1;
                        currentFootstepSound2 = FootstepSoundOutside2;
                    }
                }
                else if (playerInBuilding)
                {
                    currentFootstepSound1 = FootstepSoundBuilding1;
                    currentFootstepSound2 = FootstepSoundBuilding2;
                }
                else // in dungeon
                {
                    currentFootstepSound1 = FootstepSoundDungeon1;
                    currentFootstepSound2 = FootstepSoundDungeon2;
                }

                clip1 = null;
                clip2 = null;
            }

            // walking on water tile
            if (playerOnExteriorWater)
            {
                currentFootstepSound1 = FootstepSoundSubmerged;
                currentFootstepSound2 = FootstepSoundSubmerged;
                clip1 = null;
                clip2 = null;
            }

            // Use water sounds if in dungeon water
            if (GameManager.Instance.PlayerEnterExit.IsPlayerInsideDungeon && playerEnterExit.blockWaterLevel != 10000)
            {
                // In water, deep depth
                if ((currentFootstepSound1 != FootstepSoundSubmerged) && playerEnterExit.IsPlayerSwimming)
                {
                    currentFootstepSound1 = FootstepSoundSubmerged;
                    currentFootstepSound2 = FootstepSoundSubmerged;
                    clip1 = null;
                    clip2 = null;
                }
                // In water, shallow depth
                else if ((currentFootstepSound1 != FootstepSoundShallow) && !playerEnterExit.IsPlayerSwimming && (playerMotor.transform.position.y - 0.95f) < (playerEnterExit.blockWaterLevel * -1 * MeshReader.GlobalScale))
                {
                    currentFootstepSound1 = FootstepSoundShallow;
                    currentFootstepSound2 = FootstepSoundShallow;
                    clip1 = null;
                    clip2 = null;
                }
            }

            // Not in water, reset footsteps to normal
            if ((!playerOnExteriorWater) &&
                (currentFootstepSound1 == FootstepSoundSubmerged || currentFootstepSound1 == FootstepSoundShallow) &&
                (playerEnterExit.blockWaterLevel == 10000 || (playerMotor.transform.position.y - 0.95f) >= (playerEnterExit.blockWaterLevel * -1 * MeshReader.GlobalScale)))
            {
                currentFootstepSound1 = FootstepSoundDungeon1;
                currentFootstepSound2 = FootstepSoundDungeon2;

                clip1 = null;
                clip2 = null;
            }

            // Reload clips if needed
            if (clip1 == null)
            {
                clip1 = dfAudioSource.GetAudioClip((int)currentFootstepSound1);
            }
            if (clip2 == null)
            {
                clip2 = dfAudioSource.GetAudioClip((int)currentFootstepSound2);
            }

            // Check whether player is on foot and abort playing footsteps if not.
            if (playerMotor.IsLevitating || !transportManager.IsOnFoot && GameManager.Instance.PlayerMotor.OnExteriorWater == PlayerMotor.OnExteriorWaterMethod.None)
            {
                distance = 0f;
                return;
            }

            // Check if player is grounded
            // Note: In classic, submerged "footstep" sound is only played when walking on the floor while in the water, but it sounds like a swimming sound
            // and when outside is played while swimming at the water's surface, so it seems better to play it all the time while submerged in water.
            if (currentFootstepSound1 != FootstepSoundSubmerged)
            {
                if (!IsGrounded())
                {
                    // Player has lost grounding
                    distance      = 0f;
                    lostGrounding = true;
                    return;
                }
                else
                {
                    // Player is grounded but we might need to reset after losing grounding
                    if (lostGrounding)
                    {
                        distance      = 0f;
                        lastPosition  = GetHorizontalPosition();
                        lostGrounding = false;
                        return;
                    }
                }
            }

            // Get distance player travelled horizontally
            Vector3 position = GetHorizontalPosition();

            distance    += Vector3.Distance(position, lastPosition);
            lastPosition = position;

            // Get threshold
            float threshold = WalkStepInterval;

            if (playerMotor)
            {
                threshold = (playerMotor.IsRunning) ? RunStepInterval : WalkStepInterval;
            }

            // Play sound if over distance threshold
            if (distance > threshold && customAudioSource && clip1 && clip2)
            {
                float volumeScale = FootstepVolumeScale;
                if (playerMotor.IsMovingLessThanHalfSpeed)
                {
                    volumeScale *= 0.5f;
                }

                if (!alternateStep)
                {
                    customAudioSource.PlayOneShot(clip1, volumeScale * DaggerfallUnity.Settings.SoundVolume);
                }
                else
                {
                    customAudioSource.PlayOneShot(clip2, volumeScale * DaggerfallUnity.Settings.SoundVolume);
                }

                alternateStep = (!alternateStep);
                distance      = 0f;
            }
        }
Beispiel #14
0
        void FixedUpdate()
        {
            // Change footstep sounds between winter/summer variants
            if (dfUnity.WorldTime.SeasonValue != lastSeason)
            {
                lastSeason = dfUnity.WorldTime.SeasonValue;
                if (lastSeason == WorldTime.Seasons.Winter)
                {
                    currentFootstepSound = FootstepSoundSnow;
                }
                else
                {
                    currentFootstepSound = FootstepSoundNormal;
                }

                dfAudioSource.GetAudioClip((int)currentFootstepSound, false);
            }

            // Always check clip is loaded
            if (clip == null)
            {
                clip = dfAudioSource.GetAudioClip((int)currentFootstepSound, false);
            }

            // Check if player is grounded
            if (!IsGrounded())
            {
                // Player has lost grounding
                distance      = 0f;
                lostGrounding = true;
                return;
            }
            else
            {
                // Player is grounded but we might need to reset after losing grounding
                if (lostGrounding)
                {
                    distance      = 0f;
                    lastPosition  = GetHorizontalPosition();
                    lostGrounding = false;
                    return;
                }
            }

            // Get distance player travelled horizontally
            Vector3 position = GetHorizontalPosition();

            distance    += Vector3.Distance(position, lastPosition);
            lastPosition = position;

            // Get threshold
            float threshold = WalkStepInterval;

            if (playerMotor)
            {
                threshold = (playerMotor.IsRunning) ? RunStepInterval : WalkStepInterval;
            }

            // Play sound if over distance threshold
            if (distance > threshold && customAudioSource && clip)
            {
                // Set a random pitch so footsteps don't sound too mechanical
                customAudioSource.pitch = Random.Range(1f - PitchVariance, 1f + PitchVariance);
                customAudioSource.PlayOneShot(clip, FootstepVolumeScale);
                distance = 0f;
            }
        }
        private void UpdateMode(TransportModes transportMode)
        {
            // Update the transport mode and stop any riding sounds playing.
            mode = transportMode;
            if (ridingAudioSource.isPlaying)
            {
                ridingAudioSource.Stop();
            }

            if (mode == TransportModes.Horse || mode == TransportModes.Cart)
            {
                // Tell player motor we're riding. TODO: Change to event system so other classes can listen for transport changes.
                playerMotor.IsRiding = true;

                // Setup appropriate riding sounds.
                SoundClips sound = (mode == TransportModes.Horse) ? horseRidingSound : cartRidingSound;
                ridingAudioSource.clip = dfAudioSource.GetAudioClip((int)sound);

                // Setup appropriate riding textures.
                string textureName = (mode == TransportModes.Horse) ? horseTextureName : cartTextureName;
                for (int i = 0; i < 4; i++)
                {
                    ridingTexures[i] = ImageReader.GetImageData(textureName, 0, i, true, true);
                }
                ridingTexure = ridingTexures[0];

                // Initialise neighing timer.
                neighTime = Time.time + Random.Range(1, 5);
            }
            else
            {
                // Tell player motor we're not riding.
                playerMotor.IsRiding = false;
            }

            if (mode == TransportModes.Ship)
            {
                GameManager.Instance.PlayerMotor.CancelMovement = true;
                SerializablePlayer serializablePlayer = GetComponent <SerializablePlayer>();
                DaggerfallUI.Instance.SmashHUDToBlack();

                // Is player on board ship?
                if (boardShipPosition != null)
                {
                    // Check for terrain sampler changes. (so don't fall through floor)
                    StreamingWorld.RepositionMethods reposition = StreamingWorld.RepositionMethods.None;
                    if (boardShipPosition.terrainSamplerName != DaggerfallUnity.Instance.TerrainSampler.ToString() ||
                        boardShipPosition.terrainSamplerVersion != DaggerfallUnity.Instance.TerrainSampler.Version)
                    {
                        reposition = StreamingWorld.RepositionMethods.RandomStartMarker;
                        if (DaggerfallUI.Instance.DaggerfallHUD != null)
                        {
                            DaggerfallUI.Instance.DaggerfallHUD.PopupText.AddText("Terrain sampler changed. Repositioning player.");
                        }
                    }
                    // Restore player position from before boarding ship.
                    DFPosition mapPixel = MapsFile.WorldCoordToMapPixel(boardShipPosition.worldPosX, boardShipPosition.worldPosZ);
                    GameManager.Instance.StreamingWorld.TeleportToCoordinates(mapPixel.X, mapPixel.Y, reposition);
                    serializablePlayer.RestorePosition(boardShipPosition);
                    boardShipPosition = null;
                }
                else
                {
                    // Record current player position before boarding ship.
                    boardShipPosition = serializablePlayer.GetPlayerPositionData();

                    // Teleport to ship
                    GameManager.Instance.StreamingWorld.TeleportToCoordinates(2, 2, StreamingWorld.RepositionMethods.RandomStartMarker);
                }
                DaggerfallUI.Instance.FadeHUDFromBlack();
                mode = TransportModes.Foot;
            }
        }
        void Update()
        {
            // Change sound presets
            if (Presets != lastPresets)
            {
                // Clear settings
                lastPresets  = Presets;
                rainLoop     = null;
                cricketsLoop = null;

                // Stop playing any loops
                if (dfAudioSource.AudioSource.isPlaying)
                {
                    dfAudioSource.AudioSource.Stop();
                    dfAudioSource.AudioSource.clip = null;
                    dfAudioSource.AudioSource.loop = false;
                }

                ApplyPresets();
                StartWaiting();
            }

            // Update sound volume
            dfAudioSource.AudioSource.volume = DaggerfallUnity.Settings.SoundVolume;

            // Start rain loop if not running
            if ((Presets == AmbientSoundPresets.Rain || Presets == AmbientSoundPresets.Storm) && rainLoop == null)
            {
                rainLoop = dfAudioSource.GetAudioClip((int)SoundClips.AmbientRaining);
                dfAudioSource.AudioSource.clip         = rainLoop;
                dfAudioSource.AudioSource.loop         = true;
                dfAudioSource.AudioSource.spatialBlend = 0;
                dfAudioSource.AudioSource.Play();
            }

            // Start crickets loop if not running
            if ((Presets == AmbientSoundPresets.ClearNight) && cricketsLoop == null)
            {
                cricketsLoop = dfAudioSource.GetAudioClip((int)SoundClips.AmbientCrickets);
                dfAudioSource.AudioSource.clip         = cricketsLoop;
                dfAudioSource.AudioSource.loop         = true;
                dfAudioSource.AudioSource.spatialBlend = 0;
                dfAudioSource.AudioSource.Play();
            }

            // Tick counters
            waitCounter      += Time.deltaTime;
            waterWaitCounter += Time.deltaTime;
            if (waitCounter > waitTime)
            {
                PlayEffects();
                StartWaiting();
            }

            // Play water sound effects. Timing based on classic.
            if (waterWaitCounter > Entity.PlayerEntity.ClassicUpdateInterval)
            {
                if (playerEnterExit && playerEnterExit.blockWaterLevel != 10000)
                {
                    // Chance to play gentle water sound at water surface
                    if (DFRandom.rand() < 50)
                    {
                        Vector3 waterSoundPosition = playerBehaviour.transform.position;
                        waterSoundPosition.y             = playerEnterExit.blockWaterLevel * -1 * MeshReader.GlobalScale;
                        waterSoundPosition.x            += Random.Range(-3, 3);
                        waterSoundPosition.y            += Random.Range(-3, 3);
                        dfAudioSource.transform.position = waterSoundPosition;
                        dfAudioSource.PlayOneShot((int)SoundClips.WaterGentle, 1, 3f);
                    }

                    // Chance to play water bubbles sound if player is underwater
                    if (playerEnterExit.IsPlayerSubmerged && DFRandom.rand() < 100)
                    {
                        dfAudioSource.PlayOneShot((int)SoundClips.AmbientWaterBubbles, 0);
                    }
                }
                waterWaitCounter = 0;
            }
        }