v1.6.18.1 (Unto the Breach Hotfix 1)

This commit is contained in:
Regalis11
2024-10-28 15:03:46 +02:00
parent a29662c074
commit 7eac44ea7d
47 changed files with 246 additions and 124 deletions

View File

@@ -48,7 +48,7 @@ namespace Barotrauma
if (sound != null)
{
SoundPlayer.PlaySound(sound.Sound, worldPosition, sound.Volume, sound.Range, ignoreMuffling: sound.IgnoreMuffling, freqMult: sound.GetRandomFrequencyMultiplier());
SoundPlayer.PlaySound(sound, worldPosition);
}
}
}

View File

@@ -1,5 +1,4 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;

View File

@@ -141,7 +141,7 @@ namespace Barotrauma.Items.Components
{
if (chargeSound != null)
{
chargeSoundChannel = SoundPlayer.PlaySound(chargeSound.Sound, item.WorldPosition, chargeSound.Volume, chargeSound.Range, ignoreMuffling: chargeSound.IgnoreMuffling, freqMult: chargeSound.GetRandomFrequencyMultiplier());
chargeSoundChannel = SoundPlayer.PlaySound(chargeSound, item.WorldPosition, hullGuess: item.CurrentHull);
if (chargeSoundChannel != null) { chargeSoundChannel.Looping = true; }
}
}

View File

@@ -392,11 +392,7 @@ namespace Barotrauma.Items.Components
float volume = GetSoundVolume(itemSound);
if (volume <= 0.0001f) { return; }
loopingSound = itemSound;
loopingSoundChannel = loopingSound.RoundSound.Sound.Play(
new Vector3(position.X, position.Y, 0.0f),
0.01f,
freqMult: itemSound.RoundSound.GetRandomFrequencyMultiplier(),
muffle: SoundPlayer.ShouldMuffleSound(Character.Controlled, position, loopingSound.Range, Character.Controlled?.CurrentHull));
loopingSoundChannel = SoundPlayer.PlaySound(loopingSound.RoundSound, position, volume: 0.01f, hullGuess: item.CurrentHull);
loopingSoundChannel.Looping = true;
//TODO: tweak
loopingSoundChannel.Near = loopingSound.Range * 0.4f;
@@ -407,7 +403,7 @@ namespace Barotrauma.Items.Components
{
float volume = GetSoundVolume(itemSound);
if (volume <= 0.0001f) { return; }
var channel = SoundPlayer.PlaySound(itemSound.RoundSound.Sound, position, volume, itemSound.Range, itemSound.RoundSound.GetRandomFrequencyMultiplier(), item.CurrentHull, ignoreMuffling: itemSound.RoundSound.IgnoreMuffling);
var channel = SoundPlayer.PlaySound(itemSound.RoundSound, position, volume, hullGuess: item.CurrentHull);
if (channel != null) { playingOneshotSoundChannels.Add(channel); }
}
}

View File

@@ -475,11 +475,8 @@ namespace Barotrauma.Items.Components
if (sound != null)
{
SoundPlayer.PlaySound(
sound.Sound,
sound,
item.WorldPosition,
sound.Volume,
sound.Range,
freqMult: sound.GetRandomFrequencyMultiplier(),
hullGuess: item.CurrentHull);
}
}

View File

