Unstable 0.17.0.0

This commit is contained in:
Markus Isberg
2022-02-26 02:43:01 +09:00
parent a83f375681
commit 3974067915
913 changed files with 32472 additions and 32364 deletions
@@ -9,78 +9,28 @@ using System.Xml.Linq;
namespace Barotrauma
{
public struct DamageSound
{
//the range of inflicted damage where the sound can be played
//(10.0f, 30.0f) would be played when the inflicted damage is between 10 and 30
public readonly Vector2 damageRange;
public readonly string damageType;
public readonly Sound sound;
public readonly string requiredTag;
public bool ignoreMuffling;
public DamageSound(Sound sound, Vector2 damageRange, string damageType, bool ignoreMuffling, string requiredTag = "")
{
this.sound = sound;
this.damageRange = damageRange;
this.damageType = damageType;
this.ignoreMuffling = ignoreMuffling;
this.requiredTag = requiredTag;
}
}
public class BackgroundMusic
{
public readonly string File;
public readonly string Type;
public readonly bool DuckVolume;
public readonly float Volume;
public readonly Vector2 IntensityRange;
public readonly bool ContinueFromPreviousTime;
public int PreviousTime;
public readonly XElement Element;
public BackgroundMusic(XElement element)
{
this.File = Path.GetFullPath(element.GetAttributeString("file", "")).CleanUpPath();
this.Type = element.GetAttributeString("type", "").ToLowerInvariant();
this.IntensityRange = element.GetAttributeVector2("intensityrange", new Vector2(0.0f, 100.0f));
this.DuckVolume = element.GetAttributeBool("duckvolume", false);
this.Volume = element.GetAttributeFloat("volume", 1.0f);
this.ContinueFromPreviousTime = element.GetAttributeBool("continuefromprevioustime", false);
this.Element = element;
}
}
static class SoundPlayer
{
private static ILookup<string, Sound> miscSounds;
//music
private const float MusicLerpSpeed = 1.0f;
private const float UpdateMusicInterval = 5.0f;
const int MaxMusicChannels = 6;
private readonly static Sound[] currentMusic = new Sound[MaxMusicChannels];
private readonly static BackgroundMusic[] currentMusic = new BackgroundMusic[MaxMusicChannels];
private readonly static SoundChannel[] musicChannel = new SoundChannel[MaxMusicChannels];
private readonly static BackgroundMusic[] targetMusic = new BackgroundMusic[MaxMusicChannels];
private static List<BackgroundMusic> musicClips;
private static IEnumerable<BackgroundMusic> musicClips => BackgroundMusic.BackgroundMusicPrefabs;
private static BackgroundMusic previousDefaultMusic;
private static float updateMusicTimer;
//ambience
private static Sound waterAmbienceIn, waterAmbienceOut, waterAmbienceMoving;
private static readonly SoundChannel[] waterAmbienceChannels = new SoundChannel[3];
private static Sound waterAmbienceIn => SoundPrefab.WaterAmbienceIn.ActivePrefab.Sound;
private static Sound waterAmbienceOut => SoundPrefab.WaterAmbienceOut.ActivePrefab.Sound;
private static Sound waterAmbienceMoving => SoundPrefab.WaterAmbienceMoving.ActivePrefab.Sound;
private static readonly HashSet<SoundChannel> waterAmbienceChannels = new HashSet<SoundChannel>();
private static float ambientSoundTimer;
private static Vector2 ambientSoundInterval = new Vector2(20.0f, 40.0f); //x = min, y = max
@@ -92,8 +42,8 @@ namespace Barotrauma
//misc
private static float[] targetFlowLeft, targetFlowRight;
public static List<Sound> FlowSounds = new List<Sound>();
public static List<Sound> SplashSounds = new List<Sound>();
public static IReadOnlyList<SoundPrefab> FlowSounds => SoundPrefab.FlowSounds;
public static IReadOnlyList<SoundPrefab> SplashSounds => SoundPrefab.SplashSounds;
private static SoundChannel[] flowSoundChannels;
private static float[] flowVolumeLeft;
private static float[] flowVolumeRight;
@@ -112,17 +62,13 @@ namespace Barotrauma
private static string[] fireSoundTags = new string[fireSizes] { "fire", "firemedium", "firelarge" };
// TODO: could use a dictionary to split up the list into smaller lists of same type?
private static List<DamageSound> damageSounds;
private static Dictionary<GUISoundType, List<Sound>> guiSounds;
private static IEnumerable<DamageSound> damageSounds => DamageSound.DamageSoundPrefabs;
private static bool firstTimeInMainMenu = true;
private static Sound startUpSound;
private static Sound startUpSound => SoundPrefab.StartupSound.ActivePrefab.Sound;
public static bool Initialized;
public static string OverrideMusicType
public static Identifier OverrideMusicType
{
get;
set;
@@ -130,291 +76,35 @@ namespace Barotrauma
public static float? OverrideMusicDuration;
public static int SoundCount;
private static List<XElement> loadedSoundElements;
private static bool SoundElementsEquivalent(XElement a, XElement b)
{
string filePathA = a.GetAttributeString("file", "").CleanUpPath();
float baseGainA = a.GetAttributeFloat("volume", 1.0f);
float rangeA = a.GetAttributeFloat("range", 1000.0f);
string filePathB = b.GetAttributeString("file", "").CleanUpPath();
float baseGainB = b.GetAttributeFloat("volume", 1.0f);
float rangeB = b.GetAttributeFloat("range", 1000.0f);
return a.Name.ToString().Equals(b.Name.ToString(), StringComparison.OrdinalIgnoreCase) &&
filePathA == filePathB && MathUtils.NearlyEqual(baseGainA, baseGainB) &&
MathUtils.NearlyEqual(rangeA, rangeB);
}
public static IEnumerable<CoroutineStatus> Init()
{
OverrideMusicType = null;
var soundFiles = GameMain.Instance.GetFilesOfType(ContentType.Sounds).ToList();
List<XElement> soundElements = new List<XElement>();
foreach (ContentFile soundFile in soundFiles)
{
XDocument doc = XMLExtensions.TryLoadXml(soundFile.Path);
if (doc == null) { continue; }
var mainElement = doc.Root;
if (doc.Root.IsOverride())
{
mainElement = doc.Root.FirstElement();
DebugConsole.NewMessage($"Overriding all sounds with {soundFile.Path}", Color.Yellow);
soundElements.Clear();
}
soundElements.AddRange(mainElement.Elements());
}
SoundCount = 1 + soundElements.Count();
var startUpSoundElement = soundElements.Find(e => e.Name.ToString().Equals("startupsound", StringComparison.OrdinalIgnoreCase));
if (startUpSoundElement != null)
{
startUpSound = GameMain.SoundManager.LoadSound(startUpSoundElement, false);
startUpSound?.Play();
}
yield return CoroutineStatus.Running;
List<KeyValuePair<string, Sound>> miscSoundList = new List<KeyValuePair<string, Sound>>();
damageSounds ??= new List<DamageSound>();
musicClips ??= new List<BackgroundMusic>();
guiSounds ??= new Dictionary<GUISoundType, List<Sound>>();
bool firstWaterAmbienceLoaded = false;
foreach (XElement soundElement in soundElements)
{
yield return CoroutineStatus.Running;
if (loadedSoundElements != null && loadedSoundElements.Any(e => SoundElementsEquivalent(e, soundElement)))
{
continue;
}
try
{
switch (soundElement.Name.ToString().ToLowerInvariant())
{
case "music":
var newMusicClip = new BackgroundMusic(soundElement);
if (File.Exists(newMusicClip.File))
{
musicClips.AddIfNotNull(newMusicClip);
if (loadedSoundElements != null)
{
if (newMusicClip.Type.Equals("menu", StringComparison.OrdinalIgnoreCase))
{
targetMusic[0] = newMusicClip;
}
}
}
else
{
DebugConsole.NewMessage($"Music file \"{newMusicClip.File}\" not found.");
}
break;
case "splash":
SplashSounds.AddIfNotNull(GameMain.SoundManager.LoadSound(soundElement, false));
break;
case "flow":
FlowSounds.AddIfNotNull(GameMain.SoundManager.LoadSound(soundElement, false));
break;
case "waterambience":
//backwards compatibility (1st waterambience used to be played both inside and outside, 2nd when moving)
if (!firstWaterAmbienceLoaded)
{
waterAmbienceIn?.Dispose();
waterAmbienceOut?.Dispose();
if (File.Exists(soundElement.GetAttributeString("file", "")))
{
waterAmbienceIn = GameMain.SoundManager.LoadSound(soundElement, false);
waterAmbienceOut = GameMain.SoundManager.LoadSound(soundElement, false);
}
else
{
waterAmbienceIn = GameMain.SoundManager.LoadSound(soundElement, false, "Content/Sounds/Water/WaterAmbienceIn.ogg");
waterAmbienceOut = GameMain.SoundManager.LoadSound(soundElement, false, "Content/Sounds/Water/WaterAmbienceOut.ogg");
}
firstWaterAmbienceLoaded = true;
}
else
{
waterAmbienceMoving?.Dispose();
if (File.Exists(soundElement.GetAttributeString("file", "")))
{
waterAmbienceMoving = GameMain.SoundManager.LoadSound(soundElement, false);
}
else
{
waterAmbienceMoving = GameMain.SoundManager.LoadSound(soundElement, false, "Content/Sounds/Water/WaterAmbienceMoving.ogg");
}
}
break;
case "waterambiencein":
waterAmbienceIn?.Dispose();
waterAmbienceIn = GameMain.SoundManager.LoadSound(soundElement, false);
break;
case "waterambienceout":
waterAmbienceOut?.Dispose();
waterAmbienceOut = GameMain.SoundManager.LoadSound(soundElement, false);
break;
case "waterambiencemoving":
waterAmbienceMoving?.Dispose();
waterAmbienceMoving = GameMain.SoundManager.LoadSound(soundElement, false);
break;
case "damagesound":
Sound damageSound = GameMain.SoundManager.LoadSound(soundElement, false);
if (damageSound == null) { continue; }
string damageSoundType = soundElement.GetAttributeString("damagesoundtype", "None");
damageSounds.Add(new DamageSound(
damageSound,
soundElement.GetAttributeVector2("damagerange", Vector2.Zero),
damageSoundType,
soundElement.GetAttributeBool("ignoremuffling", false),
soundElement.GetAttributeString("requiredtag", "")));
break;
case "guisound":
Sound guiSound = GameMain.SoundManager.LoadSound(soundElement, stream: false);
if (guiSound == null) { continue; }
if (Enum.TryParse(soundElement.GetAttributeString("guisoundtype", null), true, out GUISoundType soundType))
{
if (guiSounds.ContainsKey(soundType))
{
guiSounds[soundType].Add(guiSound);
}
else
{
guiSounds.Add(soundType, new List<Sound>() { guiSound });
}
}
break;
default:
Sound sound = GameMain.SoundManager.LoadSound(soundElement, false);
if (sound != null)
{
miscSoundList.Add(new KeyValuePair<string, Sound>(soundElement.Name.ToString().ToLowerInvariant(), sound));
}
break;
}
}
catch (System.IO.FileNotFoundException e)
{
DebugConsole.ThrowError("Error while initializing SoundPlayer.", e);
}
}
musicClips.RemoveAll(mc => !soundElements.Any(e => SoundElementsEquivalent(mc.Element, e)));
for (int i = 0; i < currentMusic.Length; i++)
{
if (currentMusic[i] != null && !musicClips.Any(mc => mc.File == currentMusic[i].Filename))
{
DisposeMusicChannel(i);
}
}
SplashSounds.ForEach(s =>
{
if (!soundElements.Any(e => SoundElementsEquivalent(s.XElement, e))) { s.Dispose(); }
});
SplashSounds.RemoveAll(s => s.Disposed);
FlowSounds.ForEach(s =>
{
if (!soundElements.Any(e => SoundElementsEquivalent(s.XElement, e))) { s.Dispose(); }
});
FlowSounds.RemoveAll(s => s.Disposed);
damageSounds.ForEach(s =>
{
if (!soundElements.Any(e => SoundElementsEquivalent(s.sound.XElement, e))) { s.sound.Dispose(); }
});
damageSounds.RemoveAll(s => s.sound.Disposed);
guiSounds.ForEach(kvp =>
{
kvp.Value?.ForEach(s =>
{
if (!soundElements.Any(e => SoundElementsEquivalent(s.XElement, e))) { s.Dispose(); }
});
});
guiSounds.ForEach(kvp => kvp.Value?.RemoveAll(s => s.Disposed));
miscSounds?.ForEach(g => g.ForEach(s =>
{
if (!soundElements.Any(e => SoundElementsEquivalent(s.XElement, e))) { s.Dispose(); }
else { miscSoundList.Add(new KeyValuePair<string, Sound>(g.Key, s)); }
}));
flowSoundChannels?.ForEach(ch => ch?.Dispose());
flowSoundChannels = new SoundChannel[FlowSounds.Count];
flowVolumeLeft = new float[FlowSounds.Count];
flowVolumeRight = new float[FlowSounds.Count];
targetFlowLeft = new float[FlowSounds.Count];
targetFlowRight = new float[FlowSounds.Count];
fireSoundChannels?.ForEach(ch => ch?.Dispose());
fireSoundChannels = new SoundChannel[fireSizes];
fireVolumeLeft = new float[fireSizes];
fireVolumeRight = new float[fireSizes];
miscSounds = miscSoundList.ToLookup(kvp => kvp.Key, kvp => kvp.Value);
Initialized = true;
loadedSoundElements = soundElements;
yield return CoroutineStatus.Success;
}
public static void Update(float deltaTime)
{
if (!Initialized) { return; }
UpdateMusic(deltaTime);
if (startUpSound != null && !GameMain.SoundManager.IsPlaying(startUpSound))
if (flowSoundChannels == null || flowSoundChannels.Length != FlowSounds.Count)
{
startUpSound.Dispose();
startUpSound = null;
flowSoundChannels = new SoundChannel[FlowSounds.Count];
flowVolumeLeft = new float[FlowSounds.Count];
flowVolumeRight = new float[FlowSounds.Count];
targetFlowLeft = new float[FlowSounds.Count];
targetFlowRight = new float[FlowSounds.Count];
}
if (fireSoundChannels == null || fireSoundChannels.Length != fireSizes)
{
fireSoundChannels = new SoundChannel[fireSizes];
fireVolumeLeft = new float[fireSizes];
fireVolumeRight = new float[fireSizes];
}
//stop water sounds if no sub is loaded
if (Submarine.MainSub == null || Screen.Selected != GameMain.GameScreen)
{
for (int i = 0; i < waterAmbienceChannels.Length; i++)
foreach (var chn in waterAmbienceChannels.Concat(flowSoundChannels).Concat(fireSoundChannels))
{
if (waterAmbienceChannels[i] == null) { continue; }
waterAmbienceChannels[i].FadeOutAndDispose();
waterAmbienceChannels[i] = null;
}
for (int i = 0; i < FlowSounds.Count; i++)
{
if (flowSoundChannels[i] == null) { continue; }
flowSoundChannels[i].FadeOutAndDispose();
flowSoundChannels[i] = null;
}
for (int i = 0; i < fireSoundChannels.Length; i++)
{
if (fireSoundChannels[i] == null) { continue; }
fireSoundChannels[i].FadeOutAndDispose();
fireSoundChannels[i] = null;
chn?.FadeOutAndDispose();
}
fireVolumeLeft[0] = 0.0f; fireVolumeLeft[1] = 0.0f;
fireVolumeRight[0] = 0.0f; fireVolumeRight[1] = 0.0f;
if (hullSoundChannel != null)
{
hullSoundChannel.FadeOutAndDispose();
hullSoundChannel = null;
hullSoundSource = null;
}
hullSoundChannel?.FadeOutAndDispose();
hullSoundSource = null;
return;
}
@@ -482,44 +172,29 @@ namespace Barotrauma
}
}
for (int i = 0; i < 3; i++)
void updateWaterAmbience(Sound sound, float volume)
{
float volume = 0.0f;
Sound sound = null;
switch (i)
SoundChannel chn = waterAmbienceChannels.FirstOrDefault(c => c.Sound == sound);
if (chn is null || !chn.IsPlaying)
{
case 0:
volume = ambienceVolume * (1.0f - movementSoundVolume) * insideSubFactor;
sound = waterAmbienceIn;
break;
case 1:
volume = ambienceVolume * movementSoundVolume * insideSubFactor;
sound = waterAmbienceMoving;
break;
case 2:
volume = 1.0f - insideSubFactor;
sound = waterAmbienceOut;
break;
if (!(chn is null)) { waterAmbienceChannels.Remove(chn); }
chn = sound.Play(volume, "waterambience");
chn.Looping = true;
waterAmbienceChannels.Add(chn);
}
if (sound == null) { continue; }
// Consider the volume set in sounds.xml
volume *= sound.BaseGain;
if ((waterAmbienceChannels[i] == null || !waterAmbienceChannels[i].IsPlaying) && volume > 0.01f)
else
{
waterAmbienceChannels[i] = sound.Play(volume, "waterambience");
waterAmbienceChannels[i].Looping = true;
}
else if (waterAmbienceChannels[i] != null)
{
waterAmbienceChannels[i].Gain += deltaTime * Math.Sign(volume - waterAmbienceChannels[i].Gain);
if (waterAmbienceChannels[i].Gain < 0.01f)
chn.Gain += deltaTime * Math.Sign(volume - chn.Gain);
if (chn.Gain < 0.01f)
{
waterAmbienceChannels[i].FadeOutAndDispose();
chn.FadeOutAndDispose();
}
}
}
updateWaterAmbience(waterAmbienceIn, ambienceVolume * (1.0f - movementSoundVolume) * insideSubFactor);
updateWaterAmbience(waterAmbienceMoving, ambienceVolume * movementSoundVolume * insideSubFactor);
updateWaterAmbience(waterAmbienceOut, 1.0f - insideSubFactor);
}
private static void UpdateWaterFlowSounds(float deltaTime)
@@ -606,7 +281,7 @@ namespace Barotrauma
Vector2 soundPos = new Vector2(GameMain.SoundManager.ListenerPosition.X + (flowVolumeRight[i] - flowVolumeLeft[i]) * 100, GameMain.SoundManager.ListenerPosition.Y);
if (flowSoundChannels[i] == null || !flowSoundChannels[i].IsPlaying)
{
flowSoundChannels[i] = FlowSounds[i].Play(1.0f, FlowSoundRange, soundPos);
flowSoundChannels[i] = FlowSounds[i].Sound.Play(1.0f, FlowSoundRange, soundPos);
flowSoundChannels[i].Looping = true;
}
flowSoundChannels[i].Gain = Math.Min(Math.Max(flowVolumeRight[i], flowVolumeLeft[i]), 1.0f);
@@ -624,7 +299,7 @@ namespace Barotrauma
}
Vector2 listenerPos = new Vector2(GameMain.SoundManager.ListenerPosition.X, GameMain.SoundManager.ListenerPosition.Y);
foreach (Hull hull in Hull.hullList)
foreach (Hull hull in Hull.HullList)
{
foreach (FireSource fs in hull.FireSources)
{
@@ -760,10 +435,10 @@ namespace Barotrauma
public static Sound GetSound(string soundTag)
{
var matchingSounds = miscSounds[soundTag].ToList();
if (matchingSounds.Count == 0) return null;
var matchingSounds = SoundPrefab.Prefabs.Where(p => p.ElementName == soundTag);
if (!matchingSounds.Any()) return null;
return matchingSounds[Rand.Int(matchingSounds.Count)];
return matchingSounds.GetRandomUnsynced().Sound;
}
/// <summary>
@@ -806,14 +481,14 @@ namespace Barotrauma
private static void UpdateMusic(float deltaTime)
{
if (musicClips == null || GameMain.SoundManager.Disabled) { return; }
if (musicClips == null || (GameMain.SoundManager?.Disabled ?? true)) { return; }
if (OverrideMusicType != null && OverrideMusicDuration.HasValue)
{
OverrideMusicDuration -= deltaTime;
if (OverrideMusicDuration <= 0.0f)
{
OverrideMusicType = null;
OverrideMusicType = Identifier.Empty;
OverrideMusicDuration = null;
}
}
@@ -824,7 +499,7 @@ namespace Barotrauma
if (updateMusicTimer <= 0.0f)
{
//find appropriate music for the current situation
string currentMusicType = GetCurrentMusicType();
Identifier currentMusicType = GetCurrentMusicType();
float currentIntensity = GameMain.GameSession?.EventManager != null ?
GameMain.GameSession.EventManager.MusicIntensity * 100.0f : 0.0f;
@@ -835,13 +510,13 @@ namespace Barotrauma
targetMusic[mainTrackIndex] = null;
}
//switch the music if nothing playing atm or the currently playing clip is not suitable anymore
else if (targetMusic[mainTrackIndex] == null || currentMusic[mainTrackIndex] == null || !currentMusic[mainTrackIndex].IsPlaying() || !suitableMusic.Any(m => m.File == currentMusic[mainTrackIndex].Filename))
else if (targetMusic[mainTrackIndex] == null || currentMusic[mainTrackIndex] == null || !currentMusic[mainTrackIndex].IsPlaying() || !suitableMusic.Any(m => m == currentMusic[mainTrackIndex]))
{
if (currentMusicType == "default")
{
if (previousDefaultMusic == null)
{
targetMusic[mainTrackIndex] = previousDefaultMusic = suitableMusic.GetRandom();
targetMusic[mainTrackIndex] = previousDefaultMusic = suitableMusic.GetRandomUnsynced();
}
else
{
@@ -850,7 +525,7 @@ namespace Barotrauma
}
else
{
targetMusic[mainTrackIndex] = suitableMusic.GetRandom();
targetMusic[mainTrackIndex] = suitableMusic.GetRandomUnsynced();
}
}
@@ -858,16 +533,16 @@ namespace Barotrauma
{
// Find background noise loop for the current biome
IEnumerable<BackgroundMusic> suitableNoiseLoops = Screen.Selected == GameMain.GameScreen ?
GetSuitableMusicClips(Level.Loaded.LevelData?.Biome?.Identifier, currentIntensity) :
GetSuitableMusicClips(Level.Loaded.LevelData.Biome.Identifier, currentIntensity) :
Enumerable.Empty<BackgroundMusic>();
if (suitableNoiseLoops.Count() == 0)
{
targetMusic[noiseLoopIndex] = null;
}
// Switch the noise loop if nothing playing atm or the currently playing clip is not suitable anymore
else if (targetMusic[noiseLoopIndex] == null || currentMusic[noiseLoopIndex] == null || !suitableNoiseLoops.Any(m => m.File == currentMusic[noiseLoopIndex].Filename))
else if (targetMusic[noiseLoopIndex] == null || currentMusic[noiseLoopIndex] == null || !suitableNoiseLoops.Any(m => m == currentMusic[noiseLoopIndex]))
{
targetMusic[noiseLoopIndex] = suitableNoiseLoops.GetRandom();
targetMusic[noiseLoopIndex] = suitableNoiseLoops.GetRandomUnsynced();
}
}
else
@@ -875,35 +550,36 @@ namespace Barotrauma
targetMusic[noiseLoopIndex] = null;
}
IEnumerable<BackgroundMusic> suitableTypeAmbiences = GetSuitableMusicClips($"{currentMusicType}ambience", currentIntensity);
IEnumerable<BackgroundMusic> suitableTypeAmbiences = GetSuitableMusicClips($"{currentMusicType}ambience".ToIdentifier(), currentIntensity);
int typeAmbienceTrackIndex = 2;
if (suitableTypeAmbiences.None())
{
targetMusic[typeAmbienceTrackIndex] = null;
}
// Switch the type ambience if nothing playing atm or the currently playing clip is not suitable anymore
else if (targetMusic[typeAmbienceTrackIndex] == null || currentMusic[typeAmbienceTrackIndex] == null || !currentMusic[typeAmbienceTrackIndex].IsPlaying() || suitableTypeAmbiences.None(m => m.File == currentMusic[typeAmbienceTrackIndex].Filename))
else if (targetMusic[typeAmbienceTrackIndex] == null || currentMusic[typeAmbienceTrackIndex] == null || !currentMusic[typeAmbienceTrackIndex].IsPlaying() || suitableTypeAmbiences.None(m => m == currentMusic[typeAmbienceTrackIndex]))
{
targetMusic[typeAmbienceTrackIndex] = suitableTypeAmbiences.GetRandom();
targetMusic[typeAmbienceTrackIndex] = suitableTypeAmbiences.GetRandomUnsynced();
}
//get the appropriate intensity layers for current situation
IEnumerable<BackgroundMusic> suitableIntensityMusic = Screen.Selected == GameMain.GameScreen ?
GetSuitableMusicClips("intensity", currentIntensity) :
GetSuitableMusicClips("intensity".ToIdentifier(), currentIntensity) :
Enumerable.Empty<BackgroundMusic>();
int intensityTrackStartIndex = 3;
for (int i = intensityTrackStartIndex; i < MaxMusicChannels; i++)
{
//disable targetmusics that aren't suitable anymore
if (targetMusic[i] != null && !suitableIntensityMusic.Any(m => m.File == targetMusic[i].File))
if (targetMusic[i] != null && !suitableIntensityMusic.Any(m => m == targetMusic[i]))
{
targetMusic[i] = null;
}
}
foreach (BackgroundMusic intensityMusic in suitableIntensityMusic)
{
//already playing, do nothing
if (targetMusic.Any(m => m != null && m.File == intensityMusic.File)) { continue; }
if (targetMusic.Any(m => m != null && m == intensityMusic)) { continue; }
for (int i = intensityTrackStartIndex; i < MaxMusicChannels; i++)
{
@@ -932,12 +608,12 @@ namespace Barotrauma
}
}
//something should be playing, but the targetMusic is invalid
else if (!musicClips.Any(mc => mc.File == targetMusic[i].File))
else if (!musicClips.Any(mc => mc == targetMusic[i]))
{
targetMusic[i] = GetSuitableMusicClips(targetMusic[i].Type, 0.0f).GetRandom();
targetMusic[i] = GetSuitableMusicClips(targetMusic[i].Type, 0.0f).GetRandomUnsynced();
}
//something should be playing, but the channel is playing nothing or an incorrect clip
else if (currentMusic[i] == null || targetMusic[i].File != currentMusic[i].Filename)
else if (currentMusic[i] == null || targetMusic[i] != currentMusic[i])
{
//something playing -> mute it first
if (musicChannel[i] != null && musicChannel[i].IsPlaying)
@@ -949,18 +625,9 @@ namespace Barotrauma
if (currentMusic[i] == null || (musicChannel[i] == null || !musicChannel[i].IsPlaying))
{
DisposeMusicChannel(i);
try
{
currentMusic[i] = GameMain.SoundManager.LoadSound(targetMusic[i].File, true);
}
catch (System.IO.InvalidDataException e)
{
DebugConsole.ThrowError($"Failed to load the music clip \"{targetMusic[i].File}\".", e);
musicClips.Remove(targetMusic[i]);
targetMusic[i] = null;
break;
}
musicChannel[i] = currentMusic[i].Play(0.0f, i == noiseLoopIndex ? "default" : "music");
currentMusic[i] = targetMusic[i];
musicChannel[i] = currentMusic[i].Sound.Play(0.0f, i == noiseLoopIndex ? "default" : "music");
if (targetMusic[i].ContinueFromPreviousTime)
{
musicChannel[i].StreamSeekPos = targetMusic[i].PreviousTime;
@@ -974,7 +641,7 @@ namespace Barotrauma
if (musicChannel[i] == null || !musicChannel[i].IsPlaying)
{
musicChannel[i]?.Dispose();
musicChannel[i] = currentMusic[i].Play(0.0f, i == noiseLoopIndex ? "default" : "music");
musicChannel[i] = currentMusic[i].Sound.Play(0.0f, i == noiseLoopIndex ? "default" : "music");
musicChannel[i].Looping = true;
}
float targetGain = targetMusic[i].Volume;
@@ -989,17 +656,17 @@ namespace Barotrauma
private static void DisposeMusicChannel(int index)
{
var clip = musicClips.Find(m => m.File == musicChannel[index]?.Sound?.Filename);
var clip = musicClips.FirstOrDefault(m => m.Sound == musicChannel[index]?.Sound);
if (clip != null)
{
if (clip.ContinueFromPreviousTime) { clip.PreviousTime = musicChannel[index].StreamSeekPos; }
}
musicChannel[index]?.Dispose(); musicChannel[index] = null;
currentMusic[index]?.Dispose(); currentMusic[index] = null;
currentMusic[index] = null;
}
private static IEnumerable<BackgroundMusic> GetSuitableMusicClips(string musicType, float currentIntensity)
private static IEnumerable<BackgroundMusic> GetSuitableMusicClips(Identifier musicType, float currentIntensity)
{
return musicClips.Where(music =>
music != null &&
@@ -1008,28 +675,22 @@ namespace Barotrauma
currentIntensity <= music.IntensityRange.Y);
}
private static string GetCurrentMusicType()
private static Identifier GetCurrentMusicType()
{
if (OverrideMusicType != null) { return OverrideMusicType; }
if (Screen.Selected == null) { return "menu"; }
if (Screen.Selected == null) { return "menu".ToIdentifier(); }
if (Screen.Selected == GameMain.CharacterEditorScreen ||
Screen.Selected == GameMain.LevelEditorScreen ||
Screen.Selected == GameMain.ParticleEditorScreen ||
Screen.Selected == GameMain.SpriteEditorScreen ||
Screen.Selected == GameMain.SubEditorScreen ||
Screen.Selected == GameMain.EventEditorScreen ||
(Screen.Selected == GameMain.GameScreen && GameMain.GameSession?.GameMode is TestGameMode) ||
Screen.Selected == GameMain.NetLobbyScreen)
if ((Screen.Selected?.IsEditor ?? false)
|| (Screen.Selected == GameMain.NetLobbyScreen))
{
return "editor";
return "editor".ToIdentifier();
}
if (Screen.Selected != GameMain.GameScreen)
{
previousDefaultMusic = null;
return firstTimeInMainMenu ? "menu" : "default";
return (firstTimeInMainMenu ? "menu" : "default").ToIdentifier();
}
firstTimeInMainMenu = false;
@@ -1040,21 +701,21 @@ namespace Barotrauma
if (Level.Loaded != null && Level.Loaded.Ruins != null &&
Level.Loaded.Ruins.Any(r => r.Area.Contains(Character.Controlled.WorldPosition)))
{
return "ruins";
return "ruins".ToIdentifier();
}
if (Character.Controlled.Submarine?.Info?.IsWreck ?? false)
{
return "wreck";
return "wreck".ToIdentifier();
}
if (Level.IsLoadedOutpost)
{
// Only return music type for location types which have music tracks defined
var locationType = Level.Loaded.StartLocation?.Type?.Identifier?.ToLowerInvariant();
if (!string.IsNullOrEmpty(locationType) && musicClips.Any(c => c.Type == locationType))
var locationType = Level.Loaded.StartLocation?.Type?.Identifier;
if (locationType.HasValue && locationType != Identifier.Empty && musicClips.Any(c => c.Type == locationType))
{
return locationType;
return locationType.Value;
}
}
}
@@ -1062,26 +723,26 @@ namespace Barotrauma
Submarine targetSubmarine = Character.Controlled?.Submarine;
if (targetSubmarine != null && targetSubmarine.AtDamageDepth)
{
return "deep";
return "deep".ToIdentifier();
}
if (GameMain.GameScreen != null && Screen.Selected == GameMain.GameScreen && Submarine.MainSub != null &&
Level.Loaded != null && Level.Loaded.GetRealWorldDepth(GameMain.GameScreen.Cam.Position.Y) > Submarine.MainSub.RealWorldCrushDepth)
{
return "deep";
return "deep".ToIdentifier();
}
if (targetSubmarine != null)
{
float floodedArea = 0.0f;
float totalArea = 0.0f;
foreach (Hull hull in Hull.hullList)
foreach (Hull hull in Hull.HullList)
{
if (hull.Submarine != targetSubmarine) { continue; }
floodedArea += hull.WaterVolume;
totalArea += hull.Volume;
}
if (totalArea > 0.0f && floodedArea / totalArea > 0.25f) { return "flooded"; }
if (totalArea > 0.0f && floodedArea / totalArea > 0.25f) { return "flooded".ToIdentifier(); }
}
float enemyDistThreshold = 5000.0f;
@@ -1100,14 +761,14 @@ namespace Barotrauma
{
if (Vector2.DistanceSquared(character.WorldPosition, targetSubmarine.WorldPosition) < enemyDistThreshold * enemyDistThreshold)
{
return "monster";
return "monster".ToIdentifier();
}
}
else if (Character.Controlled != null)
{
if (Vector2.DistanceSquared(character.WorldPosition, Character.Controlled.WorldPosition) < enemyDistThreshold * enemyDistThreshold)
{
return "monster";
return "monster".ToIdentifier();
}
}
}
@@ -1116,16 +777,16 @@ namespace Barotrauma
{
if (Submarine.Loaded != null && Level.Loaded != null && Submarine.MainSub != null && Submarine.MainSub.AtEndExit)
{
return "levelend";
return "levelend".ToIdentifier();
}
if (Timing.TotalTime < GameMain.GameSession.RoundStartTime + 120.0 &&
Level.Loaded?.Type == LevelData.LevelType.LocationConnection)
{
return "start";
return "start".ToIdentifier();
}
}
return "default";
return "default".ToIdentifier();
}
public static bool ShouldMuffleSound(Character listener, Vector2 soundWorldPos, float range, Hull hullGuess)
@@ -1159,7 +820,7 @@ namespace Barotrauma
if (SplashSounds.Count == 0) { return; }
int splashIndex = MathHelper.Clamp((int)(strength + Rand.Range(-2.0f, 2.0f)), 0, SplashSounds.Count - 1);
float range = 800.0f;
var channel = SplashSounds[splashIndex].Play(1.0f, range, worldPosition, muffle: ShouldMuffleSound(Character.Controlled, worldPosition, range, null));
var channel = SplashSounds[splashIndex].Sound.Play(1.0f, range, worldPosition, muffle: ShouldMuffleSound(Character.Controlled, worldPosition, range, null));
}
public static void PlayDamageSound(string damageType, float damage, PhysicsBody body)
@@ -1169,35 +830,29 @@ namespace Barotrauma
}
private static readonly List<DamageSound> tempList = new List<DamageSound>();
public static void PlayDamageSound(string damageType, float damage, Vector2 position, float range = 2000.0f, IEnumerable<string> tags = null)
public static void PlayDamageSound(string damageType, float damage, Vector2 position, float range = 2000.0f, IEnumerable<Identifier> tags = null)
{
damage = MathHelper.Clamp(damage + Rand.Range(-10.0f, 10.0f), 0.0f, 100.0f);
tempList.Clear();
foreach (var s in damageSounds)
{
if ((s.damageRange == Vector2.Zero ||
(damage >= s.damageRange.X && damage <= s.damageRange.Y)) &&
string.Equals(s.damageType, damageType, StringComparison.OrdinalIgnoreCase) &&
(string.IsNullOrEmpty(s.requiredTag) || (tags == null ? string.IsNullOrEmpty(s.requiredTag) : tags.Contains(s.requiredTag))))
if ((s.DamageRange == Vector2.Zero ||
(damage >= s.DamageRange.X && damage <= s.DamageRange.Y)) &&
s.DamageType == damageType &&
(s.RequiredTag.IsEmpty || (tags == null ? s.RequiredTag.IsEmpty : tags.Contains(s.RequiredTag))))
{
tempList.Add(s);
}
}
var damageSound = tempList.GetRandom();
if (damageSound.sound != null)
{
damageSound.sound.Play(1.0f, range, position, muffle: !damageSound.ignoreMuffling && ShouldMuffleSound(Character.Controlled, position, range, null));
}
var damageSound = tempList.GetRandomUnsynced();
damageSound?.Sound?.Play(1.0f, range, position, muffle: !damageSound.IgnoreMuffling && ShouldMuffleSound(Character.Controlled, position, range, null));
}
public static void PlayUISound(GUISoundType soundType)
{
if (guiSounds == null || guiSounds.Count < 1) { return; }
if (guiSounds.TryGetValue(soundType, out List<Sound> sounds))
{
if (sounds == null || sounds.Count < 1) { return; }
sounds.GetRandom()?.Play(null, "ui");
}
GUISound.GUISoundPrefabs
.Where(s => s.Type == soundType)
.GetRandomUnsynced()?.Sound?.Play(null, "ui");
}
}
}