@@ -229,7 +229,7 @@ namespace Barotrauma.Items.Components
{
if (reelSoundChannel is not { IsPlaying: true })
{
reelSoundChannel = SoundPlayer.PlaySound(sound.Sound, position, sound.Volume, sound.Range, ignoreMuffling: sound.IgnoreMuffling, freqMult: sound.GetRandomFrequencyMultiplier());
reelSoundChannel = SoundPlayer.PlaySound(sound, position);
if (reelSoundChannel != null)
{
reelSoundChannel.Looping = true;
@@ -244,7 +244,7 @@ namespace Barotrauma.Items.Components
}
else
{
SoundPlayer.PlaySound(sound.Sound, position, sound.Volume, sound.Range, ignoreMuffling: sound.IgnoreMuffling, freqMult: sound.GetRandomFrequencyMultiplier());
SoundPlayer.PlaySound(sound, position);
}
}

View File

@@ -227,14 +227,14 @@ namespace Barotrauma.Items.Components
{
if (moveSoundChannel == null && startMoveSound != null)
{
moveSoundChannel = SoundPlayer.PlaySound(startMoveSound.Sound, item.WorldPosition, startMoveSound.Volume, startMoveSound.Range, ignoreMuffling: startMoveSound.IgnoreMuffling, freqMult: startMoveSound.GetRandomFrequencyMultiplier());
moveSoundChannel = SoundPlayer.PlaySound(startMoveSound, item.WorldPosition, hullGuess: item.CurrentHull);
}
else if (moveSoundChannel == null || !moveSoundChannel.IsPlaying)
{
if (moveSound != null)
{
moveSoundChannel?.FadeOutAndDispose();
moveSoundChannel = SoundPlayer.PlaySound(moveSound.Sound, item.WorldPosition, moveSound.Volume, moveSound.Range, ignoreMuffling: moveSound.IgnoreMuffling, freqMult: moveSound.GetRandomFrequencyMultiplier());
moveSoundChannel = SoundPlayer.PlaySound(moveSound, item.WorldPosition, hullGuess: item.CurrentHull);
if (moveSoundChannel != null) { moveSoundChannel.Looping = true;}
}
}
@@ -246,7 +246,7 @@ namespace Barotrauma.Items.Components
if (endMoveSound != null && moveSoundChannel.Sound != endMoveSound.Sound)
{
moveSoundChannel.FadeOutAndDispose();
moveSoundChannel = SoundPlayer.PlaySound(endMoveSound.Sound, item.WorldPosition, endMoveSound.Volume, endMoveSound.Range, ignoreMuffling: endMoveSound.IgnoreMuffling, freqMult: endMoveSound.GetRandomFrequencyMultiplier());
moveSoundChannel = SoundPlayer.PlaySound(endMoveSound, item.WorldPosition, hullGuess: item.CurrentHull);
if (moveSoundChannel != null) { moveSoundChannel.Looping = false; }
}
else if (!moveSoundChannel.IsPlaying)
@@ -275,7 +275,7 @@ namespace Barotrauma.Items.Components
{
if (chargeSound != null)
{
chargeSoundChannel = SoundPlayer.PlaySound(chargeSound.Sound, item.WorldPosition, chargeSound.Volume, chargeSound.Range, ignoreMuffling: chargeSound.IgnoreMuffling, freqMult: chargeSound.GetRandomFrequencyMultiplier());
chargeSoundChannel = SoundPlayer.PlaySound(chargeSound, item.WorldPosition, hullGuess: item.CurrentHull);
if (chargeSoundChannel != null) { chargeSoundChannel.Looping = true; }
}
}

View File

@@ -408,7 +408,7 @@ namespace Barotrauma
fadeInBrokenSprite.Sprite.effects ^= SpriteEffects;
}
if (body == null)
if (body == null || body.BodyType == BodyType.Static)
{
if (Prefab.ResizeHorizontal || Prefab.ResizeVertical)
{

View File

@@ -16,6 +16,8 @@ namespace Barotrauma
public readonly bool Stream;
public readonly bool IgnoreMuffling;
public readonly bool MuteBackgroundMusic;
public readonly string? Filename;
private RoundSound(ContentXElement element, Sound sound)
@@ -26,6 +28,7 @@ namespace Barotrauma
Range = element.GetAttributeFloat("range", 1000.0f);
Volume = element.GetAttributeFloat("volume", 1.0f);
IgnoreMuffling = element.GetAttributeBool("dontmuffle", false);
MuteBackgroundMusic = element.GetAttributeBool("MuteBackgroundMusic", false);
FrequencyMultiplierRange = new Vector2(1.0f);
string freqMultAttr = element.GetAttributeString("frequencymultiplier", element.GetAttributeString("frequency", "1.0"));

View File

@@ -437,7 +437,7 @@ namespace Barotrauma
jobDropDown.AddItem(TextManager.Get("Any"), null);
foreach (JobPrefab jobPrefab in JobPrefab.Prefabs)
{
if (jobPrefab.HiddenJob) { continue; }
if (jobPrefab.Name.IsNullOrWhiteSpace()) { continue; }
jobDropDown.AddItem(jobPrefab.Name, jobPrefab);
}
jobDropDown.SelectItem(AssignedJob);

View File

@@ -763,6 +763,11 @@ namespace Barotrauma.Networking
case ServerPacketHeader.CANCEL_STARTGAME:
DebugConsole.Log("Received CANCEL_STARTGAME packet.");
GameMain.NetLobbyScreen?.CloseStartRoundWarning();
if (GameMain.NetLobbyScreen?.ReadyToStartBox is { } readyToStartBox)
{
readyToStartBox.Selected = false;
SetReadyToStart(readyToStartBox);
}
break;
case ServerPacketHeader.STARTGAME:
DebugConsole.Log("Received STARTGAME packet.");

View File

@@ -291,7 +291,7 @@ namespace Barotrauma
if (characterInfos.Count >= 3) { break; }
}
}
characterInfos.Sort((a, b) => Math.Sign(b.Job.MinKarma - a.Job.MinKarma));
characterInfos.Sort((a, b) => Math.Sign(a.Job.CampaignSetupUIOrder - b.Job.CampaignSetupUIOrder));
characterInfoColumns.ClearChildren();
CharacterMenus?.ForEach(m => m.Dispose());

View File

@@ -2708,13 +2708,18 @@ namespace Barotrauma
if (newTeamPreference == CharacterTeamType.None
&& GameMain.Client?.ServerSettings?.PvpTeamSelectionMode == PvpTeamSelectionMode.PlayerChoice) { return false; } // Already handled by delegate above
var oldPreference = MultiplayerPreferences.Instance.TeamPreference;
MultiplayerPreferences.Instance.TeamPreference = newTeamPreference;
UpdateSelectedSub(newTeamPreference);
GameMain.Client?.ForceNameJobTeamUpdate();
if (newTeamPreference != oldPreference)
{
GameMain.Client?.ForceNameJobTeamUpdate();
GameSettings.SaveCurrentConfig();
}
RefreshPvpTeamSelectionButtons();
GameSettings.SaveCurrentConfig();
UpdateDisembarkPointListFromServerSettings();
//need to update job preferences and close the selection frame
//because the team selection might affect the uniform sprite and the loadouts
@@ -4015,7 +4020,9 @@ namespace Barotrauma
JobSelectionFrame.Visible = false;
}
if (GUI.MouseOn?.UserData is JobVariant jobPrefab && GUI.MouseOn.Style?.Name == "JobVariantButton")
if (GUI.MouseOn?.UserData is JobVariant jobPrefab &&
GUI.MouseOn.Style?.Name == "JobVariantButton" &&
GUI.MouseOn.Parent != null)
{
if (jobVariantTooltip?.UserData is not JobVariant prevVisibleVariant ||
prevVisibleVariant.Prefab != jobPrefab.Prefab ||

View File

@@ -448,7 +448,7 @@ namespace Barotrauma
.ToArray();
bool inSelectedCall = false;
languageDropdown.AfterSelected = (_, userData) =>
languageDropdown.OnSelected = (_, userData) =>
{
if (inSelectedCall) { return true; }
try
@@ -465,33 +465,38 @@ namespace Barotrauma
bool noneSelected = langTickboxes.All(tb => !tb.Selected);
bool allSelected = langTickboxes.All(tb => tb.Selected);
if (allSelected != allTickbox.Selected)
{
allTickbox.Selected = allSelected;
}
if (allSelected)
{
languageDropdown.Text = TextManager.Get(allLanguagesKey);
}
else if (noneSelected)
{
languageDropdown.Text = TextManager.Get("None");
}
var languages = languageDropdown.SelectedDataMultiple.OfType<LanguageIdentifier>();
ServerListFilters.Instance.SetAttribute(languageKey, string.Join(", ", languages));
GameSettings.SaveCurrentConfig();
return true;
}
finally
{
inSelectedCall = false;
FilterServers();
}
};
languageDropdown.AfterSelected = (_, userData) =>
{
bool noneSelected = langTickboxes.All(tb => !tb.Selected);
bool allSelected = langTickboxes.All(tb => tb.Selected);
if (allSelected)
{
languageDropdown.Text = TextManager.Get(allLanguagesKey);
}
else if (noneSelected)
{
languageDropdown.Text = TextManager.Get("None");
}
var languages = languageDropdown.SelectedDataMultiple.OfType<LanguageIdentifier>();
ServerListFilters.Instance.SetAttribute(languageKey, string.Join(", ", languages));
GameSettings.SaveCurrentConfig();
FilterServers();
return true;
};
}
// Filter Tags

View File

@@ -62,6 +62,8 @@ namespace Barotrauma.Sounds
public float BaseNear;
public float BaseFar;
public bool MuteBackgroundMusic;
public Sound(SoundManager owner, string filename, bool stream, bool streamsReliably, ContentXElement xElement = null, bool getFullPath = true)
{
Owner = owner;

View File

@@ -434,6 +434,8 @@ namespace Barotrauma.Sounds
private readonly uint[] unqueuedBuffers;
private readonly float[] streamBufferAmplitudes;
public bool MuteBackgroundMusic;
public int StreamSeekPos
{
get { return streamSeekPos; }

View File

@@ -484,8 +484,20 @@ namespace Barotrauma
if (sound == null) { return null; }
return PlaySound(sound, position, volume ?? sound.BaseGain, range ?? sound.BaseFar, 1.0f, hullGuess);
}
public static SoundChannel PlaySound(RoundSound sound, Vector2 position, float? volume = null, Hull hullGuess = null)
{
return PlaySound(
sound.Sound,
position,
volume ?? sound.Volume,
sound.Range,
ignoreMuffling: sound.IgnoreMuffling,
hullGuess: hullGuess,
freqMult: sound.GetRandomFrequencyMultiplier(),
muteBackgroundMusic: sound.MuteBackgroundMusic);
}
public static SoundChannel PlaySound(Sound sound, Vector2 position, float? volume = null, float? range = null, float? freqMult = null, Hull hullGuess = null, bool ignoreMuffling = false)
public static SoundChannel PlaySound(Sound sound, Vector2 position, float? volume = null, float? range = null, float? freqMult = null, Hull hullGuess = null, bool ignoreMuffling = false, bool muteBackgroundMusic = false)
{
if (sound == null)
{
@@ -501,7 +513,12 @@ namespace Barotrauma
return null;
}
bool muffle = !ignoreMuffling && ShouldMuffleSound(Character.Controlled, position, far, hullGuess);
return sound.Play(volume ?? sound.BaseGain, far, freqMult ?? 1.0f, position, muffle: muffle);
var channel = sound.Play(volume ?? sound.BaseGain, far, freqMult ?? 1.0f, position, muffle: muffle);
if (channel != null)
{
channel.MuteBackgroundMusic = muteBackgroundMusic;
}
return channel;
}
public static void DisposeDisabledMusic()
@@ -673,6 +690,17 @@ namespace Barotrauma
updateMusicTimer = UpdateMusicInterval;
}
bool muteBackgroundMusic = false;
for (int i = 0; i < SoundManager.SourceCount; i++)
{
SoundChannel playingSoundChannel = GameMain.SoundManager.GetSoundChannelFromIndex(SoundManager.SourcePoolIndex.Default, i);
if (playingSoundChannel is { MuteBackgroundMusic: true, IsPlaying: true })
{
muteBackgroundMusic = true;
break;
}
}
int activeTrackCount = targetMusic.Count(m => m != null);
for (int i = 0; i < MaxMusicChannels; i++)
{
@@ -729,6 +757,10 @@ namespace Barotrauma
musicChannel[i].Looping = true;
}
float targetGain = targetMusic[i].Volume;
if (muteBackgroundMusic)
{
targetGain = 0.0f;
}
if (targetMusic[i].DuckVolume)
{
targetGain *= (float)Math.Sqrt(1.0f / activeTrackCount);

View File

@@ -93,6 +93,7 @@ namespace Barotrauma
else
{
angle = -item.RotationRad;
if (item.FlippedX) { angle += MathHelper.Pi; }
particleRotation = item.RotationRad;
}
entityAngleAssigned = true;

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>1.6.17.0</Version>
<Version>1.6.18.1</Version>
<Copyright>Copyright © FakeFish 2018-2024</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>1.6.17.0</Version>
<Version>1.6.18.1</Version>
<Copyright>Copyright © FakeFish 2018-2024</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>1.6.17.0</Version>
<Version>1.6.18.1</Version>
<Copyright>Copyright © FakeFish 2018-2024</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>1.6.17.0</Version>
<Version>1.6.18.1</Version>
<Copyright>Copyright © FakeFish 2018-2023</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>1.6.17.0</Version>
<Version>1.6.18.1</Version>
<Copyright>Copyright © FakeFish 2018-2023</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -40,8 +40,6 @@ namespace Barotrauma
/// </summary>
private readonly List<KillCount> kills = new List<KillCount>();
private bool initialized = false;
private float roundEndTimer;
private float timeInTargetSubmarineTimer;
@@ -92,12 +90,6 @@ namespace Barotrauma
private void CheckTeamCharacters()
{
if (!allowRespawning && initialized)
{
//if no respawns are allowed, we only need to check the characters once
return;
}
for (int i = 0; i < crews.Length; i++)
{
foreach (var character in crews[i])
@@ -133,8 +125,6 @@ namespace Barotrauma
}
}
}
initialized = true;
}
private void CheckWinCondition(float deltaTime)

View File

@@ -615,7 +615,7 @@ namespace Barotrauma.Networking
readyToStartAutomatically = true;
}
}
if (readyToStartAutomatically)
if (readyToStartAutomatically && !isRoundStartWarningActive)
{
if (!wasReadyToStartAutomatically) { GameMain.NetLobbyScreen.LastUpdateID++; }
TryStartGame();
@@ -840,9 +840,8 @@ namespace Barotrauma.Networking
IWriteMessage msg = new WriteOnlyMessage().WithHeader(ServerPacketHeader.CANCEL_STARTGAME);
serverPeer.Send(msg, c.Connection, DeliveryMethod.Reliable);
}
AbortStartGameIfWarningActive();
}
AbortStartGameIfWarningActive();
break;
case ClientPacketHeader.REQUEST_STARTGAMEFINALIZE:
if (connectedClient == null)
@@ -2547,6 +2546,21 @@ namespace Barotrauma.Networking
private void AbortStartGameIfWarningActive()
{
isRoundStartWarningActive = false;
//reset autorestart countdown to give the clients time to reselect perks
if (ServerSettings.AutoRestart)
{
ServerSettings.AutoRestartTimer = Math.Max(ServerSettings.AutoRestartInterval, 5.0f);
}
//reset start round votes so we don't immediately attempt to restart
foreach (var client in connectedClients)
{
client.SetVote(VoteType.StartRound, false);
}
int clientsReady = connectedClients.Count(c => c.GetVote<bool>(VoteType.StartRound));
GameMain.NetLobbyScreen.LastUpdateID++;
CoroutineManager.StopCoroutines(nameof(WarnAndDelayStartGame));
}
@@ -3312,6 +3326,24 @@ namespace Barotrauma.Networking
if (c == null || string.IsNullOrEmpty(newName) || !NetIdUtils.IdMoreRecent(nameId, c.NameId)) { return false; }
if (!newJob.IsEmpty)
{
if (!JobPrefab.Prefabs.TryGet(newJob, out JobPrefab newJobPrefab) || newJobPrefab.HiddenJob)
{
newJob = Identifier.Empty;
}
}
if (newName == c.Name && newJob == c.PreferredJob && newTeam == c.PreferredTeam) { return false; }
c.NameId = nameId;
c.PreferredJob = newJob;
if (newTeam != c.PreferredTeam)
{
c.PreferredTeam = newTeam;
RefreshPvpTeamAssignments();
}
var timeSinceNameChange = DateTime.Now - c.LastNameChangeTime;
if (timeSinceNameChange < Client.NameChangeCoolDown && newName != c.Name)
{
@@ -3321,29 +3353,14 @@ namespace Barotrauma.Networking
var coolDownRemaining = Client.NameChangeCoolDown - timeSinceNameChange;
SendDirectChatMessage($"ServerMessage.NameChangeFailedCooldownActive~[seconds]={(int)coolDownRemaining.TotalSeconds}", c);
LastClientListUpdateID++;
//increment the ID to make sure the current server-side name is treated as the "latest",
//and the client correctly reverts back to the old name
c.NameId++;
}
c.NameId = nameId;
c.RejectedName = newName;
return false;
}
if (!newJob.IsEmpty)
{
if (!JobPrefab.Prefabs.TryGet(newJob, out JobPrefab newJobPrefab) || newJobPrefab.HiddenJob)
{
newJob = Identifier.Empty;
}
}
c.NameId = nameId;
if (newName == c.Name && newJob == c.PreferredJob && newTeam == c.PreferredTeam) { return false; }
c.PreferredJob = newJob;
if (newTeam != c.PreferredTeam)
{
c.PreferredTeam = newTeam;
RefreshPvpTeamAssignments();
}
return TryChangeClientName(c, newName);
}

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>1.6.17.0</Version>
<Version>1.6.18.1</Version>
<Copyright>Copyright © FakeFish 2018-2023</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -74,7 +74,6 @@ namespace Barotrauma
private float pathBackTimer;
private const float DefaultCoolDown = 10.0f;
private const float PathBackCheckTime = 1.0f;
private IEnumerable<Body> myBodies;
private float aimTimer;
private float reloadTimer;
private float spreadTimer;
@@ -1375,9 +1374,10 @@ namespace Barotrauma
float aimFactor = MathHelper.PiOver2 * (1 - AimAccuracy);
if (VectorExtensions.Angle(VectorExtensions.Forward(Weapon.body.TransformedRotation), Enemy.WorldPosition - Weapon.WorldPosition) < MathHelper.PiOver4 + aimFactor)
{
myBodies ??= character.AnimController.Limbs.Select(l => l.body.FarseerBody);
// Check that we don't hit friendlies. No need to check the walls, because there's a separate check for that at 1096 (which intentionally has a small delay)
var pickedBodies = Submarine.PickBodies(Weapon.SimPosition, Submarine.GetRelativeSimPosition(from: Weapon, to: Enemy), myBodies, Physics.CollisionCharacter);
var pickedBodies = Submarine.PickBodies(Weapon.SimPosition, Submarine.GetRelativeSimPosition(from: Weapon, to: Enemy),
ignoredBodies: character.AnimController.LimbBodies,
Physics.CollisionCharacter);
foreach (var body in pickedBodies)
{
Character target = body.UserData switch

View File

@@ -64,6 +64,9 @@ namespace Barotrauma
}
}
private readonly List<Body> limbBodies = new List<Body>();
public IEnumerable<Body> LimbBodies => limbBodies;
public bool HasMultipleLimbsOfSameType => limbs != null && limbs.Length > limbDictionary.Count;
private bool frozen;
@@ -524,6 +527,7 @@ namespace Barotrauma
protected void CreateLimbs()
{
limbBodies.Clear();
limbs?.ForEach(l => l.Remove());
Mass = 0;
DebugConsole.Log($"Creating limbs from {RagdollParams.Name}.");
@@ -618,6 +622,7 @@ namespace Barotrauma
{
throw new Exception($"Failed to add a limb to the character \"{Character?.ConfigPath ?? "null"}\" (limb index {ID} out of bounds). The ragdoll file may be configured incorrectly.");
}
limbBodies.Add(limb.body.FarseerBody);
Limbs[ID] = limb;
Mass += limb.Mass;
if (!limbDictionary.ContainsKey(limb.type)) { limbDictionary.Add(limb.type, limb); }
@@ -629,6 +634,7 @@ namespace Barotrauma
limb.body.FarseerBody.OnCollision += OnLimbCollision;
Array.Resize(ref limbs, Limbs.Length + 1);
Limbs[Limbs.Length - 1] = limb;
limbBodies.Add(limb.body.FarseerBody);
Mass += limb.Mass;
if (!limbDictionary.ContainsKey(limb.type)) { limbDictionary.Add(limb.type, limb); }
SetupDrawOrder();
@@ -636,14 +642,14 @@ namespace Barotrauma
public void RemoveLimb(Limb limb)
{
if (!Limbs.Contains(limb)) return;
if (!Limbs.Contains(limb)) { return; }
Limb[] newLimbs = new Limb[Limbs.Length - 1];
int i = 0;
foreach (Limb existingLimb in Limbs)
{
if (existingLimb == limb) continue;
if (existingLimb == limb) { continue; }
newLimbs[i] = existingLimb;
i++;
}
@@ -680,8 +686,11 @@ namespace Barotrauma
}
LimbJoints = newJoints;
}
limbBodies.Remove(limb.body.FarseerBody);
limb.Remove();
System.Diagnostics.Debug.Assert(!limbs.Contains(limb));
System.Diagnostics.Debug.Assert(limbs.None(l => l.Removed));
foreach (LimbJoint limbJoint in attachedJoints)
{
GameMain.World.Remove(limbJoint.Joint);
@@ -2243,6 +2252,7 @@ namespace Barotrauma
}
limbs = null;
}
limbBodies.Clear();
if (collider != null)
{

View File

@@ -5709,13 +5709,17 @@ namespace Barotrauma
return sameRoomHulls.Contains(character.CurrentHull);
}
/// <summary>
/// Returns all friendly crew members that are alive.
/// Filters out pets and characters that don't have <see cref="CharacterInfo"/>.
/// </summary>
public static IEnumerable<Character> GetFriendlyCrew(Character character)
{
if (character is null)
{
return Enumerable.Empty<Character>();
}
return CharacterList.Where(c => HumanAIController.IsFriendly(character, c, onlySameTeam: true) && !c.IsDead);
return CharacterList.Where(c => c.Info != null && !c.IsDead && !c.IsPet && HumanAIController.IsFriendly(character, c, onlySameTeam: true));
}
public bool HasRecipeForItem(Identifier recipeIdentifier)

View File

@@ -184,6 +184,13 @@ namespace Barotrauma
private set;
}
[Serialize(10, IsPropertySaveable.No, description: "Determines the order of the characters in the campaign setup ui.")]
public int CampaignSetupUIOrder
{
get;
private set;
}
[Serialize(false, IsPropertySaveable.No, description: "If set to true, a client that has chosen this as their preferred job will get it regardless of the maximum number or the amount of spawnpoints in the sub.")]
public bool AllowAlways
{

View File

@@ -1,6 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Abilities
{
@@ -14,8 +13,8 @@ namespace Barotrauma.Abilities
protected override bool MatchesConditionSpecific()
{
IEnumerable<Character> crewmembers = Character.GetFriendlyCrew(character);
int differentCrewAmount = crewmembers.Select(c => c.Info?.Job?.Prefab.Identifier).Distinct().Count();
IEnumerable<Character> crewMembers = Character.GetFriendlyCrew(character);
int differentCrewAmount = crewMembers.Select(c => c.Info.Job?.Prefab.Identifier).Distinct().Count();
return differentCrewAmount >= amount;
}
}

View File

@@ -1,6 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Linq;
namespace Barotrauma.Abilities
{
@@ -14,7 +12,7 @@ namespace Barotrauma.Abilities
protected override bool MatchesConditionSpecific()
{
return Character.GetFriendlyCrew(character).Where(c => c.Info != null && (c.Info.GetCurrentLevel() - character.Info.GetCurrentLevel() >= levelsBehind)).Any();
return Character.GetFriendlyCrew(character).Any(c => c.Info.GetCurrentLevel() - character.Info.GetCurrentLevel() >= levelsBehind);
}
}
}

View File

@@ -28,7 +28,7 @@ namespace Barotrauma.Abilities
foreach (Character character in Character.GetFriendlyCrew(Character))
{
JobPrefab? characterJob = character.Info?.Job?.Prefab;
JobPrefab? characterJob = character.Info.Job?.Prefab;
if (characterJob is null) { continue; }
switch (characterJob.Identifier == apprenticeJob.Identifier)

View File

@@ -30,7 +30,7 @@
foreach (Character otherCharacter in Character.GetFriendlyCrew(Character))
{
if (otherCharacter == Character) { continue; }
otherCharacter.Info?.IncreaseSkillLevel(identifier, abilitySkillGain.Value, gainedFromAbility: true);
otherCharacter.Info.IncreaseSkillLevel(identifier, abilitySkillGain.Value, gainedFromAbility: true);
}
}
else

View File

@@ -75,7 +75,7 @@ namespace Barotrauma.Abilities
{
foreach (Character c in Character.GetFriendlyCrew(Character))
{
c?.Info?.ChangeSavedStatValue(statType, value, identifier, removeOnDeath, maxValue: maxValue, setValue: setValue);
c.Info.ChangeSavedStatValue(statType, value, identifier, removeOnDeath, maxValue: maxValue, setValue: setValue);
}
}
else

View File

@@ -22,7 +22,6 @@ namespace Barotrauma.Abilities
foreach (Character character in Character.GetFriendlyCrew(Character))
{
if (character.Info is null) { return; }
character.Info.AdditionalTalentPoints += amount;
}
}

View File

@@ -35,7 +35,7 @@ namespace Barotrauma.Abilities
GameAnalyticsManager.AddMoneyGainedEvent(moneyAmount, GameAnalyticsManager.MoneySource.Ability, CharacterTalent.Prefab.Identifier.Value);
foreach (Character character in Character.GetFriendlyCrew(Character))
{
character.Info?.GiveExperience(experienceAmount);
character.Info.GiveExperience(experienceAmount);
}
timesGiven++;
if (max > 0 && timesGiven >= max) { break; }

View File

@@ -168,7 +168,7 @@ namespace Barotrauma
logError: false);
}
humanPrefab ??= NPCSet.Get(NPCSetIdentifier, NPCIdentifier, logError: true);
humanPrefab ??= NPCSet.Get(NPCSetIdentifier, NPCIdentifier, logError: true, contentPackageToLogInError: ParentEvent.Prefab.ContentPackage);
if (humanPrefab != null)
{

View File

@@ -568,7 +568,7 @@ namespace Barotrauma
Identifier characterIdentifier = element.GetAttributeIdentifier("identifier", Identifier.Empty);
Identifier characterFrom = element.GetAttributeIdentifier("from", Identifier.Empty);
HumanPrefab humanPrefab = NPCSet.Get(characterFrom, characterIdentifier);
HumanPrefab humanPrefab = NPCSet.Get(characterFrom, characterIdentifier, contentPackageToLogInError: Prefab.ContentPackage);
if (humanPrefab == null)
{
DebugConsole.ThrowError($"Couldn't spawn character for mission: character prefab \"{characterIdentifier}\" not found in the NPC set \"{characterFrom}\".",

View File

@@ -128,7 +128,7 @@ namespace Barotrauma
{
Identifier characterIdentifier = characterElement.GetAttributeIdentifier("identifier", Identifier.Empty);
Identifier characterFrom = characterElement.GetAttributeIdentifier("from", Identifier.Empty);
HumanPrefab humanPrefab = NPCSet.Get(characterFrom, characterIdentifier);
HumanPrefab humanPrefab = NPCSet.Get(characterFrom, characterIdentifier, contentPackageToLogInError: Prefab.ContentPackage);
if (humanPrefab == null)
{
DebugConsole.ThrowError($"Error in mission \"{prefab.Identifier}\". Character prefab \"{characterIdentifier}\" not found in the NPC set \"{characterFrom}\".",

View File

@@ -234,7 +234,8 @@ namespace Barotrauma.Items.Components
base.Update(deltaTime, cam);
if (targetCharacter != null)
{
if (SetTaintedOnDeath && targetCharacter.IsDead && !tainted)
if (SetTaintedOnDeath && !tainted &&
targetCharacter.IsDead && targetCharacter.CauseOfDeath is not { Type: CauseOfDeathType.Disconnected })
{
SetTainted(true);
}

View File

@@ -850,7 +850,8 @@ namespace Barotrauma.Items.Components
private bool CanAutoInteractWithContained(Item containedItem)
{
return AutoInteractWithContained && autoInteractWithContainedTags.Any(t => containedItem.HasTag(t));
return AutoInteractWithContained &&
(autoInteractWithContainedTags.None() || autoInteractWithContainedTags.Any(t => containedItem.HasTag(t)));
}
private void SetContainedActive(bool active)

View File

@@ -210,7 +210,7 @@ namespace Barotrauma.Items.Components
{
if (!powerOnSoundPlayed && powerOnSound != null)
{
SoundPlayer.PlaySound(powerOnSound.Sound, item.WorldPosition, powerOnSound.Volume, powerOnSound.Range, hullGuess: item.CurrentHull, ignoreMuffling: powerOnSound.IgnoreMuffling, freqMult: powerOnSound.GetRandomFrequencyMultiplier());
SoundPlayer.PlaySound(powerOnSound, item.WorldPosition, hullGuess: item.CurrentHull);
powerOnSoundPlayed = true;
}
}

View File

@@ -243,7 +243,16 @@ namespace Barotrauma.Items.Components
public void SetPhysicsBodyPosition(bool ignoreContacts = true)
{
if (PhysicsBody == null) { return; }
Vector2 offset = ConvertUnits.ToSimUnits(BodyOffset * item.Scale);
if (item.FlippedX)
{
offset.X = -offset.X;
}
if (item.FlippedY)
{
offset.Y = -offset.Y;
}
if (!MathUtils.NearlyEqual(item.RotationRad, 0))
{
Matrix transform = Matrix.CreateRotationZ(-item.RotationRad);
@@ -260,6 +269,15 @@ namespace Barotrauma.Items.Components
PhysicsBody.UpdateDrawPosition();
}
public override void FlipX(bool relativeToSub)
{
SetPhysicsBodyPosition();
}
public override void FlipY(bool relativeToSub)
{
SetPhysicsBodyPosition();
}
public override void OnMapLoaded()
{
base.OnMapLoaded();

View File

@@ -15,7 +15,7 @@ namespace Barotrauma
Humans = element.Elements().Select(npcElement => new HumanPrefab(npcElement, file, Identifier)).ToImmutableArray();
}
public static HumanPrefab? Get(Identifier setIdentifier, Identifier npcidentifier, bool logError = true)
public static HumanPrefab? Get(Identifier setIdentifier, Identifier npcidentifier, bool logError = true, ContentPackage? contentPackageToLogInError = null)
{
HumanPrefab? prefab = Sets.Where(set => set.Identifier == setIdentifier).SelectMany(npcSet => npcSet.Humans.Where(npcSetHuman => npcSetHuman.Identifier == npcidentifier)).FirstOrDefault();
@@ -23,7 +23,7 @@ namespace Barotrauma
{
if (logError)
{
DebugConsole.ThrowError($"Could not find human prefab \"{npcidentifier}\" from \"{setIdentifier}\".");
DebugConsole.ThrowError($"Could not find human prefab \"{npcidentifier}\" from \"{setIdentifier}\".", contentPackage: contentPackageToLogInError);
}
return null;
}

View File

@@ -196,36 +196,40 @@ namespace Barotrauma
private class Entry
{
private readonly HumanPrefab humanPrefab = null;
private readonly Identifier setIdentifier = Identifier.Empty;
private readonly Identifier npcIdentifier = Identifier.Empty;
public readonly Identifier SetIdentifier = Identifier.Empty;
public readonly Identifier NpcIdentifier = Identifier.Empty;
public readonly Identifier FactionIdentifier = Identifier.Empty;
public readonly ContentPackage ContentPackage;
public Entry(HumanPrefab humanPrefab, Identifier factionIdentifier)
public Entry(HumanPrefab humanPrefab, Identifier factionIdentifier, ContentPackage contentPackage)
{
this.humanPrefab = humanPrefab;
this.FactionIdentifier = factionIdentifier;
FactionIdentifier = factionIdentifier;
ContentPackage = contentPackage;
}
public Entry(Identifier setIdentifier, Identifier npcIdentifier, Identifier factionIdentifier)
public Entry(Identifier setIdentifier, Identifier npcIdentifier, Identifier factionIdentifier, ContentPackage contentPackage)
{
this.setIdentifier = setIdentifier;
this.npcIdentifier = npcIdentifier;
this.FactionIdentifier = factionIdentifier;
SetIdentifier = setIdentifier;
NpcIdentifier = npcIdentifier;
FactionIdentifier = factionIdentifier;
ContentPackage = contentPackage;
}
public HumanPrefab HumanPrefab
=> humanPrefab ?? NPCSet.Get(setIdentifier, npcIdentifier);
=> humanPrefab ?? NPCSet.Get(SetIdentifier, NpcIdentifier, contentPackageToLogInError: ContentPackage);
}
private readonly List<Entry> entries = new List<Entry>();
public void Add(HumanPrefab humanPrefab, Identifier factionIdentifier)
=> entries.Add(new Entry(humanPrefab, factionIdentifier));
public void Add(HumanPrefab humanPrefab, Identifier factionIdentifier, ContentPackage contentPackage)
=> entries.Add(new Entry(humanPrefab, factionIdentifier, contentPackage));
public void Add(Identifier setIdentifier, Identifier npcIdentifier, Identifier factionIdentifier)
=> entries.Add(new Entry(setIdentifier, npcIdentifier, factionIdentifier));
public void Add(Identifier setIdentifier, Identifier npcIdentifier, Identifier factionIdentifier, ContentPackage contentPackage)
=> entries.Add(new Entry(setIdentifier, npcIdentifier, factionIdentifier, contentPackage));
public IEnumerator<HumanPrefab> GetEnumerator()
{
@@ -244,7 +248,10 @@ namespace Barotrauma
{
if (entry.FactionIdentifier == Identifier.Empty || factions.Any(f => f.Identifier == entry.FactionIdentifier))
{
yield return entry.HumanPrefab;
if (entry.HumanPrefab != null)
{
yield return entry.HumanPrefab;
}
}
}
}
@@ -315,11 +322,11 @@ namespace Barotrauma
Identifier faction = npcElement.GetAttributeIdentifier("faction", Identifier.Empty);
if (from != Identifier.Empty)
{
newCollection.Add(from, npcElement.GetAttributeIdentifier("identifier", Identifier.Empty), faction);
newCollection.Add(from, npcElement.GetAttributeIdentifier("identifier", Identifier.Empty), faction, npcElement.ContentPackage);
}
else
{
newCollection.Add(new HumanPrefab(npcElement, file, npcSetIdentifier: from), faction);
newCollection.Add(new HumanPrefab(npcElement, file, npcSetIdentifier: from), faction, npcElement.ContentPackage);
}
}
humanPrefabCollections.Add(newCollection);

View File

@@ -1,4 +1,26 @@
-------------------------------------------------------------------------------------------------------------------------------------------------
v1.6.18.1
-------------------------------------------------------------------------------------------------------------------------------------------------
- Fixed several issues when the server rejects a name change due to a client trying to change their name too often: the server would start spamming the "can't change name" message, team and job preference selection would stop working too, and the game would crash when attempting to open the job preferences.
- Fixed equipped genes becoming tainted if you die due to disconnection.
- Fixed kill/death counters not working in the Sub vs. Sub PvP missions.
- Fixed gravity spheres not rotating in the sub editor.
- Fixed current generators not getting properly mirrored in ruins in mirrored levels.
- Fixed spawnpoints for escorted characters and prisoners not working.
- Fixed crashing if an AI character's husk infection is removed when they're using a ranged weapon.
- Fixed psychosis effect persisting if you leave the outpost midway through the "minds unraveled" event.
- Fixed night club merchants spawning in outposts without a night club.
- Fixed night club merchants not selling beer or rum (literally unplayable).
- Fixed bots cleaning up live grenades.
- Fixed server getting stuck in an infinite "restart loop" if autorestart or starting when everyone is ready is enabled and the selected perks are not suitable for the selected sub. The server would just attempt an immediate restart if the players wanted to cancel and reselect the perks.
- Fixed "All" option not working in the server browser's language filter dropdown.
- Fixed Raate Colony pvp map missing hulls near upper turrets.
Modding:
- Fixed outpost generation parameters that reference non-existent NPC prefabs causing a crash during outpost generation.
-------------------------------------------------------------------------------------------------------------------------------------------------
v1.6.17.0
-------------------------------------------------------------------------------------------------------------------------------------------------