diff --git a/Barotrauma/BarotraumaClient/Accessibility.dll b/Barotrauma/BarotraumaClient/Accessibility.dll
new file mode 100644
index 000000000..c04738936
Binary files /dev/null and b/Barotrauma/BarotraumaClient/Accessibility.dll differ
diff --git a/Barotrauma/BarotraumaClient/ClientCode.projitems b/Barotrauma/BarotraumaClient/ClientCode.projitems
index 991ce2d39..96e169d05 100644
--- a/Barotrauma/BarotraumaClient/ClientCode.projitems
+++ b/Barotrauma/BarotraumaClient/ClientCode.projitems
@@ -223,6 +223,7 @@
Never
+
diff --git a/Barotrauma/BarotraumaClient/LinuxClient.csproj b/Barotrauma/BarotraumaClient/LinuxClient.csproj
index c3c50da75..c96a76c05 100644
--- a/Barotrauma/BarotraumaClient/LinuxClient.csproj
+++ b/Barotrauma/BarotraumaClient/LinuxClient.csproj
@@ -80,8 +80,8 @@
-
- ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\GameAnalytics.Mono.dll
+
+ ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.2.1.6\lib\net45\GameAnalytics.Mono.dll
..\..\Libraries\NuGet\MonoGame.Framework.DesktopGL.3.7.1.189\lib\net45\MonoGame.Framework.dll
@@ -101,7 +101,7 @@
- ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\System.Data.SQLite.dll
+ ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.2.1.6\lib\net45\System.Data.SQLite.dll
@@ -247,6 +247,9 @@
PreserveNewest
+
+ PreserveNewest
+
PreserveNewest
@@ -268,6 +271,12 @@
PreserveNewest
+
+ PreserveNewest
+
+
+ PreserveNewest
+
PreserveNewest
@@ -341,13 +350,13 @@
-
-
+
+
This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
+
diff --git a/Barotrauma/BarotraumaClient/MacClient.csproj b/Barotrauma/BarotraumaClient/MacClient.csproj
index 797f42a80..b57d6b7cc 100644
--- a/Barotrauma/BarotraumaClient/MacClient.csproj
+++ b/Barotrauma/BarotraumaClient/MacClient.csproj
@@ -79,8 +79,8 @@
-
- ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\GameAnalytics.Mono.dll
+
+ ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.2.1.6\lib\net45\GameAnalytics.Mono.dll
..\..\Libraries\NuGet\MonoGame.Framework.DesktopGL.3.7.1.189\lib\net45\MonoGame.Framework.dll
@@ -100,7 +100,7 @@
- ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\System.Data.SQLite.dll
+ ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.2.1.6\lib\net45\System.Data.SQLite.dll
@@ -271,13 +271,12 @@
-
This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
+
-
+
-
+
+
+
\ No newline at end of file
diff --git a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs
index d93ecf6e3..b9666c162 100644
--- a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs
+++ b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs
@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("0.9.0.2")]
-[assembly: AssemblyFileVersion("0.9.0.2")]
+[assembly: AssemblyVersion("0.9.0.4")]
+[assembly: AssemblyFileVersion("0.9.0.4")]
diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs
index 0ee4b4bdf..aaf8d1e3b 100644
--- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs
+++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs
@@ -43,7 +43,7 @@ namespace Barotrauma
{
return text;
}
- text = TextManager.Get(textTag).Replace("[key]", keyBind);
+ text = TextManager.GetWithVariable(textTag, "[key]", keyBind);
cachedHudTexts.Add(textTag + keyBind, text);
return text;
}
diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterInfo.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterInfo.cs
index 9896272dd..f678e8b3a 100644
--- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterInfo.cs
+++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterInfo.cs
@@ -119,11 +119,9 @@ namespace Barotrauma
if ((int)newLevel > (int)prevLevel)
{
GUI.AddMessage(
- TextManager.Get("SkillIncreased")
- .Replace("[name]", Name)
- .Replace("[skillname]", TextManager.Get("SkillName." + skillIdentifier))
- .Replace("[newlevel]", ((int)newLevel).ToString()),
- Color.Green);
+ TextManager.GetWithVariables("SkillIncreased", new string[3] { "[name]", "[skillname]", "[newlevel]" },
+ new string[3] { Name, TextManager.Get("SkillName." + skillIdentifier), ((int)newLevel).ToString() },
+ new bool[3] { false, true, false }), Color.Green);
}
}
diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs
index 018d5254b..d9425a502 100644
--- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs
+++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs
@@ -181,13 +181,11 @@ namespace Barotrauma
bool attackInput = msg.ReadBoolean();
keys[(int)InputType.Attack].Held = attackInput;
keys[(int)InputType.Attack].SetState(false, attackInput);
-
- if (aimInput)
- {
- double aimAngle = ((double)msg.ReadUInt16() / 65535.0) * 2.0 * Math.PI;
- cursorPosition = AimRefPosition + new Vector2((float)Math.Cos(aimAngle), (float)Math.Sin(aimAngle)) * 60.0f;
- TransformCursorPos();
- }
+
+ double aimAngle = msg.ReadUInt16() / 65535.0 * 2.0 * Math.PI;
+ cursorPosition = AimRefPosition + new Vector2((float)Math.Cos(aimAngle), (float)Math.Sin(aimAngle)) * 60.0f;
+ TransformCursorPos();
+
bool ragdollInput = msg.ReadBoolean();
keys[(int)InputType.Ragdoll].Held = ragdollInput;
keys[(int)InputType.Ragdoll].SetState(false, ragdollInput);
diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Health/AfflictionHusk.cs b/Barotrauma/BarotraumaClient/Source/Characters/Health/AfflictionHusk.cs
index 727aea035..802016b71 100644
--- a/Barotrauma/BarotraumaClient/Source/Characters/Health/AfflictionHusk.cs
+++ b/Barotrauma/BarotraumaClient/Source/Characters/Health/AfflictionHusk.cs
@@ -26,7 +26,7 @@ namespace Barotrauma
}
else if (state != InfectionState.Active && Character.Controlled == character)
{
- GUI.AddMessage(TextManager.Get("HuskActivate").Replace("[Attack]", GameMain.Config.KeyBind(InputType.Attack).ToString()),
+ GUI.AddMessage(TextManager.GetWithVariable("HuskActivate", "[Attack]", GameMain.Config.KeyBind(InputType.Attack).ToString()),
Color.Red);
}
}
diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs
index afa1d3daf..90748c3f2 100644
--- a/Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs
+++ b/Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs
@@ -606,7 +606,7 @@ namespace Barotrauma
.ThenByDescending(a => a.Strength).FirstOrDefault();
if (affliction.DamagePerSecond > 0 || affliction.Strength > 0)
{
- var limbHealth = GetMathingLimbHealth(affliction);
+ var limbHealth = GetMatchingLimbHealth(affliction);
if (limbHealth != null)
{
selectedLimbIndex = limbHealths.IndexOf(limbHealth);
diff --git a/Barotrauma/BarotraumaClient/Source/DebugConsole.cs b/Barotrauma/BarotraumaClient/Source/DebugConsole.cs
index 98320ab69..f8a34fd0f 100644
--- a/Barotrauma/BarotraumaClient/Source/DebugConsole.cs
+++ b/Barotrauma/BarotraumaClient/Source/DebugConsole.cs
@@ -401,6 +401,18 @@ namespace Barotrauma
GameMain.CharacterEditorScreen.Select();
}));
+ commands.Add(new Command("money", "", args =>
+ {
+ if (args.Length == 0) { return; }
+ if (GameMain.GameSession.GameMode is CampaignMode campaign)
+ {
+ if (int.TryParse(args[0], out int money))
+ {
+ campaign.Money += money;
+ }
+ }
+ }, isCheat: true));
+
AssignRelayToServer("kick", false);
AssignRelayToServer("kickid", false);
AssignRelayToServer("ban", false);
diff --git a/Barotrauma/BarotraumaClient/Source/GameMain.cs b/Barotrauma/BarotraumaClient/Source/GameMain.cs
index a7e1de746..6f1f43694 100644
--- a/Barotrauma/BarotraumaClient/Source/GameMain.cs
+++ b/Barotrauma/BarotraumaClient/Source/GameMain.cs
@@ -343,7 +343,7 @@ namespace Barotrauma
SoundManager.SetCategoryGainMultiplier("ui", Config.SoundVolume);
SoundManager.SetCategoryGainMultiplier("waterambience", Config.SoundVolume);
SoundManager.SetCategoryGainMultiplier("music", Config.MusicVolume);
- SoundManager.SetCategoryGainMultiplier("voip", Config.VoiceChatVolume * 5.0f);
+ SoundManager.SetCategoryGainMultiplier("voip", Config.VoiceChatVolume * 20.0f);
if (Config.EnableSplashScreen)
{
var pendingSplashScreens = TitleScreen.PendingSplashScreens;
@@ -519,10 +519,8 @@ namespace Barotrauma
var exePaths = contentPackage.GetFilesOfType(ContentType.Executable);
if (exePaths.Any() && AppDomain.CurrentDomain.FriendlyName != exePaths.First())
{
- var msgBox = new GUIMessageBox(TextManager.Get("Error"),
- TextManager.Get("IncorrectExe")
- .Replace("[selectedpackage]", contentPackage.Name)
- .Replace("[exename]", exePaths.First()),
+ var msgBox = new GUIMessageBox(TextManager.Get("Error"), TextManager.GetWithVariables("IncorrectExe",
+ new string[2] { "[selectedpackage]", "[exename]" }, new string[2] { contentPackage.Name, exePaths.First() }),
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
msgBox.Buttons[0].OnClicked += (_, userdata) =>
{
@@ -618,7 +616,7 @@ namespace Barotrauma
GameMain.ResetFrameTime();
if (TitleScreen.LoadState >= 100.0f &&
- (!waitForKeyHit || PlayerInput.GetKeyboardState.GetPressedKeys().Length>0 || PlayerInput.LeftButtonClicked()))
+ (!waitForKeyHit || ((PlayerInput.GetKeyboardState.GetPressedKeys().Length > 0 || PlayerInput.LeftButtonClicked()) && WindowActive)))
{
loadingScreenOpen = false;
}
@@ -637,7 +635,7 @@ namespace Barotrauma
{
SoundPlayer.Update((float)Timing.Step);
- if (PlayerInput.KeyHit(Keys.Escape))
+ if (PlayerInput.KeyHit(Keys.Escape) && WindowActive)
{
// Check if a text input is selected.
if (GUI.KeyboardDispatcher.Subscriber != null)
@@ -862,7 +860,7 @@ namespace Barotrauma
{
if (NetworkMember != null) NetworkMember.Disconnect();
SteamManager.ShutDown();
- if (GameSettings.SendUserStatistics) GameAnalytics.OnStop();
+ if (GameSettings.SendUserStatistics) GameAnalytics.OnQuit();
base.OnExiting(sender, args);
}
}
diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs b/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs
index f85cd2475..392301a01 100644
--- a/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs
+++ b/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs
@@ -8,7 +8,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
-using Barotrauma.Extensions;
namespace Barotrauma
{
@@ -505,7 +504,10 @@ namespace Barotrauma
btn.OnClicked += (GUIButton button, object userData) =>
{
- if (Character.Controlled == null || Character.Controlled.SpeechImpediment >= 100.0f) return false;
+#if CLIENT
+ if (GameMain.Client != null && Character.Controlled == null) { return false; }
+#endif
+ if (Character.Controlled != null && Character.Controlled.SpeechImpediment >= 100.0f) { return false; }
if (btn.GetChildByUserData("selected").Visible)
{
@@ -919,7 +921,9 @@ namespace Barotrauma
Font = GUI.SmallFont,
OnClicked = (btn, userData) =>
{
- if (Character.Controlled == null) return false;
+#if CLIENT
+ if (GameMain.Client != null && Character.Controlled == null) { return false; }
+#endif
SetCharacterOrder(character, userData as Order, option, Character.Controlled);
orderTargetFrame = null;
OrderOptionButtons.Clear();
@@ -957,7 +961,9 @@ namespace Barotrauma
UserData = item == null ? order : new Order(order, item, item.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType)),
OnClicked = (btn, userData) =>
{
- if (Character.Controlled == null) return false;
+#if CLIENT
+ if (GameMain.Client != null && Character.Controlled == null) { return false; }
+#endif
SetCharacterOrder(character, userData as Order, option, Character.Controlled);
orderTargetFrame = null;
OrderOptionButtons.Clear();
@@ -1353,7 +1359,7 @@ namespace Barotrauma
bool hasLeaks = Character.Controlled.CurrentHull.Submarine != null && Character.Controlled.CurrentHull.ConnectedGaps.Any(g => !g.IsRoomToRoom && g.Open > 0.0f);
ToggleReportButton("reportbreach", hasLeaks);
- bool hasIntruders = Character.CharacterList.Any(c => c.CurrentHull == Character.Controlled.CurrentHull && AIObjectiveFightIntruders.IsValidTarget(Character.Controlled, c));
+ bool hasIntruders = Character.CharacterList.Any(c => c.CurrentHull == Character.Controlled.CurrentHull && AIObjectiveFightIntruders.IsValidTarget(c, Character.Controlled));
ToggleReportButton("reportintruders", hasIntruders);
foreach (GUIComponent reportButton in reportButtonFrame.Children)
diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/MultiPlayerCampaign.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/MultiPlayerCampaign.cs
index bb18197ea..6be3bacb1 100644
--- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/MultiPlayerCampaign.cs
+++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/MultiPlayerCampaign.cs
@@ -113,8 +113,8 @@ namespace Barotrauma
if (GameMain.Client != null && interactor == Character.Controlled)
{
- var msgBox = new GUIMessageBox("", TextManager.Get("CampaignEnterOutpostPrompt")
- .Replace("[locationname]", Submarine.MainSub.AtStartPosition ? Map.CurrentLocation.Name : Map.SelectedLocation.Name),
+ var msgBox = new GUIMessageBox("", TextManager.GetWithVariable("CampaignEnterOutpostPrompt", "[locationname]",
+ Submarine.MainSub.AtStartPosition ? Map.CurrentLocation.Name : Map.SelectedLocation.Name),
new string[] { TextManager.Get("Yes"), TextManager.Get("No") })
{
UserData = "watchmanprompt"
diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs
index b0463872e..0bb370465 100644
--- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs
+++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs
@@ -125,12 +125,12 @@ namespace Barotrauma
}
else if (leavingSub.AtEndPosition)
{
- endRoundButton.Text = ToolBox.LimitString(TextManager.Get("EnterLocation").Replace("[locationname]", Map.SelectedLocation.Name), endRoundButton.Font, endRoundButton.Rect.Width - 5);
+ endRoundButton.Text = ToolBox.LimitString(TextManager.GetWithVariable("EnterLocation", "[locationname]", Map.SelectedLocation.Name), endRoundButton.Font, endRoundButton.Rect.Width - 5);
endRoundButton.Visible = true;
}
else if (leavingSub.AtStartPosition)
{
- endRoundButton.Text = ToolBox.LimitString(TextManager.Get("EnterLocation").Replace("[locationname]", Map.CurrentLocation.Name), endRoundButton.Font, endRoundButton.Rect.Width - 5);
+ endRoundButton.Text = ToolBox.LimitString(TextManager.GetWithVariable("EnterLocation", "[locationname]", Map.CurrentLocation.Name), endRoundButton.Font, endRoundButton.Rect.Width - 5);
endRoundButton.Visible = true;
}
else
@@ -189,8 +189,8 @@ namespace Barotrauma
{
return;
}
- var msgBox = new GUIMessageBox("", TextManager.Get("CampaignEnterOutpostPrompt")
- .Replace("[locationname]", leavingSub.AtStartPosition ? Map.CurrentLocation.Name : Map.SelectedLocation.Name),
+ var msgBox = new GUIMessageBox("", TextManager.GetWithVariable("CampaignEnterOutpostPrompt", "[locationname]",
+ leavingSub.AtStartPosition ? Map.CurrentLocation.Name : Map.SelectedLocation.Name),
new string[] { TextManager.Get("Yes"), TextManager.Get("No") })
{
UserData = "watchmanprompt"
diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/CaptainTutorial.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/CaptainTutorial.cs
index 0e329d0f2..f45ec0fc9 100644
--- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/CaptainTutorial.cs
+++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/CaptainTutorial.cs
@@ -165,9 +165,9 @@ namespace Barotrauma.Tutorials
{
yield return null;
GameMain.GameSession.CrewManager.HighlightOrderButton(captain_mechanic, "repairsystems", highlightColor, new Vector2(5, 5));
- HighlightOrderOption("jobspecific");
+ //HighlightOrderOption("jobspecific");
}
- while (!HasOrder(captain_mechanic, "repairsystems", "jobspecific"));
+ while (!HasOrder(captain_mechanic, "repairsystems"));
RemoveCompletedObjective(segments[1]);
yield return new WaitForSeconds(2f, false);
TriggerTutorialSegment(2);
@@ -230,7 +230,7 @@ namespace Barotrauma.Tutorials
} while (!Submarine.MainSub.AtEndPosition || Submarine.MainSub.DockedTo.Count == 0);
RemoveCompletedObjective(segments[6]);
yield return new WaitForSeconds(3f, false);
- GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Captain.Radio.Complete").Replace("[OUTPOSTNAME]", GameMain.GameSession.EndLocation.Name), ChatMessageType.Radio, null);
+ GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.GetWithVariable("Captain.Radio.Complete", "[OUTPOSTNAME]", GameMain.GameSession.EndLocation.Name), ChatMessageType.Radio, null);
SetHighlight(captain_navConsole.Item, false);
SetHighlight(captain_sonar.Item, false);
SetHighlight(captain_statusMonitor, false);
diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/DoctorTutorial.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/DoctorTutorial.cs
index ef9a5000c..186656d22 100644
--- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/DoctorTutorial.cs
+++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/DoctorTutorial.cs
@@ -364,6 +364,10 @@ namespace Barotrauma.Tutorials
{
yield return new WaitForSeconds(1.0f, false);
}
+
+ subPatients[2].Oxygen = -50;
+ CoroutineManager.StartCoroutine(KeepPatientAlive(subPatients[2]), "KeepPatient3Alive");
+
yield return new WaitForSeconds(5.0f, false);
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Doctor.Radio.EnteredSub"), ChatMessageType.Radio, null);
@@ -376,8 +380,6 @@ namespace Barotrauma.Tutorials
patient.AIController.Enabled = true;
SetHighlight(patient, true);
}
- subPatients[2].Oxygen = -50;
- CoroutineManager.StartCoroutine(KeepPatientAlive(subPatients[2]), "KeepPatient3Alive");
double subEnterTime = Timing.TotalTime;
diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/EngineerTutorial.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/EngineerTutorial.cs
index 12f6bcf47..95dfd8b4b 100644
--- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/EngineerTutorial.cs
+++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/EngineerTutorial.cs
@@ -193,6 +193,7 @@ namespace Barotrauma.Tutorials
engineer_submarineJunctionBox_2 = Item.ItemList.Find(i => i.HasTag("engineer_submarinejunctionbox_2"));
engineer_submarineJunctionBox_3 = Item.ItemList.Find(i => i.HasTag("engineer_submarinejunctionbox_3"));
engineer_submarineReactor = Item.ItemList.Find(i => i.HasTag("engineer_submarinereactor")).GetComponent();
+ engineer_submarineReactor.OnOffSwitch.BarScrollValue = .25f;
engineer_submarineReactor.IsActive = engineer_submarineReactor.AutoTemp = false;
engineer_submarineJunctionBox_1.Indestructible = false;
diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/MechanicTutorial.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/MechanicTutorial.cs
index 4d516fb8e..c7a4755bb 100644
--- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/MechanicTutorial.cs
+++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/MechanicTutorial.cs
@@ -330,7 +330,6 @@ namespace Barotrauma.Tutorials
do { yield return null; } while (mechanic_brokenhull_1.WaterPercentage > waterVolumeBeforeOpening); // Unlock door once drained
RemoveCompletedObjective(segments[3]);
SetDoorAccess(mechanic_thirdDoor, mechanic_thirdDoorLight, true);
- yield return new WaitForSeconds(1.5f, false);
//TriggerTutorialSegment(11, GameMain.Config.KeyBind(InputType.Select), GameMain.Config.KeyBind(InputType.Up), GameMain.Config.KeyBind(InputType.Down), GameMain.Config.KeyBind(InputType.Select)); // Ladder objective
//do { yield return null; } while (!mechanic_ladderSensor.MotionDetected);
//RemoveCompletedObjective(segments[11]);
@@ -348,52 +347,46 @@ namespace Barotrauma.Tutorials
SetHighlight(mechanic_craftingCabinet.Item, true);
do
{
- for (int i = 0; i < mechanic_craftingCabinet.Inventory.Items.Length; i++)
- {
- if (mechanic_craftingCabinet.Inventory.Items[i] != null)
- {
- HighlightInventorySlot(mechanic_craftingCabinet.Inventory, i, highlightColor, .5f, .5f, 0f);
- }
- }
if (mechanic.SelectedConstruction == mechanic_craftingCabinet.Item)
{
for (int i = 0; i < mechanic.Inventory.slots.Length; i++)
{
if (mechanic.Inventory.Items[i] == null) HighlightInventorySlot(mechanic.Inventory, i, highlightColor, .5f, .5f, 0f);
}
- }
- yield return null;
- } while (mechanic.Inventory.FindItemByIdentifier("oxygentank") == null || mechanic.Inventory.FindItemByIdentifier("sodium") == null); // Wait until looted
- yield return new WaitForSeconds(1.0f, false);
- SetHighlight(mechanic_craftingCabinet.Item, false);
- SetHighlight(mechanic_deconstructor.Item, true);
-
- do
- {
- if (IsSelectedItem(mechanic_deconstructor.Item))
- {
- if (mechanic.Inventory.FindItemByIdentifier("oxygentank") != null)
+ if (mechanic.Inventory.FindItemByIdentifier("oxygentank") == null && mechanic.Inventory.FindItemByIdentifier("aluminium") == null)
{
- HighlightInventorySlot(mechanic.Inventory, "oxygentank", highlightColor, .5f, .5f, 0f);
-
- if (mechanic_deconstructor.InputContainer.Inventory.slots != null)
+ for (int i = 0; i < mechanic_craftingCabinet.Inventory.Items.Length; i++)
{
- for (int i = 0; i < mechanic_deconstructor.InputContainer.Inventory.slots.Length; i++)
+ Item item = mechanic_craftingCabinet.Inventory.Items[i];
+ if (item != null && item.prefab.Identifier == "oxygentank")
{
- HighlightInventorySlot(mechanic_deconstructor.InputContainer.Inventory, i, highlightColor, .5f, .5f, 0f);
+ HighlightInventorySlot(mechanic_craftingCabinet.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
}
- if (mechanic_deconstructor.InputContainer.Inventory.FindItemByIdentifier("oxygentank") != null && !mechanic_deconstructor.IsActive)
+ if (mechanic.Inventory.FindItemByIdentifier("sodium") == null)
{
- if (mechanic_deconstructor.ActivateButton.Frame.FlashTimer <= 0)
+ for (int i = 0; i < mechanic_craftingCabinet.Inventory.Items.Length; i++)
{
- mechanic_deconstructor.ActivateButton.Frame.Flash(highlightColor, 1.5f, false);
+ Item item = mechanic_craftingCabinet.Inventory.Items[i];
+ if (item != null && item.prefab.Identifier == "sodium")
+ {
+ HighlightInventorySlot(mechanic_craftingCabinet.Inventory, i, highlightColor, .5f, .5f, 0f);
+ }
}
}
-
+ }
+ yield return null;
+ } while ((mechanic.Inventory.FindItemByIdentifier("oxygentank") == null && mechanic.Inventory.FindItemByIdentifier("aluminium") == null) || mechanic.Inventory.FindItemByIdentifier("sodium") == null); // Wait until looted
+ yield return new WaitForSeconds(1.0f, false);
+ SetHighlight(mechanic_craftingCabinet.Item, false);
+ SetHighlight(mechanic_deconstructor.Item, true);
+ do
+ {
+ if (IsSelectedItem(mechanic_deconstructor.Item))
+ {
if (mechanic_deconstructor.OutputContainer.Inventory.FindItemByIdentifier("aluminium") != null)
{
HighlightInventorySlot(mechanic_deconstructor.OutputContainer.Inventory, "aluminium", highlightColor, .5f, .5f, 0f);
@@ -403,6 +396,29 @@ namespace Barotrauma.Tutorials
if (mechanic.Inventory.Items[i] == null) HighlightInventorySlot(mechanic.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
+ else
+ {
+ if (mechanic.Inventory.FindItemByIdentifier("oxygentank") != null && mechanic_deconstructor.InputContainer.Inventory.FindItemByIdentifier("oxygentank") == null)
+ {
+ HighlightInventorySlot(mechanic.Inventory, "oxygentank", highlightColor, .5f, .5f, 0f);
+
+ if (mechanic_deconstructor.InputContainer.Inventory.slots != null)
+ {
+ for (int i = 0; i < mechanic_deconstructor.InputContainer.Inventory.slots.Length; i++)
+ {
+ HighlightInventorySlot(mechanic_deconstructor.InputContainer.Inventory, i, highlightColor, .5f, .5f, 0f);
+ }
+ }
+ }
+
+ if (mechanic_deconstructor.InputContainer.Inventory.FindItemByIdentifier("oxygentank") != null && !mechanic_deconstructor.IsActive)
+ {
+ if (mechanic_deconstructor.ActivateButton.Frame.FlashTimer <= 0)
+ {
+ mechanic_deconstructor.ActivateButton.Frame.Flash(highlightColor, 1.5f, false);
+ }
+ }
+ }
}
yield return null;
} while (mechanic.Inventory.FindItemByIdentifier("aluminium") == null); // Wait until deconstructed
diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameSession.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameSession.cs
index 016cd1d1c..b9d2f5b69 100644
--- a/Barotrauma/BarotraumaClient/Source/GameSession/GameSession.cs
+++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameSession.cs
@@ -123,7 +123,7 @@ namespace Barotrauma
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform), Mission.Name, font: GUI.LargeFont);
- new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform), TextManager.Get("MissionReward").Replace("[reward]", Mission.Reward.ToString()));
+ new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform), TextManager.GetWithVariable("MissionReward", "[reward]", Mission.Reward.ToString()));
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform), Mission.Description, wrap: true);
}
diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/RoundSummary.cs b/Barotrauma/BarotraumaClient/Source/GameSession/RoundSummary.cs
index 2d6ebcfec..e4e0bb2a6 100644
--- a/Barotrauma/BarotraumaClient/Source/GameSession/RoundSummary.cs
+++ b/Barotrauma/BarotraumaClient/Source/GameSession/RoundSummary.cs
@@ -44,12 +44,9 @@ namespace Barotrauma
GUIListBox infoTextBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.7f), paddedFrame.RectTransform));
- string summaryText = TextManager.Get(gameOver ? "RoundSummaryGameOver" :
- (progress ? "RoundSummaryProgress" : "RoundSummaryReturn"));
-
- summaryText = summaryText
- .Replace("[sub]", Submarine.MainSub.Name)
- .Replace("[location]", progress ? GameMain.GameSession.EndLocation.Name : GameMain.GameSession.StartLocation.Name);
+ string summaryText = TextManager.GetWithVariables(gameOver ? "RoundSummaryGameOver" :
+ (progress ? "RoundSummaryProgress" : "RoundSummaryReturn"), new string[2] { "[sub]", "[location]" },
+ new string[2] { Submarine.MainSub.Name, progress ? GameMain.GameSession.EndLocation.Name : GameMain.GameSession.StartLocation.Name });
var infoText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
summaryText, wrap: true);
@@ -61,25 +58,27 @@ namespace Barotrauma
}
//don't show the mission info if the mission was not completed and there's no localized "mission failed" text available
- if (GameMain.GameSession.Mission != null &&
- (GameMain.GameSession.Mission.Completed || !string.IsNullOrEmpty(GameMain.GameSession.Mission.FailureMessage)))
+ if (GameMain.GameSession.Mission != null)
{
- //spacing
- new GUIFrame(new RectTransform(new Vector2(1.0f, 0.1f), infoTextBox.Content.RectTransform), style: null);
-
- new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
- TextManager.AddPunctuation(':', TextManager.Get("Mission"), GameMain.GameSession.Mission.Name),
- font: GUI.LargeFont);
-
- var missionInfo = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
- GameMain.GameSession.Mission.Completed ? GameMain.GameSession.Mission.SuccessMessage : GameMain.GameSession.Mission.FailureMessage,
- wrap: true);
-
- if (GameMain.GameSession.Mission.Completed && singleplayer)
+ string message = GameMain.GameSession.Mission.Completed ? GameMain.GameSession.Mission.SuccessMessage : GameMain.GameSession.Mission.FailureMessage;
+ if (!string.IsNullOrEmpty(message))
{
- var missionReward = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
- TextManager.Get("MissionReward").Replace("[reward]", GameMain.GameSession.Mission.Reward.ToString()));
- }
+ //spacing
+ new GUIFrame(new RectTransform(new Vector2(1.0f, 0.1f), infoTextBox.Content.RectTransform), style: null);
+
+ new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
+ TextManager.AddPunctuation(':', TextManager.Get("Mission"), GameMain.GameSession.Mission.Name),
+ font: GUI.LargeFont);
+
+ var missionInfo = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
+ message, wrap: true);
+
+ if (GameMain.GameSession.Mission.Completed && singleplayer)
+ {
+ var missionReward = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
+ TextManager.GetWithVariable("MissionReward", "[reward]", GameMain.GameSession.Mission.Reward.ToString()));
+ }
+ }
}
foreach (GUIComponent child in infoTextBox.Content.Children)
diff --git a/Barotrauma/BarotraumaClient/Source/GameSettings.cs b/Barotrauma/BarotraumaClient/Source/GameSettings.cs
index 212acdc56..a19e7fce8 100644
--- a/Barotrauma/BarotraumaClient/Source/GameSettings.cs
+++ b/Barotrauma/BarotraumaClient/Source/GameSettings.cs
@@ -106,18 +106,15 @@ namespace Barotrauma
{
tickBox.TextColor = Color.Red;
tickBox.Enabled = false;
- tickBox.ToolTip = TextManager.Get(contentPackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage")
- .Replace("[packagename]", contentPackage.Name)
- .Replace("[packageversion]", contentPackage.GameVersion.ToString())
- .Replace("[gameversion]", GameMain.Version.ToString());
+ tickBox.ToolTip = TextManager.GetWithVariables(contentPackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage",
+ new string[3] { "[packagename]", "[packageversion]", "[gameversion]" }, new string[3] { contentPackage.Name, contentPackage.GameVersion.ToString(), GameMain.Version.ToString() });
}
else if (contentPackage.CorePackage && !contentPackage.ContainsRequiredCorePackageFiles(out List missingContentTypes))
{
tickBox.TextColor = Color.Red;
tickBox.Enabled = false;
- tickBox.ToolTip = TextManager.Get("ContentPackageMissingCoreFiles")
- .Replace("[packagename]", contentPackage.Name)
- .Replace("[missingfiletypes]", string.Join(", ", missingContentTypes));
+ tickBox.ToolTip = TextManager.GetWithVariables("ContentPackageMissingCoreFiles", new string[2] { "[packagename]", "[missingfiletypes]" },
+ new string[2] { contentPackage.Name, string.Join(", ", missingContentTypes) }, new bool[2] { false, true });
}
}
diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/MiniMap.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/MiniMap.cs
index 467bbbb77..0e058bbd9 100644
--- a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/MiniMap.cs
+++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/MiniMap.cs
@@ -110,7 +110,7 @@ namespace Barotrauma.Items.Components
if (child.UserData is Hull hull)
{
if (hull.Submarine == null || !hull.Submarine.IsOutpost) { continue; }
- string text = TextManager.Get("MiniMapOutpostDockingInfo").Replace("[outpost]", hull.Submarine.Name);
+ string text = TextManager.GetWithVariable("MiniMapOutpostDockingInfo", "[outpost]", hull.Submarine.Name);
Vector2 textSize = GUI.Font.MeasureString(text);
Vector2 textPos = child.Center;
if (textPos.X + textSize.X / 2 > submarineContainer.Rect.Right)
diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Steering.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Steering.cs
index 404829e26..a6fc8d8e2 100644
--- a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Steering.cs
+++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Steering.cs
@@ -290,9 +290,9 @@ namespace Barotrauma.Items.Components
noPowerTip = TextManager.Get("SteeringNoPowerTip");
autoPilotMaintainPosTip = TextManager.Get("SteeringAutoPilotMaintainPosTip");
- autoPilotLevelStartTip = TextManager.Get("SteeringAutoPilotLocationTip").Replace("[locationname]",
+ autoPilotLevelStartTip = TextManager.GetWithVariable("SteeringAutoPilotLocationTip", "[locationname]",
GameMain.GameSession?.StartLocation == null ? "Start" : GameMain.GameSession.StartLocation.Name);
- autoPilotLevelEndTip = TextManager.Get("SteeringAutoPilotLocationTip").Replace("[locationname]",
+ autoPilotLevelEndTip = TextManager.GetWithVariable("SteeringAutoPilotLocationTip", "[locationname]",
GameMain.GameSession?.EndLocation == null ? "End" : GameMain.GameSession.EndLocation.Name);
steerArea = new GUICustomComponent(new RectTransform(new Point(viewSize), GuiFrame.RectTransform, Anchor.CenterLeft),
diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/Connection.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/Connection.cs
index d5ab17ccb..294f6214b 100644
--- a/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/Connection.cs
+++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/Connection.cs
@@ -57,8 +57,8 @@ namespace Barotrauma.Items.Components
}
}
- Vector2 rightPos = new Vector2(x + width - 130 * GUI.xScale, y + 80 * GUI.yScale);
- Vector2 leftPos = new Vector2(x + 130 * GUI.xScale, y + 80 * GUI.yScale);
+ Vector2 rightPos = new Vector2(x + width - 110 * GUI.xScale, y + 80 * GUI.yScale);
+ Vector2 leftPos = new Vector2(x + 110 * GUI.xScale, y + 80 * GUI.yScale);
Vector2 rightWirePos = new Vector2(x + width - 5 * GUI.xScale, y + 30 * GUI.yScale);
Vector2 leftWirePos = new Vector2(x + 5 * GUI.xScale, y + 30 * GUI.yScale);
diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/CustomInterface.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/CustomInterface.cs
index a116d7603..004286d00 100644
--- a/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/CustomInterface.cs
+++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/CustomInterface.cs
@@ -120,13 +120,13 @@ namespace Barotrauma.Items.Components
if (uiElements[i] is GUIButton button)
{
button.Text = string.IsNullOrWhiteSpace(customInterfaceElementList[i].Label) ?
- TextManager.Get("connection.signaloutx").Replace("[num]", (i + 1).ToString()) :
+ TextManager.GetWithVariable("connection.signaloutx", "[num]", (i + 1).ToString()) :
customInterfaceElementList[i].Label;
}
else if (uiElements[i] is GUITickBox tickBox)
{
tickBox.Text = string.IsNullOrWhiteSpace(customInterfaceElementList[i].Label) ?
- TextManager.Get("connection.signaloutx").Replace("[num]", (i + 1).ToString()) :
+ TextManager.GetWithVariable("connection.signaloutx", "[num]", (i + 1).ToString()) :
customInterfaceElementList[i].Label;
}
}
diff --git a/Barotrauma/BarotraumaClient/Source/Items/Inventory.cs b/Barotrauma/BarotraumaClient/Source/Items/Inventory.cs
index 3f8633f0c..53994493b 100644
--- a/Barotrauma/BarotraumaClient/Source/Items/Inventory.cs
+++ b/Barotrauma/BarotraumaClient/Source/Items/Inventory.cs
@@ -721,7 +721,7 @@ namespace Barotrauma
var shadowSprite = GUI.Style.GetComponentStyle("OuterGlow").Sprites[GUIComponent.ComponentState.None][0];
string toolTip = mouseOnHealthInterface ? TextManager.Get("QuickUseAction.UseTreatment") :
Character.Controlled.FocusedItem != null ?
- TextManager.Get("PutItemIn").Replace("[itemname]", Character.Controlled.FocusedItem.Name) :
+ TextManager.GetWithVariable("PutItemIn", "[itemname]", Character.Controlled.FocusedItem.Name, true) :
TextManager.Get("DropItem");
int textWidth = (int)Math.Max(GUI.Font.MeasureString(draggingItem.Name).X, GUI.SmallFont.MeasureString(toolTip).X);
int textSpacing = (int)(15 * GUI.Scale);
@@ -771,11 +771,11 @@ namespace Barotrauma
{
if (idJob == null)
{
- description = TextManager.Get("IDCardName").Replace("[name]", idName);
+ description = TextManager.GetWithVariable("IDCardName", "[name]", idName);
}
else
{
- description = TextManager.Get("IDCardNameJob").Replace("[name]", idName).Replace("[job]", idJob);
+ description = TextManager.GetWithVariables("IDCardNameJob", new string[2] { "[name]", "[job]" }, new string[2] { idName, idJob }, new bool[2] { false, true });
}
if (!string.IsNullOrEmpty(item.Description))
{
diff --git a/Barotrauma/BarotraumaClient/Source/Items/Item.cs b/Barotrauma/BarotraumaClient/Source/Items/Item.cs
index bd3248c1a..83476d546 100644
--- a/Barotrauma/BarotraumaClient/Source/Items/Item.cs
+++ b/Barotrauma/BarotraumaClient/Source/Items/Item.cs
@@ -51,7 +51,7 @@ namespace Barotrauma
{
itemInUseWarning = new GUITextBlock(new RectTransform(new Point(10), GUI.Canvas), "",
textColor: Color.Orange, color: Color.Black,
- textAlignment:Alignment.Center, style: "OuterGlow");
+ textAlignment: Alignment.Center, style: "OuterGlow");
}
return itemInUseWarning;
}
@@ -662,7 +662,7 @@ namespace Barotrauma
new Rectangle(
20, 20,
GameMain.GraphicsWidth - 40,
- HUDLayoutSettings.InventoryTopY > 0 ? HUDLayoutSettings.InventoryTopY - 20 : GameMain.GraphicsHeight - 80));
+ HUDLayoutSettings.InventoryTopY > 0 ? HUDLayoutSettings.InventoryTopY - 40 : GameMain.GraphicsHeight - 80));
foreach (ItemComponent ic in activeHUDs)
{
@@ -740,9 +740,9 @@ namespace Barotrauma
}
}
- if (itemInUseWarning != null && mergedHUDRect != Rectangle.Empty)
+ if (mergedHUDRect != Rectangle.Empty)
{
- itemInUseWarning.Visible = false;
+ if (itemInUseWarning != null) { itemInUseWarning.Visible = false; }
foreach (Character otherCharacter in Character.CharacterList)
{
if (otherCharacter != character &&
@@ -754,7 +754,7 @@ namespace Barotrauma
itemInUseWarning.RectTransform.NonScaledSize = new Point(mergedHUDRect.Width, (int)(50 * GUI.Scale));
if (itemInUseWarning.UserData != otherCharacter)
{
- itemInUseWarning.Text = TextManager.Get("ItemInUse").Replace("[character]", otherCharacter.Name);
+ itemInUseWarning.Text = TextManager.GetWithVariable("ItemInUse", "[character]", otherCharacter.Name);
itemInUseWarning.UserData = otherCharacter;
}
break;
diff --git a/Barotrauma/BarotraumaClient/Source/Map/LinkedSubmarine.cs b/Barotrauma/BarotraumaClient/Source/Map/LinkedSubmarine.cs
index 7b311c66b..ce5385fee 100644
--- a/Barotrauma/BarotraumaClient/Source/Map/LinkedSubmarine.cs
+++ b/Barotrauma/BarotraumaClient/Source/Map/LinkedSubmarine.cs
@@ -127,7 +127,7 @@ namespace Barotrauma
if (!File.Exists(pathBox.Text))
{
- new GUIMessageBox(TextManager.Get("Error"), TextManager.Get("ReloadLinkedSubError").Replace("[file]", pathBox.Text));
+ new GUIMessageBox(TextManager.Get("Error"), TextManager.GetWithVariable("ReloadLinkedSubError", "[file]", pathBox.Text));
pathBox.Flash(Color.Red);
pathBox.Text = filePath;
return false;
diff --git a/Barotrauma/BarotraumaClient/Source/Map/Submarine.cs b/Barotrauma/BarotraumaClient/Source/Map/Submarine.cs
index 7e9d2051b..3063a925b 100644
--- a/Barotrauma/BarotraumaClient/Source/Map/Submarine.cs
+++ b/Barotrauma/BarotraumaClient/Source/Map/Submarine.cs
@@ -310,7 +310,7 @@ namespace Barotrauma
Vector2 realWorldDimensions = Dimensions * Physics.DisplayToRealWorldRatio;
if (realWorldDimensions != Vector2.Zero)
{
- string dimensionsStr = TextManager.Get("DimensionsFormat").Replace("[width]", ((int)(realWorldDimensions.X)).ToString()).Replace("[height]", ((int)(realWorldDimensions.Y)).ToString());
+ string dimensionsStr = TextManager.GetWithVariables("DimensionsFormat", new string[2] { "[width]", "[height]" }, new string[2] { ((int)realWorldDimensions.X).ToString(), ((int)realWorldDimensions.Y).ToString() });
var dimensionsText = new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform),
TextManager.Get("Dimensions"), textAlignment: Alignment.TopLeft, font: GUI.Font, wrap: true)
diff --git a/Barotrauma/BarotraumaClient/Source/Networking/BanList.cs b/Barotrauma/BarotraumaClient/Source/Networking/BanList.cs
index 5077cef2c..962e8f436 100644
--- a/Barotrauma/BarotraumaClient/Source/Networking/BanList.cs
+++ b/Barotrauma/BarotraumaClient/Source/Networking/BanList.cs
@@ -81,7 +81,7 @@ namespace Barotrauma.Networking
new GUITextBlock(new RectTransform(new Vector2(0.6f, 0.0f), paddedPlayerFrame.RectTransform),
bannedPlayer.ExpirationTime == null ?
- TextManager.Get("BanPermanent") : TextManager.Get("BanExpires").Replace("[time]", bannedPlayer.ExpirationTime.Value.ToString()),
+ TextManager.Get("BanPermanent") : TextManager.GetWithVariable("BanExpires", "[time]", bannedPlayer.ExpirationTime.Value.ToString()),
font: GUI.SmallFont);
var reasonText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 0.0f), paddedPlayerFrame.RectTransform),
diff --git a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs
index 205820841..26e9bdf38 100644
--- a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs
+++ b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs
@@ -269,7 +269,7 @@ namespace Barotrauma.Networking
catch
{
new GUIMessageBox(TextManager.Get("CouldNotConnectToServer"),
- TextManager.Get("InvalidIPAddress").Replace("[serverip]", serverIP).Replace("[port]", Port.ToString()));
+ TextManager.GetWithVariables("InvalidIPAddress", new string[2] { "[serverip]", "[port]" }, new string[2] { serverIP, Port.ToString() }));
return;
}
@@ -319,10 +319,11 @@ namespace Barotrauma.Networking
}
private bool connectCancelled;
- private bool CancelConnect(GUIButton button, object obj)
+ private void CancelConnect()
{
connectCancelled = true;
- return true;
+ steamAuthTicket?.Cancel();
+ steamAuthTicket = null;
}
// Before main looping starts, we loop here and wait for approval message
@@ -346,8 +347,8 @@ namespace Barotrauma.Networking
{
if (reconnectBox == null)
{
- reconnectBox = new GUIMessageBox(connectingText, TextManager.Get("ConnectingTo").Replace("[serverip]", serverIP), new string[] { TextManager.Get("Cancel") });
- reconnectBox.Buttons[0].OnClicked += CancelConnect;
+ reconnectBox = new GUIMessageBox(connectingText, TextManager.GetWithVariable("ConnectingTo", "[serverip]", serverIP), new string[] { TextManager.Get("Cancel") });
+ reconnectBox.Buttons[0].OnClicked += (btn, userdata) => { CancelConnect(); return true; };
reconnectBox.Buttons[0].OnClicked += reconnectBox.Close;
}
@@ -447,7 +448,7 @@ namespace Barotrauma.Networking
if (connectionStatus == NetConnectionStatus.Disconnected)
{
ReadDisconnectMessage(inc, false);
- connectCancelled = true;
+ CancelConnect();
}
break;
}
@@ -467,8 +468,9 @@ namespace Barotrauma.Networking
reconnectBox = null;
}
- var msgBox = new GUIMessageBox(pwMsg, "", new string[] { TextManager.Get("OK"), TextManager.Get("Cancel") });
- var passwordBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 0.1f), msgBox.InnerFrame.RectTransform, Anchor.Center))
+ var msgBox = new GUIMessageBox(pwMsg, "", new string[] { TextManager.Get("OK"), TextManager.Get("Cancel") },
+ relativeSize: new Vector2(0.25f, 0.2f), minSize: new Point(400, 150));
+ var passwordBox = new GUITextBox(new RectTransform(new Vector2(0.8f, 0.1f), msgBox.InnerFrame.RectTransform, Anchor.Center) { MinSize = new Point(0, 20) })
{
IgnoreLayoutGroups = true,
UserData = "password"
@@ -489,7 +491,7 @@ namespace Barotrauma.Networking
{
ReadDisconnectMessage(inc, false);
msgBox.Close(null, null);
- connectCancelled = true;
+ CancelConnect();
}
break;
}
@@ -521,7 +523,7 @@ namespace Barotrauma.Networking
else if (cancelButton.Selected)
{
msgBox.Close(null, null);
- connectCancelled = true;
+ CancelConnect();
}
else
{
@@ -665,7 +667,7 @@ namespace Barotrauma.Networking
string errorMsg = "Error while reading a message from server. {" + e + "}\n" + e.StackTrace;
GameAnalyticsManager.AddErrorEventOnce("GameClient.Update:CheckServerMessagesException" + e.TargetSite.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
DebugConsole.ThrowError("Error while reading a message from server.", e);
- new GUIMessageBox(TextManager.Get("Error"), TextManager.Get("MessageReadError").Replace("[message]", e.Message).Replace("[targetsite]", e.TargetSite.ToString()));
+ new GUIMessageBox(TextManager.Get("Error"), TextManager.GetWithVariables("MessageReadError", new string[2] { "[message]", "[targetsite]" }, new string[2] { e.Message, e.TargetSite.ToString() }));
Disconnect();
GameMain.MainMenuScreen.Select();
return;
@@ -1197,7 +1199,7 @@ namespace Barotrauma.Networking
{
secondsLeft -= CoroutineManager.UnscaledDeltaTime;
yield return CoroutineStatus.Running;
- } while (secondsLeft > 0.0f);
+ } while (secondsLeft > 0.0f && Screen.Selected == GameMain.GameScreen);
}
Submarine.Unload();
@@ -1684,7 +1686,7 @@ namespace Barotrauma.Networking
switch (transfer.FileType)
{
case FileTransferType.Submarine:
- new GUIMessageBox(TextManager.Get("ServerDownloadFinished"), TextManager.Get("FileDownloadedNotification").Replace("[filename]", transfer.FileName));
+ new GUIMessageBox(TextManager.Get("ServerDownloadFinished"), TextManager.GetWithVariable("FileDownloadedNotification", "[filename]", transfer.FileName));
var newSub = new Submarine(transfer.FilePath);
var existingSubs = Submarine.SavedSubmarines.Where(s => s.Name == newSub.Name && s.MD5Hash.Hash == newSub.MD5Hash.Hash).ToList();
foreach (Submarine existingSub in existingSubs)
@@ -1803,7 +1805,6 @@ namespace Barotrauma.Networking
{
client.Shutdown("");
steamAuthTicket?.Cancel();
-
steamAuthTicket = null;
foreach (var fileTransfer in FileReceiver.ActiveTransfers)
@@ -2263,7 +2264,7 @@ namespace Barotrauma.Networking
GUI.DrawString(spriteBatch,
pos,
- ToolBox.LimitString(TextManager.Get("DownloadingFile").Replace("[filename]", transfer.FileName), GUI.SmallFont, (int)downloadBarSize.X),
+ ToolBox.LimitString(TextManager.GetWithVariable("DownloadingFile", "[filename]", transfer.FileName), GUI.SmallFont, (int)downloadBarSize.X),
Color.White, null, 0, GUI.SmallFont);
GUI.DrawProgressBar(spriteBatch, new Vector2(pos.X, -pos.Y - downloadBarSize.Y / 2), new Vector2(downloadBarSize.X * 0.7f, downloadBarSize.Y / 2), transfer.Progress, Color.Green);
GUI.DrawString(spriteBatch, pos + new Vector2(5, downloadBarSize.Y / 2),
@@ -2296,9 +2297,7 @@ namespace Barotrauma.Networking
}
else
{
- string endVoteText = TextManager.Get("EndRoundVotes")
- .Replace("[votes]", EndVoteCount.ToString())
- .Replace("[max]", EndVoteMax.ToString());
+ string endVoteText = TextManager.GetWithVariables("EndRoundVotes", new string[2] { "[votes]", "[max]" }, new string[2] { EndVoteCount.ToString(), EndVoteMax.ToString() });
GUI.DrawString(spriteBatch, EndVoteTickBox.Rect.Center.ToVector2() - GUI.SmallFont.MeasureString(endVoteText) / 2,
endVoteText,
Color.White,
@@ -2316,14 +2315,13 @@ namespace Barotrauma.Networking
if (respawnManager.CurrentState == RespawnManager.State.Waiting &&
respawnManager.CountdownStarted)
{
- respawnInfo = TextManager.Get(respawnManager.UsingShuttle ? "RespawnShuttleDispatching" : "RespawningIn");
- respawnInfo = respawnInfo.Replace("[time]", ToolBox.SecondsToReadableTime(respawnManager.RespawnTimer));
+ respawnInfo = TextManager.GetWithVariable(respawnManager.UsingShuttle ? "RespawnShuttleDispatching" : "RespawningIn", "[time]", ToolBox.SecondsToReadableTime(respawnManager.RespawnTimer));
}
else if (respawnManager.CurrentState == RespawnManager.State.Transporting)
{
respawnInfo = respawnManager.TransportTimer <= 0.0f ?
"" :
- TextManager.Get("RespawnShuttleLeavingIn").Replace("[time]", ToolBox.SecondsToReadableTime(respawnManager.TransportTimer));
+ TextManager.GetWithVariable("RespawnShuttleLeavingIn", "[time]", ToolBox.SecondsToReadableTime(respawnManager.TransportTimer));
}
if (respawnManager != null)
diff --git a/Barotrauma/BarotraumaClient/Source/Networking/ServerInfo.cs b/Barotrauma/BarotraumaClient/Source/Networking/ServerInfo.cs
index d896575f9..68356b34d 100644
--- a/Barotrauma/BarotraumaClient/Source/Networking/ServerInfo.cs
+++ b/Barotrauma/BarotraumaClient/Source/Networking/ServerInfo.cs
@@ -203,23 +203,20 @@ namespace Barotrauma.Networking
if (ContentPackage.List.Any(cp => cp.MD5hash.Hash == ContentPackageHashes[i]))
{
packageText.TextColor = Color.Orange;
- packageText.ToolTip = TextManager.Get("ServerListContentPackageNotEnabled")
- .Replace("[contentpackage]", ContentPackageNames[i]);
+ packageText.ToolTip = TextManager.GetWithVariable("ServerListContentPackageNotEnabled", "[contentpackage]", ContentPackageNames[i]);
}
//workshop download link found
else if (i < ContentPackageWorkshopUrls.Count && !string.IsNullOrEmpty(ContentPackageWorkshopUrls[i]))
{
availableWorkshopUrls.Add(ContentPackageWorkshopUrls[i]);
packageText.TextColor = Color.Yellow;
- packageText.ToolTip = TextManager.Get("ServerListIncompatibleContentPackageWorkshopAvailable")
- .Replace("[contentpackage]", ContentPackageNames[i]);
+ packageText.ToolTip = TextManager.GetWithVariable("ServerListIncompatibleContentPackageWorkshopAvailable", "[contentpackage]", ContentPackageNames[i]);
}
else //no package or workshop download link found, tough luck
{
packageText.TextColor = Color.Red;
- packageText.ToolTip = TextManager.Get("ServerListIncompatibleContentPackage")
- .Replace("[contentpackage]", ContentPackageNames[i])
- .Replace("[hash]", ContentPackageHashes[i]);
+ packageText.ToolTip = TextManager.GetWithVariables("ServerListIncompatibleContentPackage",
+ new string[2] { "[contentpackage]", "[hash]" }, new string[2] { ContentPackageNames[i], ContentPackageHashes[i] });
}
}
}
diff --git a/Barotrauma/BarotraumaClient/Source/Networking/ServerSettings.cs b/Barotrauma/BarotraumaClient/Source/Networking/ServerSettings.cs
index a4e27b2e1..2af9e3428 100644
--- a/Barotrauma/BarotraumaClient/Source/Networking/ServerSettings.cs
+++ b/Barotrauma/BarotraumaClient/Source/Networking/ServerSettings.cs
@@ -464,7 +464,8 @@ namespace Barotrauma.Networking
((GUIComponent)obj).Visible = !((GUIComponent)obj).Visible;
return true;
};
-
+
+ InitMonstersEnabled();
List monsterNames = MonsterEnabled.Keys.ToList();
tempMonsterEnabled = new Dictionary(MonsterEnabled);
foreach (string s in monsterNames)
diff --git a/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs b/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs
index 696d6d141..38b56ce3e 100644
--- a/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs
+++ b/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs
@@ -1,11 +1,11 @@
using Barotrauma.Networking;
using Facepunch.Steamworks;
+using RestSharp;
using RestSharp.Extensions.MonoHttp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using System.Net;
namespace Barotrauma.Steam
{
@@ -467,13 +467,29 @@ namespace Barotrauma.Steam
string previewImagePath = Path.GetFullPath(Path.Combine(itemEditor.Folder, PreviewImageName));
itemEditor.PreviewImage = previewImagePath;
- using (WebClient client = new WebClient())
+ try
{
- if (File.Exists(previewImagePath))
+ if (File.Exists(previewImagePath)) { File.Delete(previewImagePath); }
+
+ Uri baseAddress = new Uri(existingItem.PreviewImageUrl);
+ Uri directory = new Uri(baseAddress, "."); // "." == current dir, like MS-DOS
+ string fileName = Path.GetFileName(baseAddress.LocalPath);
+
+ IRestClient client = new RestClient(directory);
+ var request = new RestRequest(fileName, Method.GET);
+ var response = client.Execute(request);
+
+ if (response.ResponseStatus == ResponseStatus.Completed)
{
- File.Delete(previewImagePath);
+ File.WriteAllBytes(previewImagePath, response.RawBytes);
}
- client.DownloadFile(new Uri(existingItem.PreviewImageUrl), previewImagePath);
+ }
+
+ catch (Exception e)
+ {
+ string errorMsg = "Failed to save workshop item preview image to \"" + previewImagePath + "\" when creating workshop item staging folder.";
+ GameAnalyticsManager.AddErrorEventOnce("SteamManager.CreateWorkshopItemStaging:WriteAllBytesFailed" + previewImagePath,
+ GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + e.Message);
}
ContentPackage tempContentPackage = new ContentPackage(Path.Combine(existingItem.Directory.FullName, MetadataFileName));
@@ -580,7 +596,7 @@ namespace Barotrauma.Steam
{
if (!item.Installed)
{
- errorMsg = TextManager.Get("WorkshopErrorInstallRequiredToEnable").Replace("[itemname]", item.Title);
+ errorMsg = TextManager.GetWithVariable("WorkshopErrorInstallRequiredToEnable", "[itemname]", item.Title);
DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red);
return false;
}
@@ -591,18 +607,15 @@ namespace Barotrauma.Steam
if (!contentPackage.IsCompatible())
{
- errorMsg = TextManager.Get(contentPackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage")
- .Replace("[packagename]", contentPackage.Name)
- .Replace("[packageversion]", contentPackage.GameVersion.ToString())
- .Replace("[gameversion]", GameMain.Version.ToString());
+ errorMsg = TextManager.GetWithVariables(contentPackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage",
+ new string[3] { "[packagename]", "[packageversion]", "[gameversion]" }, new string[3] { contentPackage.Name, contentPackage.GameVersion.ToString(), GameMain.Version.ToString() });
return false;
}
if (contentPackage.CorePackage && !contentPackage.ContainsRequiredCorePackageFiles(out List missingContentTypes))
{
- errorMsg = TextManager.Get("ContentPackageMissingCoreFiles")
- .Replace("[packagename]", contentPackage.Name)
- .Replace("[missingfiletypes]", string.Join(", ", missingContentTypes));
+ errorMsg = TextManager.GetWithVariables("ContentPackageMissingCoreFiles", new string[2] { "[packagename]", "[missingfiletypes]" },
+ new string[2] { contentPackage.Name, string.Join(", ", missingContentTypes) }, new bool[2] { false, true });
return false;
}
@@ -624,9 +637,7 @@ namespace Barotrauma.Steam
{
if (File.Exists(newContentPackagePath) && !CheckFileEquality(newContentPackagePath, metaDataFilePath))
{
- errorMsg = TextManager.Get("WorkshopErrorOverwriteOnEnable")
- .Replace("[itemname]", item.Title)
- .Replace("[filename]", newContentPackagePath);
+ errorMsg = TextManager.GetWithVariables("WorkshopErrorOverwriteOnEnable", new string[2] { "[itemname]", "[filename]" }, new string[2] { item.Title, newContentPackagePath });
DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red);
return false;
}
@@ -636,9 +647,7 @@ namespace Barotrauma.Steam
string sourceFile = Path.Combine(item.Directory.FullName, contentFile.Path);
if (File.Exists(sourceFile) && File.Exists(contentFile.Path) && !CheckFileEquality(sourceFile, contentFile.Path))
{
- errorMsg = TextManager.Get("WorkshopErrorOverwriteOnEnable")
- .Replace("[itemname]", item.Title)
- .Replace("[filename]", contentFile.Path);
+ errorMsg = TextManager.GetWithVariables("WorkshopErrorOverwriteOnEnable", new string[2] { "[itemname]", "[filename]" }, new string[2] { item.Title, contentFile.Path });
DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red);
return false;
}
@@ -657,15 +666,14 @@ namespace Barotrauma.Steam
//the content package is trying to copy a file to a prohibited path, which is not allowed
if (File.Exists(sourceFile))
{
- errorMsg = TextManager.Get("WorkshopErrorIllegalPathOnEnable").Replace("[filename]", contentFile.Path);
+ errorMsg = TextManager.GetWithVariable("WorkshopErrorIllegalPathOnEnable", "[filename]", contentFile.Path);
return false;
}
//not trying to copy anything, so this is a reference to an external file
//if the external file doesn't exist, we cannot enable the package
else if (!File.Exists(contentFile.Path))
{
- //TODO: add the error message to localization
- errorMsg = TextManager.Get("WorkshopErrorEnableFailed").Replace("[itemname]", item.Title) + " {File \"" + contentFile.Path + "\" not found.}";
+ errorMsg = TextManager.GetWithVariable("WorkshopErrorEnableFailed", "[itemname]", item.Title) + " " + TextManager.GetWithVariable("WorkshopFileNotFound", "[path]", "\"" + contentFile.Path + "\"");
return false;
}
continue;
@@ -680,8 +688,7 @@ namespace Barotrauma.Steam
else
{
//file not present in either the mod or the game folder -> cannot enable the package
- //TODO: add the error message to localization
- errorMsg = TextManager.Get("WorkshopErrorEnableFailed").Replace("[itemname]", item.Title) + " {File \"" + contentFile.Path + "\" not found.}";
+ errorMsg = TextManager.GetWithVariable("WorkshopErrorEnableFailed", "[itemname]", item.Title) + " " + TextManager.GetWithVariable("WorkshopFileNotFound", "[path]", "\"" + contentFile.Path + "\"");
return false;
}
}
@@ -697,7 +704,7 @@ namespace Barotrauma.Steam
if (!File.Exists(sourceFile)) { continue; }
if (!ContentPackage.IsModFilePathAllowed(nonContentFile))
{
- DebugConsole.ThrowError(TextManager.Get("WorkshopErrorIllegalPathOnEnable").Replace("[filename]", nonContentFile));
+ DebugConsole.ThrowError(TextManager.GetWithVariable("WorkshopErrorIllegalPathOnEnable", "[filename]", nonContentFile));
continue;
}
Directory.CreateDirectory(Path.GetDirectoryName(nonContentFile));
@@ -706,7 +713,7 @@ namespace Barotrauma.Steam
}
catch (Exception e)
{
- errorMsg = TextManager.Get("WorkshopErrorEnableFailed").Replace("[itemname]", item.Title) + " {" + e.Message + "}";
+ errorMsg = TextManager.GetWithVariable("WorkshopErrorEnableFailed", "[itemname]", item.Title) + " {" + e.Message + "}";
DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red);
return false;
}
@@ -921,11 +928,11 @@ namespace Barotrauma.Steam
DebugConsole.ThrowError(errorMsg);
new GUIMessageBox(
TextManager.Get("Error"),
- TextManager.Get("WorkshopItemUpdateFailed").Replace("[itemname]", item.Title).Replace("[errormessage]", errorMsg));
+ TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { item.Title, errorMsg }));
}
else
{
- new GUIMessageBox("", TextManager.Get("WorkshopItemUpdated").Replace("[itemname]", item.Title));
+ new GUIMessageBox("", TextManager.GetWithVariable("WorkshopItemUpdated", "[itemname]", item.Title));
itemsUpdated = true;
}
}
diff --git a/Barotrauma/BarotraumaClient/Source/Program.cs b/Barotrauma/BarotraumaClient/Source/Program.cs
index 37646cf3f..b6315f7f1 100644
--- a/Barotrauma/BarotraumaClient/Source/Program.cs
+++ b/Barotrauma/BarotraumaClient/Source/Program.cs
@@ -281,7 +281,7 @@ namespace Barotrauma
{
CrashMessageBox("A crash report (\"" + filePath + "\") was saved in the root folder of the game and sent to the developers.");
GameAnalytics.AddErrorEvent(EGAErrorSeverity.Critical, crashReport);
- GameAnalytics.OnStop();
+ GameAnalytics.OnQuit();
}
else
{
diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs
index 70b981ebe..d3b3cde22 100644
--- a/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs
+++ b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs
@@ -121,8 +121,7 @@ namespace Barotrauma
if (!hasRequiredContentPackages)
{
var msgBox = new GUIMessageBox(TextManager.Get("ContentPackageMismatch"),
- TextManager.Get("ContentPackageMismatchWarning")
- .Replace("[requiredcontentpackages]", string.Join(", ", selectedSub.RequiredContentPackages)),
+ TextManager.GetWithVariable("ContentPackageMismatchWarning", "[requiredcontentpackages]", string.Join(", ", selectedSub.RequiredContentPackages)),
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
msgBox.Buttons[0].OnClicked = msgBox.Close;
@@ -253,7 +252,7 @@ namespace Barotrauma
public void UpdateSubList(IEnumerable submarines)
{
-#if DEBUG
+#if !DEBUG
var subsToShow = submarines.Where(s => !s.HasTag(SubmarineTag.HideInMenus));
#else
var subsToShow = submarines;
diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs b/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs
index e622bc1ca..a393d601a 100644
--- a/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs
+++ b/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs
@@ -636,7 +636,7 @@ namespace Barotrauma
CanBeFocused = false
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), container.RectTransform),
- TextManager.Get("Reward").Replace("[reward]", selectedMission.Reward.ToString()))
+ TextManager.GetWithVariable("Reward", "[reward]", selectedMission.Reward.ToString()))
{
CanBeFocused = false
};
@@ -860,8 +860,7 @@ namespace Barotrauma
public string GetMoney()
{
- return TextManager.Get("PlayerCredits").Replace("[credits]",
- ((GameMain.GameSession == null) ? "0" : string.Format(CultureInfo.InvariantCulture, "{0:N0}", Campaign.Money)));
+ return TextManager.GetWithVariable("PlayerCredits", "[credits]", (GameMain.GameSession == null) ? "0" : string.Format(CultureInfo.InvariantCulture, "{0:N0}", Campaign.Money));
}
private bool SelectCharacter(GUIComponent component, object selection)
@@ -902,7 +901,7 @@ namespace Barotrauma
{
var confirmDialog = new GUIMessageBox(
TextManager.Get("FireWarningHeader"),
- TextManager.Get("FireWarningText").Replace("[charactername]", ((CharacterInfo)obj).Name),
+ TextManager.GetWithVariable("FireWarningText", "[charactername]", ((CharacterInfo)obj).Name),
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
confirmDialog.Buttons[0].UserData = (CharacterInfo)obj;
confirmDialog.Buttons[0].OnClicked = FireCharacter;
diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CreditsPlayer.cs b/Barotrauma/BarotraumaClient/Source/Screens/CreditsPlayer.cs
index 718c7c116..594fac1ca 100644
--- a/Barotrauma/BarotraumaClient/Source/Screens/CreditsPlayer.cs
+++ b/Barotrauma/BarotraumaClient/Source/Screens/CreditsPlayer.cs
@@ -8,19 +8,31 @@ namespace Barotrauma
{
private GUIListBox listBox;
- private readonly float scrollSpeed;
+ private XElement configElement;
+
+ private float scrollSpeed;
+
public CreditsPlayer(RectTransform rectT, string configFile) : base(null, rectT)
{
- var doc = XMLExtensions.TryLoadXml(configFile);
- scrollSpeed = doc.Root.GetAttributeFloat("scrollspeed", 100.0f);
- int spacing = doc.Root.GetAttributeInt("spacing", 0);
+ GameMain.Instance.OnResolutionChanged += () => { ClearChildren(); Load(); };
- listBox = new GUIListBox(new RectTransform(Vector2.One, rectT), style: null)
+ var doc = XMLExtensions.TryLoadXml(configFile);
+ configElement = doc.Root;
+
+ Load();
+ }
+
+ private void Load()
+ {
+ scrollSpeed = configElement.GetAttributeFloat("scrollspeed", 100.0f);
+ int spacing = configElement.GetAttributeInt("spacing", 0);
+
+ listBox = new GUIListBox(new RectTransform(Vector2.One, RectTransform), style: null)
{
Spacing = spacing
};
- foreach (XElement subElement in doc.Root.Elements())
+ foreach (XElement subElement in configElement.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
diff --git a/Barotrauma/BarotraumaClient/Source/Screens/LevelEditorScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/LevelEditorScreen.cs
index 14dd89537..cf8126a46 100644
--- a/Barotrauma/BarotraumaClient/Source/Screens/LevelEditorScreen.cs
+++ b/Barotrauma/BarotraumaClient/Source/Screens/LevelEditorScreen.cs
@@ -277,7 +277,7 @@ namespace Barotrauma
Stretch = true
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.4f), commonnessContainer.RectTransform),
- TextManager.Get("LevelEditorLevelObjCommonness").Replace("[leveltype]", selectedParams.Name), textAlignment: Alignment.Center);
+ TextManager.GetWithVariable("LevelEditorLevelObjCommonness", "[leveltype]", selectedParams.Name), textAlignment: Alignment.Center);
new GUINumberInput(new RectTransform(new Vector2(0.5f, 0.4f), commonnessContainer.RectTransform), GUINumberInput.NumberType.Float)
{
MinValueFloat = 0,
diff --git a/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs
index 6351ab8a4..e4fe091d2 100644
--- a/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs
+++ b/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs
@@ -584,11 +584,32 @@ namespace Barotrauma
private void UpdateTutorialList()
{
var tutorialList = menuTabs[(int)Tab.Tutorials].GetChild();
+
+ int completedTutorials = 0;
+
foreach (GUITextBlock tutorialText in tutorialList.Content.Children)
{
if (((Tutorial)tutorialText.UserData).Completed)
{
- tutorialText.TextColor = Color.LightGreen;
+ completedTutorials++;
+ }
+ }
+
+ for (int i = 0; i < tutorialList.Content.Children.Count(); i++)
+ {
+ if (i < completedTutorials + 1)
+ {
+ (tutorialList.Content.GetChild(i) as GUITextBlock).TextColor = Color.LightGreen;
+#if !DEBUG
+ (tutorialList.Content.GetChild(i) as GUITextBlock).CanBeFocused = true;
+#endif
+ }
+ else
+ {
+ (tutorialList.Content.GetChild(i) as GUITextBlock).TextColor = Color.Gray;
+#if !DEBUG
+ (tutorialList.Content.GetChild(i) as GUITextBlock).CanBeFocused = false;
+#endif
}
}
}
@@ -691,11 +712,8 @@ namespace Barotrauma
" -ownerkey " + ownerKey.ToString();
string filename = "DedicatedServer.exe";
-#if LINUX
+#if LINUX || OSX
filename = "./DedicatedServer";
-#elif OSX
- filename = "mono";
- arguments = "./DedicatedServer.exe " + arguments;
#endif
var processInfo = new ProcessStartInfo
{
diff --git a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs
index 447ca9c7e..3545ce38e 100644
--- a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs
+++ b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs
@@ -1986,16 +1986,17 @@ namespace Barotrauma
string errorMsg = "";
if (sub == null)
{
- errorMsg = TextManager.Get("SubNotFoundError").Replace("[subname]", subName) + " ";
+ errorMsg = TextManager.GetWithVariable("SubNotFoundError", "[subname]", subName) + " ";
}
else if (sub.MD5Hash.Hash == null)
{
- errorMsg = TextManager.Get("SubLoadError").Replace("[subname]", subName) + " ";
+ errorMsg = TextManager.GetWithVariable("SubLoadError", "[subname]", subName) + " ";
if (matchingListSub != null) matchingListSub.GetChild().TextColor = Color.Red;
}
else
{
- errorMsg = TextManager.Get("SubDoesntMatchError").Replace("[subname]", sub.Name).Replace("[myhash]", sub.MD5Hash.ShortHash).Replace("[serverhash]", Md5Hash.GetShortHash(md5Hash)) + " ";
+ errorMsg = TextManager.GetWithVariables("SubDoesntMatchError", new string[3] { "[subname]" , "[myhash]", "[serverhash]" },
+ new string[3] { sub.Name, sub.MD5Hash.ShortHash, Md5Hash.GetShortHash(md5Hash) }) + " ";
}
errorMsg += TextManager.Get("DownloadSubQuestion");
diff --git a/Barotrauma/BarotraumaClient/Source/Screens/ServerListScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/ServerListScreen.cs
index 163e3f9ae..f2ec192dd 100644
--- a/Barotrauma/BarotraumaClient/Source/Screens/ServerListScreen.cs
+++ b/Barotrauma/BarotraumaClient/Source/Screens/ServerListScreen.cs
@@ -120,10 +120,11 @@ namespace Barotrauma
serverList = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f), serverListHolder.RectTransform, Anchor.Center))
{
OnSelected = (btn, obj) => {
- ServerInfo serverInfo = (ServerInfo)obj;
-
- serverInfo.CreatePreviewWindow(serverPreview);
-
+ if (obj is ServerInfo)
+ {
+ ServerInfo serverInfo = (ServerInfo)obj;
+ serverInfo.CreatePreviewWindow(serverPreview);
+ }
return true;
}
};
@@ -218,7 +219,7 @@ namespace Barotrauma
private bool SelectServer(GUIComponent component, object obj)
{
- if (obj == null || waitingForRefresh) { return false; }
+ if (obj == null || waitingForRefresh || (!(obj is ServerInfo))) { return false; }
if (!string.IsNullOrWhiteSpace(clientNameBox.Text))
{
@@ -468,16 +469,15 @@ namespace Barotrauma
{
string toolTip = "";
if (serverInfo.GameVersion != GameMain.Version.ToString())
- toolTip = TextManager.Get("ServerListIncompatibleVersion").Replace("[version]", serverInfo.GameVersion);
+ toolTip = TextManager.GetWithVariable("ServerListIncompatibleVersion", "[version]", serverInfo.GameVersion);
for (int i = 0; i < serverInfo.ContentPackageNames.Count; i++)
{
if (!GameMain.SelectedPackages.Any(cp => cp.MD5hash.Hash == serverInfo.ContentPackageHashes[i]))
{
if (toolTip != "") toolTip += "\n";
- toolTip += TextManager.Get("ServerListIncompatibleContentPackage")
- .Replace("[contentpackage]", serverInfo.ContentPackageNames[i])
- .Replace("[hash]", Md5Hash.GetShortHash(serverInfo.ContentPackageHashes[i]));
+ toolTip += TextManager.GetWithVariables("ServerListIncompatibleContentPackage", new string[2] { "[contentpackage]", "[hash]" },
+ new string[2] { serverInfo.ContentPackageNames[i], Md5Hash.GetShortHash(serverInfo.ContentPackageHashes[i]) });
}
}
@@ -541,7 +541,7 @@ namespace Barotrauma
if (masterServerResponse.ErrorException != null)
{
serverList.ClearChildren();
- new GUIMessageBox(TextManager.Get("MasterServerErrorLabel"), TextManager.Get("MasterServerErrorException").Replace("[error]", masterServerResponse.ErrorException.ToString()));
+ new GUIMessageBox(TextManager.Get("MasterServerErrorLabel"), TextManager.GetWithVariable("MasterServerErrorException", "[error]", masterServerResponse.ErrorException.ToString()));
}
else if (masterServerResponse.StatusCode != System.Net.HttpStatusCode.OK)
{
@@ -551,24 +551,16 @@ namespace Barotrauma
{
case System.Net.HttpStatusCode.NotFound:
new GUIMessageBox(TextManager.Get("MasterServerErrorLabel"),
- TextManager.Get("MasterServerError404")
- .Replace("[masterserverurl]", NetConfig.MasterServerUrl)
- .Replace("[statuscode]", masterServerResponse.StatusCode.ToString())
- .Replace("[statusdescription]", masterServerResponse.StatusDescription));
+ TextManager.GetWithVariable("MasterServerError404", "[masterserverurl]", NetConfig.MasterServerUrl));
break;
case System.Net.HttpStatusCode.ServiceUnavailable:
new GUIMessageBox(TextManager.Get("MasterServerErrorLabel"),
- TextManager.Get("MasterServerErrorUnavailable")
- .Replace("[masterserverurl]", NetConfig.MasterServerUrl)
- .Replace("[statuscode]", masterServerResponse.StatusCode.ToString())
- .Replace("[statusdescription]", masterServerResponse.StatusDescription));
+ TextManager.Get("MasterServerErrorUnavailable"));
break;
default:
new GUIMessageBox(TextManager.Get("MasterServerErrorLabel"),
- TextManager.Get("MasterServerError404")
- .Replace("[masterserverurl]", NetConfig.MasterServerUrl)
- .Replace("[statuscode]", masterServerResponse.StatusCode.ToString())
- .Replace("[statusdescription]", masterServerResponse.StatusDescription));
+ TextManager.GetWithVariables("MasterServerErrorDefault", new string[2] { "[statuscode]", "[statusdescription]" },
+ new string[2] { masterServerResponse.StatusCode.ToString(), masterServerResponse.StatusDescription }));
break;
}
diff --git a/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs
index d7b1219b3..ce5b54c2d 100644
--- a/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs
+++ b/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs
@@ -1,11 +1,11 @@
using Barotrauma.Steam;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
+using RestSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using System.Net;
using System.Text;
using System.Windows.Forms;
@@ -357,20 +357,25 @@ namespace Barotrauma
if (!pendingPreviewImageDownloads.Contains(item.PreviewImageUrl))
{
pendingPreviewImageDownloads.Add(item.PreviewImageUrl);
- using (WebClient client = new WebClient())
+
+ if (File.Exists(imagePreviewPath))
{
- if (File.Exists(imagePreviewPath))
- {
- File.Delete(imagePreviewPath);
- }
- Directory.CreateDirectory(SteamManager.WorkshopItemPreviewImageFolder);
- client.DownloadFileAsync(new Uri(item.PreviewImageUrl), imagePreviewPath);
- CoroutineManager.StartCoroutine(WaitForItemPreviewDownloaded(item, listBox, imagePreviewPath));
- client.DownloadFileCompleted += (sender, args) =>
- {
- pendingPreviewImageDownloads.Remove(item.PreviewImageUrl);
- };
+ File.Delete(imagePreviewPath);
}
+ Directory.CreateDirectory(SteamManager.WorkshopItemPreviewImageFolder);
+
+ Uri baseAddress = new Uri(item.PreviewImageUrl);
+ Uri directory = new Uri(baseAddress, "."); // "." == current dir, like MS-DOS
+ string fileName = Path.GetFileName(baseAddress.LocalPath);
+
+ IRestClient client = new RestClient(directory);
+ var request = new RestRequest(fileName, Method.GET);
+ client.ExecuteAsync(request, response =>
+ {
+ pendingPreviewImageDownloads.Remove(item.PreviewImageUrl);
+ OnPreviewImageDownloaded(response, imagePreviewPath);
+ CoroutineManager.StartCoroutine(WaitForItemPreviewDownloaded(item, listBox, imagePreviewPath));
+ });
}
else
{
@@ -410,14 +415,14 @@ namespace Barotrauma
{
if (SteamManager.UpdateWorkshopItem(item, out string errorMsg))
{
- new GUIMessageBox("", TextManager.Get("WorkshopItemUpdated").Replace("[itemname]", TextManager.EnsureUTF8(item.Title)));
+ new GUIMessageBox("", TextManager.GetWithVariable("WorkshopItemUpdated", "[itemname]", TextManager.EnsureUTF8(item.Title)));
}
else
{
DebugConsole.ThrowError(errorMsg);
new GUIMessageBox(
TextManager.Get("Error"),
- TextManager.Get("WorkshopItemUpdateFailed").Replace("[itemname]", TextManager.EnsureUTF8(item.Title)).Replace("[errormessage]", errorMsg));
+ TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { TextManager.EnsureUTF8(item.Title), errorMsg }));
}
btn.Enabled = false;
btn.Visible = false;
@@ -539,6 +544,24 @@ namespace Barotrauma
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.4f), innerFrame.RectTransform), contentPackage.Name, textAlignment: Alignment.CenterLeft);
}
+ private void OnPreviewImageDownloaded(IRestResponse response, string previewImagePath)
+ {
+ if (response.ResponseStatus == ResponseStatus.Completed)
+ {
+ try
+ {
+ File.WriteAllBytes(previewImagePath, response.RawBytes);
+ }
+ catch (Exception e)
+ {
+ string errorMsg = "Failed to save workshop item preview image to \"" + previewImagePath + "\".";
+ GameAnalyticsManager.AddErrorEventOnce("SteamWorkshopScreen.OnItemPreviewDownloaded:WriteAllBytesFailed" + previewImagePath,
+ GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + e.Message);
+ return;
+ }
+ }
+ }
+
private IEnumerable
-
- ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\GameAnalytics.Mono.dll
+
+ ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.2.1.6\lib\net45\GameAnalytics.Mono.dll
..\..\Libraries\NuGet\MonoGame.Framework.WindowsDX.3.7.1.189\lib\net45\MonoGame.Framework.dll
@@ -132,7 +132,7 @@
- ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\System.Data.SQLite.dll
+ ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.2.1.6\lib\net45\System.Data.SQLite.dll
@@ -306,13 +306,13 @@
-
-
+
+
This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
+
diff --git a/Barotrauma/BarotraumaClient/packages.config b/Barotrauma/BarotraumaClient/packages.config
index d637bffbb..e593ce09a 100644
--- a/Barotrauma/BarotraumaClient/packages.config
+++ b/Barotrauma/BarotraumaClient/packages.config
@@ -1,6 +1,6 @@

-
+
diff --git a/Barotrauma/BarotraumaClient/soft_oal_x64.dll b/Barotrauma/BarotraumaClient/soft_oal_x64.dll
new file mode 100644
index 000000000..f903a0c63
Binary files /dev/null and b/Barotrauma/BarotraumaClient/soft_oal_x64.dll differ
diff --git a/Barotrauma/BarotraumaClient/soft_oal_x86.dll b/Barotrauma/BarotraumaClient/soft_oal_x86.dll
new file mode 100644
index 000000000..5cf7f3a9b
Binary files /dev/null and b/Barotrauma/BarotraumaClient/soft_oal_x86.dll differ
diff --git a/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs
index 160a3625a..34eab06f2 100644
--- a/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs
+++ b/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs
@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("0.9.0.2")]
-[assembly: AssemblyFileVersion("0.9.0.2")]
+[assembly: AssemblyVersion("0.9.0.3")]
+[assembly: AssemblyFileVersion("0.9.0.3")]
diff --git a/Barotrauma/BarotraumaServer/Server.csproj b/Barotrauma/BarotraumaServer/Server.csproj
index 99289cacd..6b66b1b69 100644
--- a/Barotrauma/BarotraumaServer/Server.csproj
+++ b/Barotrauma/BarotraumaServer/Server.csproj
@@ -149,7 +149,13 @@
true
+
+ ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.2.1.6\lib\net45\GameAnalytics.Mono.dll
+
+
+ ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.2.1.6\lib\net45\System.Data.SQLite.dll
+
@@ -163,12 +169,6 @@
..\..\Libraries\NuGet\NLog.4.3.8\lib\net45\NLog.dll
-
- ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\GameAnalytics.Mono.dll
-
-
- ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\System.Data.SQLite.dll
-
..\..\Libraries\NuGet\RestSharp.105.2.3\lib\net45\RestSharp.dll
@@ -293,5 +293,11 @@
-
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
\ No newline at end of file
diff --git a/Barotrauma/BarotraumaServer/Source/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaServer/Source/Characters/CharacterNetworking.cs
index d00a8d7eb..f991738e2 100644
--- a/Barotrauma/BarotraumaServer/Source/Characters/CharacterNetworking.cs
+++ b/Barotrauma/BarotraumaServer/Source/Characters/CharacterNetworking.cs
@@ -354,12 +354,10 @@ namespace Barotrauma
tempBuffer.Write(((HumanoidAnimController)AnimController).Crouching);
}
tempBuffer.Write(attack);
-
- if (aiming)
- {
- Vector2 relativeCursorPos = cursorPosition - AimRefPosition;
- tempBuffer.Write((UInt16)(65535.0 * Math.Atan2(relativeCursorPos.Y, relativeCursorPos.X) / (2.0 * Math.PI)));
- }
+
+ Vector2 relativeCursorPos = cursorPosition - AimRefPosition;
+ tempBuffer.Write((UInt16)(65535.0 * Math.Atan2(relativeCursorPos.Y, relativeCursorPos.X) / (2.0 * Math.PI)));
+
tempBuffer.Write(IsRagdolled || IsUnconscious || Stun > 0.0f || IsDead);
tempBuffer.Write(AnimController.Dir > 0.0f);
diff --git a/Barotrauma/BarotraumaServer/Source/GameMain.cs b/Barotrauma/BarotraumaServer/Source/GameMain.cs
index 6515b87c6..f97944a3e 100644
--- a/Barotrauma/BarotraumaServer/Source/GameMain.cs
+++ b/Barotrauma/BarotraumaServer/Source/GameMain.cs
@@ -128,9 +128,7 @@ namespace Barotrauma
var exePaths = contentPackage.GetFilesOfType(ContentType.ServerExecutable);
if (exePaths.Count() > 0 && AppDomain.CurrentDomain.FriendlyName != exePaths.First())
{
- DebugConsole.ShowQuestionPrompt(TextManager.Get("IncorrectExe")
- .Replace("[selectedpackage]", contentPackage.Name)
- .Replace("[exename]", exePaths.First()),
+ DebugConsole.ShowQuestionPrompt(TextManager.GetWithVariables("IncorrectExe", new string[2] { "[selectedpackage]", "[exename]" }, new string[2] { contentPackage.Name, exePaths.First() }),
(option) =>
{
if (option.ToLower() == "y" || option.ToLower() == "yes")
@@ -298,7 +296,7 @@ namespace Barotrauma
CloseServer();
SteamManager.ShutDown();
- if (GameSettings.SendUserStatistics) GameAnalytics.OnStop();
+ if (GameSettings.SendUserStatistics) GameAnalytics.OnQuit();
}
public static void ResetFrameTime()
diff --git a/Barotrauma/BarotraumaServer/Source/GameSession/GameModes/TraitorManager.cs b/Barotrauma/BarotraumaServer/Source/GameSession/GameModes/TraitorManager.cs
index a96478b67..3c05f2ef0 100644
--- a/Barotrauma/BarotraumaServer/Source/GameSession/GameModes/TraitorManager.cs
+++ b/Barotrauma/BarotraumaServer/Source/GameSession/GameModes/TraitorManager.cs
@@ -16,10 +16,9 @@ namespace Barotrauma
public void Greet(GameServer server, string codeWords, string codeResponse)
{
- string greetingMessage = TextManager.Get("TraitorStartMessage").Replace("[targetname]", TargetCharacter.Name);
- string moreAgentsMessage = TextManager.Get("TraitorMoreAgentsMessage")
- .Replace("[codewords]", codeWords)
- .Replace("[coderesponse]", codeResponse);
+ string greetingMessage = TextManager.GetWithVariable("TraitorStartMessage", "[targetname]", TargetCharacter.Name);
+ string moreAgentsMessage = TextManager.GetWithVariables("TraitorMoreAgentsMessage",
+ new string[2] { "[codewords]", "[coderesponse]" }, new string[2] { codeWords, codeResponse });
var greetingChatMsg = ChatMessage.Create(null, greetingMessage, ChatMessageType.Server, null);
var moreAgentsChatMsg = ChatMessage.Create(null, moreAgentsMessage, ChatMessageType.Server, null);
@@ -38,7 +37,7 @@ namespace Barotrauma
{
var ownerMsg = ChatMessage.Create(
null,//TextManager.Get("NewTraitor"),
- TextManager.Get("TraitorStartMessageServer").Replace("[targetname]", TargetCharacter.Name).Replace("[traitorname]", Character.Name),
+ TextManager.GetWithVariables("TraitorStartMessageServer", new string[2] { "[targetname]", "[traitorname]" }, new string[2] { TargetCharacter.Name, Character.Name }),
ChatMessageType.MessageBox,
null
);
@@ -168,9 +167,8 @@ namespace Barotrauma
}
}
- endMessage += (TextManager.ReplaceGenderPronouns(TextManager.Get(messageTag), traitorCharacter.Info.Gender) + "\n")
- .Replace("[traitorname]", traitorCharacter.Name)
- .Replace("[targetname]", targetCharacter.Name);
+ endMessage += (TextManager.ReplaceGenderPronouns(TextManager.GetWithVariables(messageTag, new string[2] { "[traitorname]", "[targetname]" },
+ new string[2] { traitorCharacter.Name, targetCharacter.Name }), traitorCharacter.Info.Gender) + "\n");
}
return endMessage;
diff --git a/Barotrauma/BarotraumaServer/Source/Items/Inventory.cs b/Barotrauma/BarotraumaServer/Source/Items/Inventory.cs
index 6d13e1aaf..6083c156e 100644
--- a/Barotrauma/BarotraumaServer/Source/Items/Inventory.cs
+++ b/Barotrauma/BarotraumaServer/Source/Items/Inventory.cs
@@ -62,7 +62,16 @@ namespace Barotrauma
if (newItemIDs[i] == 0 || (newItem != Items[i]))
{
- if (Items[i] != null) Items[i].Drop(null);
+ if (Items[i] != null)
+ {
+ Item droppedItem = Items[i];
+ Entity prevOwner = Owner;
+ droppedItem.Drop(null);
+ if (droppedItem.body != null && prevOwner != null)
+ {
+ droppedItem.body.SetTransform(prevOwner.SimPosition, 0.0f);
+ }
+ }
System.Diagnostics.Debug.Assert(Items[i] == null);
}
}
@@ -79,7 +88,10 @@ namespace Barotrauma
var holdable = item.GetComponent();
if (holdable != null && !holdable.CanBeDeattached()) continue;
- if (!item.CanClientAccess(c)) continue;
+ if (!prevItems.Contains(item) && !item.CanClientAccess(c))
+ {
+ continue;
+ }
}
TryPutItem(item, i, true, true, c.Character, false);
for (int j = 0; j < capacity; j++)
diff --git a/Barotrauma/BarotraumaServer/Source/Items/Item.cs b/Barotrauma/BarotraumaServer/Source/Items/Item.cs
index beb831abf..8e29b0a21 100644
--- a/Barotrauma/BarotraumaServer/Source/Items/Item.cs
+++ b/Barotrauma/BarotraumaServer/Source/Items/Item.cs
@@ -193,7 +193,7 @@ namespace Barotrauma
{
if (GameMain.Server == null) return;
- msg.Write(Prefab.Name);
+ msg.Write(Prefab.OriginalName);
msg.Write(Prefab.Identifier);
msg.Write(Description != prefab.Description);
if (Description != prefab.Description)
diff --git a/Barotrauma/BarotraumaServer/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaServer/Source/Networking/GameServer.cs
index b4cdb82cc..1dbc815cb 100644
--- a/Barotrauma/BarotraumaServer/Source/Networking/GameServer.cs
+++ b/Barotrauma/BarotraumaServer/Source/Networking/GameServer.cs
@@ -182,6 +182,10 @@ namespace Barotrauma.Networking
if (SteamManager.USE_STEAM)
{
SteamManager.CreateServer(this, isPublic);
+ if (isPublic)
+ {
+ registeredToMaster = true;
+ }
}
if (isPublic && !GameMain.Config.UseSteamMatchmaking)
{
@@ -411,7 +415,7 @@ namespace Barotrauma.Networking
{
if (endRoundTimer <= 0.0f)
{
- SendChatMessage(TextManager.Get("CrewDeadNoRespawns").Replace("[time]", "60"), ChatMessageType.Server);
+ SendChatMessage(TextManager.GetWithVariable("CrewDeadNoRespawns", "[time]", "60"), ChatMessageType.Server);
}
endRoundTimer += deltaTime;
}
@@ -724,7 +728,7 @@ namespace Barotrauma.Networking
if (matchingSub == null)
{
SendDirectChatMessage(
- TextManager.Get("CampaignStartFailedSubNotFound").Replace("[subname]", subName),
+ TextManager.GetWithVariable("CampaignStartFailedSubNotFound", "[subname]", subName),
connectedClient, ChatMessageType.MessageBox);
}
else
diff --git a/Barotrauma/BarotraumaServer/Source/Networking/RespawnManager.cs b/Barotrauma/BarotraumaServer/Source/Networking/RespawnManager.cs
index 593bec08f..a27e15083 100644
--- a/Barotrauma/BarotraumaServer/Source/Networking/RespawnManager.cs
+++ b/Barotrauma/BarotraumaServer/Source/Networking/RespawnManager.cs
@@ -232,7 +232,7 @@ namespace Barotrauma.Networking
//add the ID card tags they should've gotten when spawning in the shuttle
foreach (Item item in character.Inventory.Items)
{
- if (item == null || item.Prefab.Name != "ID Card") continue;
+ if (item == null || item.Prefab.Identifier != "idcard") continue;
foreach (string s in shuttleSpawnPoints[i].IdCardTags)
{
item.AddTag(s);
diff --git a/Barotrauma/BarotraumaServer/Source/Networking/SteamManager.cs b/Barotrauma/BarotraumaServer/Source/Networking/SteamManager.cs
index 99b9ac68b..1bc7105a6 100644
--- a/Barotrauma/BarotraumaServer/Source/Networking/SteamManager.cs
+++ b/Barotrauma/BarotraumaServer/Source/Networking/SteamManager.cs
@@ -37,7 +37,7 @@ namespace Barotrauma.Steam
public static bool RefreshServerDetails(Networking.GameServer server)
{
- if (instance == null || !instance.isInitialized)
+ if (instance?.server == null || !instance.isInitialized)
{
return false;
}
@@ -48,6 +48,7 @@ namespace Barotrauma.Steam
instance.server.ServerName = server.Name;
instance.server.MaxPlayers = server.ServerSettings.MaxPlayers;
instance.server.Passworded = server.ServerSettings.HasPassword;
+ instance.server.MapName = GameMain.NetLobbyScreen?.SelectedSub?.DisplayName ?? "";
Instance.server.SetKey("message", GameMain.Server.ServerSettings.ServerMessageText);
Instance.server.SetKey("version", GameMain.Version.ToString());
Instance.server.SetKey("contentpackage", string.Join(",", GameMain.Config.SelectedContentPackages.Select(cp => cp.Name)));
diff --git a/Barotrauma/BarotraumaServer/Source/Program.cs b/Barotrauma/BarotraumaServer/Source/Program.cs
index eba307e45..01070636e 100644
--- a/Barotrauma/BarotraumaServer/Source/Program.cs
+++ b/Barotrauma/BarotraumaServer/Source/Program.cs
@@ -35,7 +35,7 @@ namespace Barotrauma
inputThread.Start();
game.Run();
inputThread.Abort(); inputThread.Join();
- if (GameSettings.SendUserStatistics) GameAnalytics.OnStop();
+ if (GameSettings.SendUserStatistics) GameAnalytics.OnQuit();
SteamManager.ShutDown();
#if !DEBUG
}
@@ -105,7 +105,7 @@ namespace Barotrauma
if (GameSettings.SendUserStatistics)
{
GameAnalytics.AddErrorEvent(EGAErrorSeverity.Error, crashReport);
- GameAnalytics.OnStop();
+ GameAnalytics.OnQuit();
Console.Write("A crash report (\"crashreport.log\") was saved in the root folder of the game and sent to the developers.");
}
else
diff --git a/Barotrauma/BarotraumaServer/packages.config b/Barotrauma/BarotraumaServer/packages.config
index 7aedf4bac..6e9fd4d54 100644
--- a/Barotrauma/BarotraumaServer/packages.config
+++ b/Barotrauma/BarotraumaServer/packages.config
@@ -1,6 +1,6 @@

-
+
\ No newline at end of file
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/HumanAIController.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/HumanAIController.cs
index 7b61861e2..2f176e100 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/HumanAIController.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/HumanAIController.cs
@@ -202,22 +202,18 @@ namespace Barotrauma
if (run || speedMultiplier <= 0.0f) targetMovement *= speedMultiplier;
Character.ResetSpeedMultiplier(); // Reset, items will set the value before the next update
Character.AnimController.TargetMovement = targetMovement;
-
if (!NeedsDivingGear(Character.CurrentHull))
{
bool oxygenLow = Character.OxygenAvailable < CharacterHealth.LowOxygenThreshold;
bool highPressure = Character.CurrentHull == null || Character.CurrentHull.LethalPressure > 0 && Character.PressureProtection <= 0;
bool shouldKeepTheGearOn = !ObjectiveManager.IsCurrentObjective();
-
- // Don't allow to drop the diving suit in water or while climbing or if the current path has stairs
- bool removeDivingSuit =
- (oxygenLow && !highPressure) ||
- (!shouldKeepTheGearOn &&
- Character.CurrentHull.WaterPercentage < 1 &&
- !Character.IsClimbing &&
- steeringManager == insideSteering &&
- !PathSteering.InStairs);
-
+ bool removeDivingSuit = oxygenLow && !highPressure;
+ if (!removeDivingSuit)
+ {
+ bool targetHasNoSuit = objectiveManager.CurrentOrder is AIObjectiveGoTo gtObj && gtObj.mimic && !HasDivingSuit(gtObj.Target as Character);
+ bool canDropTheSuit = Character.CurrentHull.WaterPercentage < 1 && !Character.IsClimbing && steeringManager == insideSteering && !PathSteering.InStairs;
+ removeDivingSuit = (!shouldKeepTheGearOn || targetHasNoSuit) && canDropTheSuit;
+ }
if (removeDivingSuit)
{
var divingSuit = Character.Inventory.FindItemByIdentifier("divingsuit") ?? Character.Inventory.FindItemByTag("divingsuit");
@@ -227,7 +223,8 @@ namespace Barotrauma
divingSuit.Drop(Character);
}
}
- bool takeMaskOff = oxygenLow || (!shouldKeepTheGearOn && Character.CurrentHull.WaterPercentage < 20);
+ bool targetHasNoMask = objectiveManager.CurrentOrder is AIObjectiveGoTo gotoObjective && gotoObjective.mimic && !HasDivingMask(gotoObjective.Target as Character);
+ bool takeMaskOff = oxygenLow || (!shouldKeepTheGearOn && Character.CurrentHull.WaterPercentage < 20) || targetHasNoMask;
if (takeMaskOff)
{
var mask = Character.Inventory.FindItemByIdentifier("divingmask");
@@ -321,11 +318,13 @@ namespace Barotrauma
if (c.CurrentHull != hull) { continue; }
if (AIObjectiveRescueAll.IsValidTarget(c, Character))
{
- AddTargets(c, Character);
- if (newOrder == null)
+ if (AddTargets(c, Character))
{
- var orderPrefab = Order.PrefabList.Find(o => o.AITag == "requestfirstaid");
- newOrder = new Order(orderPrefab, c.CurrentHull, null, orderGiver: Character);
+ if (newOrder == null)
+ {
+ var orderPrefab = Order.PrefabList.Find(o => o.AITag == "requestfirstaid");
+ newOrder = new Order(orderPrefab, c.CurrentHull, null, orderGiver: Character);
+ }
}
}
}
@@ -334,7 +333,7 @@ namespace Barotrauma
if (AIObjectiveFixLeaks.IsValidTarget(gap, Character))
{
AddTargets(Character, gap);
- if (newOrder == null)
+ if (newOrder == null && !gap.IsRoomToRoom)
{
var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportbreach");
newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
@@ -382,8 +381,8 @@ namespace Barotrauma
}
if (Character.PressureTimer > 50.0f && Character.CurrentHull != null)
- {
- Character.Speak(TextManager.Get("DialogPressure").Replace("[roomname]", Character.CurrentHull.DisplayName), null, 0, "pressure", 30.0f);
+ {
+ Character.Speak(TextManager.GetWithVariable("DialogPressure", "[roomname]", Character.CurrentHull.DisplayName, true), null, 0, "pressure", 30.0f);
}
}
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveExtinguishFire.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveExtinguishFire.cs
index d60f7926b..b2bccbe4d 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveExtinguishFire.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveExtinguishFire.cs
@@ -110,8 +110,8 @@ namespace Barotrauma
move = false;
extinguisher.Use(deltaTime, character);
if (!targetHull.FireSources.Contains(fs))
- {
- character.Speak(TextManager.Get("DialogPutOutFire").Replace("[roomname]", targetHull.Name), null, 0, "putoutfire", 10.0f);
+ {
+ character.Speak(TextManager.GetWithVariable("DialogPutOutFire", "[roomname]", targetHull.Name, true), null, 0, "putoutfire", 10.0f);
}
}
}
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFindSafety.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFindSafety.cs
index 851a0cd01..3cdc8780b 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFindSafety.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFindSafety.cs
@@ -122,9 +122,8 @@ namespace Barotrauma
goToObjective = null;
}
TryAddSubObjective(ref goToObjective,
- constructor: () => new AIObjectiveGoTo(currentSafeHull, character, objectiveManager, getDivingGearIfNeeded: false)
+ constructor: () => new AIObjectiveGoTo(currentSafeHull, character, objectiveManager, getDivingGearIfNeeded: true)
{
- // If we need diving gear, we should already have it, if possible.
AllowGoingOutside = HumanAIController.HasDivingSuit(character)
},
onAbandon: () => unreachable.Add(goToObjective.Target as Hull));
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveLoop.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveLoop.cs
index 1d0816dca..82a276ec0 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveLoop.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveLoop.cs
@@ -21,6 +21,7 @@ namespace Barotrauma
public bool AddTarget(T target)
{
+ if (character.IsDead) { return false; }
if (ReportedTargets.Contains(target))
{
return false;
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveManager.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveManager.cs
index 19a21b7ff..ec1e63d2c 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveManager.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveManager.cs
@@ -234,6 +234,7 @@ namespace Barotrauma
switch (order.AITag.ToLowerInvariant())
{
case "follow":
+ if (orderGiver == null) { return null; }
newObjective = new AIObjectiveGoTo(orderGiver, character, this, repeat: true, priorityModifier: priorityModifier)
{
CloseEnough = 150,
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveOperateItem.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveOperateItem.cs
index d77c798c3..3da532975 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveOperateItem.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveOperateItem.cs
@@ -60,7 +60,7 @@ namespace Barotrauma
ItemComponent target = useController ? controller : component;
if (useController && controller == null)
{
- character.Speak(TextManager.Get("DialogCantFindController").Replace("[item]", component.Item.Name), null, 2.0f, "cantfindcontroller", 30.0f);
+ character.Speak(TextManager.GetWithVariable("DialogCantFindController", "[item]", component.Item.Name, true), null, 2.0f, "cantfindcontroller", 30.0f);
abandon = true;
return;
}
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRepairItem.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRepairItem.cs
index a3574b29d..8ddb26d26 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRepairItem.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRepairItem.cs
@@ -44,8 +44,8 @@ namespace Barotrauma
{
bool isCompleted = Item.IsFullCondition;
if (isCompleted)
- {
- character?.Speak(TextManager.Get("DialogItemRepaired").Replace("[itemname]", Item.Name), null, 0.0f, "itemrepaired", 10.0f);
+ {
+ character?.Speak(TextManager.GetWithVariable("DialogItemRepaired", "[itemname]", Item.Name, true), null, 0.0f, "itemrepaired", 10.0f);
}
return isCompleted;
}
@@ -140,7 +140,7 @@ namespace Barotrauma
{
// If the current condition is less than the previous condition, we can't complete the task, so let's abandon it. The item is probably deteriorating at a greater speed than we can repair it.
abandon = true;
- character?.Speak(TextManager.Get("DialogCannotRepair").Replace("[itemname]", Item.Name), null, 0.0f, "cannotrepair", 10.0f);
+ character?.Speak(TextManager.GetWithVariable("DialogCannotRepair", "[itemname]", Item.Name, true), null, 0.0f, "cannotrepair", 10.0f);
}
}
repairable.CurrentFixer = abandon && repairable.CurrentFixer == character ? null : character;
@@ -161,8 +161,8 @@ namespace Barotrauma
objective.CloseEnough = repairTool.Range * 0.75f;
}
return objective;
- },
- onAbandon: () => character.Speak(TextManager.Get("DialogCannotRepair").Replace("[itemname]", Item.Name), null, 0.0f, "cannotrepair", 10.0f));
+ },
+ onAbandon: () => character.Speak(TextManager.GetWithVariable("DialogCannotRepair", "[itemname]", Item.Name, true), null, 0.0f, "cannotrepair", 10.0f));
}
}
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescue.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescue.cs
index 65c43a1d9..3eff46f3a 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescue.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescue.cs
@@ -57,11 +57,10 @@ namespace Barotrauma
if (targetCharacter.IsUnconscious && HumanAIController.GetHullSafety(targetCharacter.CurrentHull, targetCharacter) < HumanAIController.HULL_SAFETY_THRESHOLD)
{
if (character.SelectedCharacter != targetCharacter)
- {
- character.Speak(TextManager.Get("DialogFoundUnconsciousTarget")
- .Replace("[targetname]", targetCharacter.Name).Replace("[roomname]", targetCharacter.CurrentHull.DisplayName),
- null, 1.0f,
- "foundunconscioustarget" + targetCharacter.Name, 60.0f);
+ {
+ character.Speak(TextManager.GetWithVariables("DialogFoundUnconsciousTarget", new string[2] { "[targetname]", "[roomname]" },
+ new string[2] { targetCharacter.Name, targetCharacter.CurrentHull.DisplayName }, new bool[2] { false, true }),
+ null, 1.0f, "foundunconscioustarget" + targetCharacter.Name, 60.0f);
// Go to the target and select it
if (!character.CanInteractWith(targetCharacter))
@@ -113,11 +112,10 @@ namespace Barotrauma
{
// We can start applying treatment
if (character.SelectedCharacter != targetCharacter)
- {
- character.Speak(TextManager.Get("DialogFoundWoundedTarget")
- .Replace("[targetname]", targetCharacter.Name).Replace("[roomname]", targetCharacter.CurrentHull.DisplayName),
- null, 1.0f,
- "foundwoundedtarget" + targetCharacter.Name, 60.0f);
+ {
+ character.Speak(TextManager.GetWithVariables("DialogFoundWoundedTarget", new string[2] { "[targetname]", "[roomname]" },
+ new string[2] { targetCharacter.Name, targetCharacter.CurrentHull.DisplayName }, new bool[2] { false, true }),
+ null, 1.0f, "foundwoundedtarget" + targetCharacter.Name, 60.0f);
character.SelectCharacter(targetCharacter);
}
@@ -191,9 +189,10 @@ namespace Barotrauma
{
itemListStr = string.Join(" or ", string.Join(", ", itemNameList.Take(itemNameList.Count - 1)), itemNameList.Last());
}
- character.Speak(TextManager.Get("DialogListRequiredTreatments")
- .Replace("[targetname]", targetCharacter.Name)
- .Replace("[treatmentlist]", itemListStr),
+
+
+ character.Speak(TextManager.GetWithVariables("DialogListRequiredTreatments", new string[2] { "[targetname]", "[treatmentlist]" },
+ new string[2] { targetCharacter.Name, itemListStr }, new bool[2] { false, true }),
null, 2.0f, "listrequiredtreatments" + targetCharacter.Name, 60.0f);
}
character.DeselectCharacter();
@@ -235,8 +234,8 @@ namespace Barotrauma
bool isCompleted = targetCharacter.Bleeding <= 0 && targetCharacter.Vitality / targetCharacter.MaxVitality > AIObjectiveRescueAll.GetVitalityThreshold(objectiveManager);
if (isCompleted)
- {
- character.Speak(TextManager.Get("DialogTargetHealed").Replace("[targetname]", targetCharacter.Name),
+ {
+ character.Speak(TextManager.GetWithVariable("DialogTargetHealed", "[targetname]", targetCharacter.Name),
null, 1.0f, "targethealed" + targetCharacter.Name, 60.0f);
}
return isCompleted || targetCharacter.IsDead;
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescueAll.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescueAll.cs
index 11d22f454..e520495bf 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescueAll.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescueAll.cs
@@ -10,7 +10,17 @@ namespace Barotrauma
private const float vitalityThreshold = 0.8f;
private const float vitalityThresholdForOrders = 0.95f;
- public static float GetVitalityThreshold(AIObjectiveManager manager) => manager.CurrentOrder is AIObjectiveRescueAll ? vitalityThresholdForOrders : vitalityThreshold;
+ public static float GetVitalityThreshold(AIObjectiveManager manager)
+ {
+ if (manager == null)
+ {
+ return vitalityThreshold;
+ }
+ else
+ {
+ return manager.CurrentOrder is AIObjectiveRescueAll ? vitalityThresholdForOrders : vitalityThreshold;
+ }
+ }
public AIObjectiveRescueAll(Character character, AIObjectiveManager objectiveManager, float priorityModifier = 1)
: base(character, objectiveManager, priorityModifier) { }
@@ -35,8 +45,14 @@ namespace Barotrauma
{
if (target == null || target.IsDead || target.Removed) { return false; }
if (!HumanAIController.IsFriendly(character, target)) { return false; }
- if (!(character.AIController is HumanAIController humanAI)) { return false; }
- if (target.Bleeding < 1 && target.Vitality / target.MaxVitality > GetVitalityThreshold(humanAI.ObjectiveManager)) { return false; }
+ if (character.AIController is HumanAIController humanAI)
+ {
+ if (target.Bleeding < 1 && target.Vitality / target.MaxVitality > GetVitalityThreshold(humanAI.ObjectiveManager)) { return false; }
+ }
+ else
+ {
+ if (target.Bleeding < 1 && target.Vitality / target.MaxVitality > vitalityThreshold) { return false; }
+ }
if (target.Submarine == null) { return false; }
if (target.Submarine.TeamID != character.Submarine.TeamID) { return false; }
if (target.CurrentHull == null) { return false; }
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Order.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Order.cs
index 6391147f5..202310ced 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Order.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Order.cs
@@ -171,12 +171,12 @@ namespace Barotrauma
string messageTag = (givingOrderToSelf && !TargetAllCharacters ? "OrderDialogSelf." : "OrderDialog.") + AITag;
if (!string.IsNullOrEmpty(orderOption)) messageTag += "." + orderOption;
- string msg = TextManager.Get(messageTag, true);
+ if (targetCharacterName == null) targetCharacterName = "";
+ if (targetRoomName == null) targetRoomName = "";
+ string msg = TextManager.GetWithVariables(messageTag, new string[2] { "[name]", "[roomname]" }, new string[2] { targetCharacterName, targetRoomName }, new bool[2] { false, true });
if (msg == null) return "";
- if (targetCharacterName == null) targetCharacterName = "";
- if (targetRoomName == null) targetRoomName = "";
- return msg.Replace("[name]", targetCharacterName).Replace("[roomname]", targetRoomName);
+ return msg;
}
}
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Params/Ragdoll/RagdollParams.cs b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Params/Ragdoll/RagdollParams.cs
index 0ca685008..cec8bfc44 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Params/Ragdoll/RagdollParams.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Params/Ragdoll/RagdollParams.cs
@@ -36,7 +36,8 @@ namespace Barotrauma
[Serialize(1.0f, true), Editable(MIN_SCALE, MAX_SCALE, DecimalCount = 3)]
public float JointScale { get; set; }
- [Serialize(1f, true), Editable(DecimalCount = 2)]
+ // Don't show in the editor, because shouldn't be edited in runtime. Requires that the limb scale and the collider sizes are adjusted. TODO: automatize.
+ [Serialize(1f, false)]
public float TextureScale { get; set; }
[Serialize(45f, true), Editable(0f, 1000f)]
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs
index 46ff1d502..52d84e829 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs
@@ -17,6 +17,12 @@ namespace Barotrauma
{
public abstract RagdollParams RagdollParams { get; protected set; }
+ const float ImpactDamageMultiplayer = 10.0f;
+ ///
+ /// Maximum damage per impact (0.1 = 10% of the character's maximum health)
+ ///
+ const float MaxImpactDamage = 0.1f;
+
private static List list = new List();
protected Hull currentHull;
@@ -688,8 +694,10 @@ namespace Barotrauma
Vector2 impactPos = ConvertUnits.ToDisplayUnits(points[0]);
if (character.Submarine != null) impactPos += character.Submarine.Position;
+ float impactDamage = Math.Min((impact - ImpactTolerance) * ImpactDamageMultiplayer, character.MaxVitality * MaxImpactDamage);
+
character.LastDamageSource = null;
- character.AddDamage(impactPos, new List() { AfflictionPrefab.InternalDamage.Instantiate((impact - ImpactTolerance) * 10.0f) }, 0.0f, true);
+ character.AddDamage(impactPos, new List() { AfflictionPrefab.InternalDamage.Instantiate(impactDamage) }, 0.0f, true);
strongestImpact = Math.Max(strongestImpact, impact - ImpactTolerance);
character.ApplyStatusEffects(ActionType.OnImpact, 1.0f);
//briefly disable impact damage
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Health/Afflictions/AfflictionHusk.cs b/Barotrauma/BarotraumaShared/Source/Characters/Health/Afflictions/AfflictionHusk.cs
index db7d465b2..234203834 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/Health/Afflictions/AfflictionHusk.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/Health/Afflictions/AfflictionHusk.cs
@@ -217,7 +217,16 @@ namespace Barotrauma
limb.body.AngularVelocity = matchingLimb.body.AngularVelocity;
}
}
- for (int i = 0; i < character.Inventory.Items.Length; i++)
+
+ if (character.Inventory.Items.Length != husk.Inventory.Items.Length)
+ {
+ string errorMsg = "Failed to move items from a human's inventory into a humanhusk's inventory (inventory sizes don't match)";
+ DebugConsole.ThrowError(errorMsg);
+ GameAnalyticsManager.AddErrorEventOnce("AfflictionHusk.CreateAIHusk:InventoryMismatch", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
+ yield return CoroutineStatus.Success;
+ }
+
+ for (int i = 0; i < character.Inventory.Items.Length && i < husk.Inventory.Items.Length; i++)
{
if (character.Inventory.Items[i] == null) continue;
husk.Inventory.TryPutItem(character.Inventory.Items[i], i, true, false, null);
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaShared/Source/Characters/Health/CharacterHealth.cs
index 4f5769f34..6425a776e 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/Health/CharacterHealth.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/Health/CharacterHealth.cs
@@ -232,13 +232,13 @@ namespace Barotrauma
}
private LimbHealth GetMatchingLimbHealth(Limb limb) => limbHealths[limb.HealthIndex];
- private LimbHealth GetMathingLimbHealth(Affliction affliction) => GetMatchingLimbHealth(Character.AnimController.GetLimb(affliction.Prefab.IndicatorLimb));
+ private LimbHealth GetMatchingLimbHealth(Affliction affliction) => GetMatchingLimbHealth(Character.AnimController.GetLimb(affliction.Prefab.IndicatorLimb));
///
/// Returns the limb afflictions and non-limbspecific afflictions that are set to be displayed on this limb.
///
private IEnumerable GetMatchingAfflictions(LimbHealth limb, Func predicate)
- => limb.Afflictions.Where(predicate).Union(afflictions.Where(a => predicate(a) && GetMathingLimbHealth(a) == limb));
+ => limb.Afflictions.Where(predicate).Union(afflictions.Where(a => predicate(a) && GetMatchingLimbHealth(a) == limb));
public Affliction GetAffliction(string afflictionType, bool allowLimbAfflictions = true)
{
diff --git a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs
index 39d8abd87..4e0db2462 100644
--- a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs
+++ b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs
@@ -988,18 +988,6 @@ namespace Barotrauma
#endif
NewMessage("Set packet duplication to " + (int)(duplicates * 100) + "%.", Color.White);
}));
-
- commands.Add(new Command("money", "", args =>
- {
- if (args.Length == 0) { return; }
- if (GameMain.GameSession.GameMode is CampaignMode campaign)
- {
- if (int.TryParse(args[0], out int money))
- {
- campaign.Money += money;
- }
- }
- }, isCheat: true));
#endif
//"dummy commands" that only exist so that the server can give clients permissions to use them
diff --git a/Barotrauma/BarotraumaShared/Source/Events/Missions/CombatMission.cs b/Barotrauma/BarotraumaShared/Source/Events/Missions/CombatMission.cs
index 550face51..09abef077 100644
--- a/Barotrauma/BarotraumaShared/Source/Events/Missions/CombatMission.cs
+++ b/Barotrauma/BarotraumaShared/Source/Events/Missions/CombatMission.cs
@@ -36,7 +36,10 @@ namespace Barotrauma
{
get
{
- if (Winner == Character.TeamType.None) { return ""; }
+ if (Winner == Character.TeamType.None || string.IsNullOrEmpty(base.SuccessMessage)) { return ""; }
+
+ //disable success message for now if it hasn't been translated
+ if (!TextManager.ContainsTag("MissionSuccess." + Prefab.Identifier)) { return ""; }
var loser = Winner == Character.TeamType.Team1 ?
Character.TeamType.Team2 :
diff --git a/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs b/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs
index 54bda73de..16b069e6e 100644
--- a/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs
+++ b/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs
@@ -16,9 +16,18 @@ namespace Barotrauma
public static void Init()
{
#if DEBUG
- GameAnalytics.SetEnabledInfoLog(true);
+ try
+ {
+ GameAnalytics.SetEnabledInfoLog(true);
+ }
+ catch (Exception e)
+ {
+ DebugConsole.ThrowError("Initializing GameAnalytics failed. Disabling user statistics...", e);
+ GameSettings.SendUserStatistics = false;
+ return;
+ }
#endif
-
+
string exePath = Assembly.GetEntryAssembly().Location;
string exeName = null;
Md5Hash exeHash = null;
diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/CargoManager.cs b/Barotrauma/BarotraumaShared/Source/GameSession/CargoManager.cs
index 271dd6dc1..03c92e52e 100644
--- a/Barotrauma/BarotraumaShared/Source/GameSession/CargoManager.cs
+++ b/Barotrauma/BarotraumaShared/Source/GameSession/CargoManager.cs
@@ -108,7 +108,7 @@ namespace Barotrauma
}
#if CLIENT
- new GUIMessageBox("", TextManager.Get("CargoSpawnNotification").Replace("[roomname]", cargoRoom.DisplayName));
+ new GUIMessageBox("", TextManager.GetWithVariable("CargoSpawnNotification", "[roomname]", cargoRoom.DisplayName, true));
#endif
Dictionary availableContainers = new Dictionary();
diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/CampaignMode.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/CampaignMode.cs
index d0cd28725..3ddd11311 100644
--- a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/CampaignMode.cs
+++ b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/CampaignMode.cs
@@ -193,7 +193,7 @@ namespace Barotrauma
character.TeamID = Character.TeamType.FriendlyNPC;
character.SetCustomInteract(
WatchmanInteract,
- hudText: TextManager.Get("TalkHint").Replace("[key]", GameMain.Config.KeyBind(InputType.Select).ToString()));
+ hudText: TextManager.GetWithVariable("TalkHint", "[key]", GameMain.Config.KeyBind(InputType.Select).ToString()));
}
protected abstract void WatchmanInteract(Character watchman, Character interactor);
diff --git a/Barotrauma/BarotraumaShared/Source/GameSettings.cs b/Barotrauma/BarotraumaShared/Source/GameSettings.cs
index 3227f1413..26313251a 100644
--- a/Barotrauma/BarotraumaShared/Source/GameSettings.cs
+++ b/Barotrauma/BarotraumaShared/Source/GameSettings.cs
@@ -206,7 +206,7 @@ namespace Barotrauma
{
voiceChatVolume = MathHelper.Clamp(value, 0.0f, 1.0f);
#if CLIENT
- GameMain.SoundManager?.SetCategoryGainMultiplier("voip", voiceChatVolume * 5.0f);
+ GameMain.SoundManager?.SetCategoryGainMultiplier("voip", voiceChatVolume * 20.0f);
#endif
}
}
@@ -569,14 +569,12 @@ namespace Barotrauma
//to make sure the package that contains text files has been loaded before we attempt to use TextManager
foreach (string missingPackagePath in missingPackagePaths)
{
- DebugConsole.ThrowError(TextManager.Get("ContentPackageNotFound").Replace("[packagepath]", missingPackagePath));
+ DebugConsole.ThrowError(TextManager.GetWithVariable("ContentPackageNotFound", "[packagepath]", missingPackagePath));
}
foreach (ContentPackage incompatiblePackage in incompatiblePackages)
{
- DebugConsole.ThrowError(TextManager.Get(incompatiblePackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage")
- .Replace("[packagename]", incompatiblePackage.Name)
- .Replace("[packageversion]", incompatiblePackage.GameVersion.ToString())
- .Replace("[gameversion]", GameMain.Version.ToString()));
+ DebugConsole.ThrowError(TextManager.GetWithVariables(incompatiblePackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage",
+ new string[3] { "[packagename]", "[packageversion]", "[gameversion]" }, new string[3] { incompatiblePackage.Name, incompatiblePackage.GameVersion.ToString(), GameMain.Version.ToString() }));
}
foreach (ContentPackage contentPackage in SelectedContentPackages)
{
@@ -955,14 +953,12 @@ namespace Barotrauma
//to make sure the package that contains text files has been loaded before we attempt to use TextManager
foreach (string missingPackagePath in missingPackagePaths)
{
- DebugConsole.ThrowError(TextManager.Get("ContentPackageNotFound").Replace("[packagepath]", missingPackagePath));
+ DebugConsole.ThrowError(TextManager.GetWithVariable("ContentPackageNotFound", "[packagepath]", missingPackagePath));
}
foreach (ContentPackage incompatiblePackage in incompatiblePackages)
{
- DebugConsole.ThrowError(TextManager.Get(incompatiblePackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage")
- .Replace("[packagename]", incompatiblePackage.Name)
- .Replace("[packageversion]", incompatiblePackage.GameVersion.ToString())
- .Replace("[gameversion]", GameMain.Version.ToString()));
+ DebugConsole.ThrowError(TextManager.GetWithVariables(incompatiblePackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage",
+ new string[3] { "[packagename]", "[packageversion]", "[gameversion]" }, new string[3] { incompatiblePackage.Name, incompatiblePackage.GameVersion.ToString(), GameMain.Version.ToString() }));
}
}
diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RepairTool.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RepairTool.cs
index 0b70d6e8a..681f74534 100644
--- a/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RepairTool.cs
+++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RepairTool.cs
@@ -40,6 +40,9 @@ namespace Barotrauma.Items.Components
[Serialize(false, false)]
public bool RepairThroughWalls { get; set; }
+ [Serialize(false, false)]
+ public bool RepairMultiple { get; set; }
+
public Vector2 TransformedBarrelPos
{
get
@@ -158,12 +161,22 @@ namespace Barotrauma.Items.Components
private void Repair(Vector2 rayStart, Vector2 rayEnd, float deltaTime, Character user, float degreeOfSuccess, List ignoredBodies)
{
var collisionCategories = Physics.CollisionWall | Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionLevel | Physics.CollisionRepair;
- if (RepairThroughWalls)
+ if (RepairMultiple)
{
var bodies = Submarine.PickBodies(rayStart, rayEnd, ignoredBodies, collisionCategories, ignoreSensors: false, allowInsideFixture: true);
+ Type lastHitType = null;
foreach (Body body in bodies)
{
- FixBody(user, deltaTime, degreeOfSuccess, body);
+ Type bodyType = body.UserData?.GetType();
+ if (!RepairThroughWalls && bodyType != null && bodyType != lastHitType)
+ {
+ //stop the ray if it already hit a door/wall and is now about to hit some other type of entity
+ if (lastHitType == typeof(Item) || lastHitType == typeof(Structure)) { break; }
+ }
+ if (FixBody(user, deltaTime, degreeOfSuccess, body))
+ {
+ if (bodyType != null) { lastHitType = bodyType; }
+ }
}
}
else
@@ -202,19 +215,19 @@ namespace Barotrauma.Items.Components
}
}
- private void FixBody(Character user, float deltaTime, float degreeOfSuccess, Body targetBody)
+ private bool FixBody(Character user, float deltaTime, float degreeOfSuccess, Body targetBody)
{
- if (targetBody?.UserData == null) { return; }
+ if (targetBody?.UserData == null) { return false; }
pickedPosition = Submarine.LastPickedPosition;
if (targetBody.UserData is Structure targetStructure)
{
- if (!fixableEntities.Contains("structure") && !fixableEntities.Contains(targetStructure.Prefab.Identifier)) return;
- if (targetStructure.IsPlatform) return;
+ if (!fixableEntities.Contains("structure") && !fixableEntities.Contains(targetStructure.Prefab.Identifier)) { return false; }
+ if (targetStructure.IsPlatform) { return false; }
int sectionIndex = targetStructure.FindSectionIndex(ConvertUnits.ToDisplayUnits(pickedPosition));
- if (sectionIndex < 0) return;
+ if (sectionIndex < 0) { return false; }
FixStructureProjSpecific(user, deltaTime, targetStructure, sectionIndex);
targetStructure.AddDamage(sectionIndex, -StructureFixAmount * degreeOfSuccess, user);
@@ -232,18 +245,21 @@ namespace Barotrauma.Items.Components
targetStructure.AddDamage(sectionIndex + i, -StructureFixAmount * degreeOfSuccess);
}
}
+ return true;
}
else if (targetBody.UserData is Character targetCharacter)
{
targetCharacter.LastDamageSource = item;
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new List() { targetCharacter });
FixCharacterProjSpecific(user, deltaTime, targetCharacter);
+ return true;
}
else if (targetBody.UserData is Limb targetLimb)
{
targetLimb.character.LastDamageSource = item;
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new List() { targetLimb.character, targetLimb });
FixCharacterProjSpecific(user, deltaTime, targetLimb.character);
+ return true;
}
else if (targetBody.UserData is Item targetItem)
{
@@ -268,7 +284,9 @@ namespace Barotrauma.Items.Components
#endif
}
FixItemProjSpecific(user, deltaTime, targetItem, prevCondition);
+ return true;
}
+ return false;
}
partial void FixStructureProjSpecific(Character user, float deltaTime, Structure targetStructure, int sectionIndex);
@@ -378,11 +396,12 @@ namespace Barotrauma.Items.Components
sinTime = 0;
if (!leak.FlowTargetHull.ConnectedGaps.Any(g => !g.IsRoomToRoom && g.Open > 0.0f))
{
- character.Speak(TextManager.Get("DialogLeaksFixed").Replace("[roomname]", leak.FlowTargetHull.DisplayName), null, 0.0f, "leaksfixed", 10.0f);
+
+ character.Speak(TextManager.GetWithVariable("DialogLeaksFixed", "[roomname]", leak.FlowTargetHull.DisplayName, true), null, 0.0f, "leaksfixed", 10.0f);
}
else
{
- character.Speak(TextManager.Get("DialogLeakFixed").Replace("[roomname]", leak.FlowTargetHull.DisplayName), null, 0.0f, "leakfixed", 10.0f);
+ character.Speak(TextManager.GetWithVariable("DialogLeakFixed", "[roomname]", leak.FlowTargetHull.DisplayName, true), null, 0.0f, "leakfixed", 10.0f);
}
}
diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Sonar.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Sonar.cs
index c18e1ad02..539ba0aac 100644
--- a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Sonar.cs
+++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Sonar.cs
@@ -219,8 +219,10 @@ namespace Barotrauma.Items.Components
{
dialogTag = "DialogSonarTargetLarge";
}
- character.Speak(TextManager.Get(dialogTag).Replace("[direction]", targetGroup.Key).Replace("[count]", targetGroup.Value.Count.ToString()),
- null, 0, "sonartarget" + targetGroup.Value[0].ID, 30);
+
+ character.Speak(TextManager.GetWithVariables(dialogTag, new string[2] { "[direction]", "[count]" },
+ new string[2] { targetGroup.Key.ToString(), targetGroup.Value.Count.ToString() },
+ new bool[2] { true, false }), null, 0, "sonartarget" + targetGroup.Value[0].ID, 30);
//prevent the character from reporting other targets in the group
for (int i = 1; i < targetGroup.Value.Count; i++)
@@ -239,7 +241,7 @@ namespace Barotrauma.Items.Components
int clockDir = (int)Math.Round((angle / MathHelper.TwoPi) * 12);
if (clockDir == 0) clockDir = 12;
- return TextManager.Get("roomname.subdiroclock").Replace("[dir]", clockDir.ToString());
+ return TextManager.GetWithVariable("roomname.subdiroclock", "[dir]", clockDir.ToString());
}
private Vector2 GetTransducerPos()
diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Power/PowerContainer.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Power/PowerContainer.cs
index f411cf341..f74e81242 100644
--- a/Barotrauma/BarotraumaShared/Source/Items/Components/Power/PowerContainer.cs
+++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Power/PowerContainer.cs
@@ -244,9 +244,10 @@ namespace Barotrauma.Items.Components
#if CLIENT
rechargeSpeedSlider.BarScroll = RechargeSpeed / Math.Max(maxRechargeSpeed, 1.0f);
#endif
- character.Speak(TextManager.Get("DialogChargeBatteries")
- .Replace("[itemname]", item.Name)
- .Replace("[rate]", ((int)(rechargeSpeed / maxRechargeSpeed * 100.0f)).ToString()), null, 1.0f, "chargebattery", 10.0f);
+
+ character.Speak(TextManager.GetWithVariables("DialogChargeBatteries", new string[2] { "[itemname]", "[rate]" },
+ new string[2] { item.Name, ((int)(rechargeSpeed / maxRechargeSpeed * 100.0f)).ToString() },
+ new bool[2] { true, false }), null, 1.0f, "chargebattery", 10.0f);
}
}
else
@@ -260,9 +261,9 @@ namespace Barotrauma.Items.Components
#if CLIENT
rechargeSpeedSlider.BarScroll = RechargeSpeed / Math.Max(maxRechargeSpeed, 1.0f);
#endif
- character.Speak(TextManager.Get("DialogStopChargingBatteries")
- .Replace("[itemname]", item.Name)
- .Replace("[rate]", ((int)(rechargeSpeed / maxRechargeSpeed * 100.0f)).ToString()), null, 1.0f, "chargebattery", 10.0f);
+ character.Speak(TextManager.GetWithVariables("DialogStopChargingBatteries", new string[2] { "[itemname]", "[rate]" },
+ new string[2] { item.Name, ((int)(rechargeSpeed / maxRechargeSpeed * 100.0f)).ToString() },
+ new bool[2] { true, false }), null, 1.0f, "chargebattery", 10.0f);
}
}
diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs
index 596e50d1e..f821873bc 100644
--- a/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs
+++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs
@@ -276,12 +276,34 @@ namespace Barotrauma.Items.Components
private List DoRayCast(Vector2 rayStart, Vector2 rayEnd)
{
List hits = new List();
+
+ Vector2 dir = rayEnd - rayStart;
+ dir = dir.LengthSquared() < 0.00001f ? Vector2.UnitY : Vector2.Normalize(dir);
+
+ //do an AABB query first to see if the start of the ray is inside a fixture
+ var aabb = new FarseerPhysics.Collision.AABB(rayStart - Vector2.One * 0.001f, rayStart + Vector2.One * 0.001f);
+ GameMain.World.QueryAABB((fixture) =>
+ {
+ //ignore sensors and items
+ if (fixture?.Body == null || fixture.IsSensor) return true;
+ if (fixture.UserData is Item) return true;
+
+ //ignore everything else than characters, sub walls and level walls
+ if (!fixture.CollisionCategories.HasFlag(Physics.CollisionCharacter) &&
+ !fixture.CollisionCategories.HasFlag(Physics.CollisionWall) &&
+ !fixture.CollisionCategories.HasFlag(Physics.CollisionLevel)) return true;
+
+ hits.Add(new HitscanResult(fixture, rayStart, -dir, 0.0f));
+ return true;
+ }, ref aabb);
+
GameMain.World.RayCast((fixture, point, normal, fraction) =>
{
- if (fixture == null || fixture.IsSensor) return -1;
-
+ //ignore sensors and items
+ if (fixture?.Body == null || fixture.IsSensor) return -1;
if (fixture.UserData is Item) return -1;
+ //ignore everything else than characters, sub walls and level walls
if (!fixture.CollisionCategories.HasFlag(Physics.CollisionCharacter) &&
!fixture.CollisionCategories.HasFlag(Physics.CollisionWall) &&
!fixture.CollisionCategories.HasFlag(Physics.CollisionLevel)) return -1;
diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Turret.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Turret.cs
index d8ad6eda2..e839e8c8b 100644
--- a/Barotrauma/BarotraumaShared/Source/Items/Components/Turret.cs
+++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Turret.cs
@@ -459,7 +459,7 @@ namespace Barotrauma.Items.Components
}
var containShellObjective = new AIObjectiveContainItem(character, container.ContainableItems[0].Identifiers[0], container, objective.objectiveManager);
- character?.Speak(TextManager.Get("DialogLoadTurret").Replace("[itemname]", item.Name), null, 0.0f, "loadturret", 30.0f);
+ character?.Speak(TextManager.GetWithVariable("DialogLoadTurret", "[itemname]", item.Name, true), null, 0.0f, "loadturret", 30.0f);
containShellObjective.targetItemCount = usableProjectileCount + 1;
containShellObjective.ignoredContainerIdentifiers = new string[] { containerItem.prefab.Identifier };
objective.AddSubObjective(containShellObjective);
@@ -489,28 +489,24 @@ namespace Barotrauma.Items.Components
closestDist = dist;
}
- if (closestEnemy == null) return false;
+ if (closestEnemy == null) { return false; }
character.AIController.SelectTarget(closestEnemy.AiTarget);
character.CursorPosition = closestEnemy.WorldPosition;
- if (item.Submarine != null) character.CursorPosition -= item.Submarine.Position;
-
- //force aim input even if the turret doesn't require it,
- //because the cursor position (and consequently, turret aim direction) is only synced to clients when aiming
- character.SetInput(InputType.Aim, false, true);
-
+ if (item.Submarine != null) { character.CursorPosition -= item.Submarine.Position; }
+
float enemyAngle = MathUtils.VectorToAngle(closestEnemy.WorldPosition - item.WorldPosition);
float turretAngle = -rotation;
- if (Math.Abs(MathUtils.GetShortestAngle(enemyAngle, turretAngle)) > 0.15f) return false;
+ if (Math.Abs(MathUtils.GetShortestAngle(enemyAngle, turretAngle)) > 0.15f) { return false; }
var pickedBody = Submarine.PickBody(ConvertUnits.ToSimUnits(item.WorldPosition), closestEnemy.SimPosition, null);
- if (pickedBody != null && !(pickedBody.UserData is Limb)) return false;
+ if (pickedBody != null && !(pickedBody.UserData is Limb)) { return false; }
if (objective.Option.ToLowerInvariant() == "fireatwill")
{
- character?.Speak(TextManager.Get("DialogFireTurret").Replace("[itemname]", item.Name), null, 0.0f, "fireturret", 5.0f);
+ character?.Speak(TextManager.GetWithVariable("DialogFireTurret", "[itemname]", item.Name, true), null, 0.0f, "fireturret", 5.0f);
character.SetInput(InputType.Shoot, true, true);
}
diff --git a/Barotrauma/BarotraumaShared/Source/Items/Item.cs b/Barotrauma/BarotraumaShared/Source/Items/Item.cs
index da2ae77e2..752d3df85 100644
--- a/Barotrauma/BarotraumaShared/Source/Items/Item.cs
+++ b/Barotrauma/BarotraumaShared/Source/Items/Item.cs
@@ -1539,9 +1539,8 @@ namespace Barotrauma
{
if (requiredSkill != null)
{
- GUI.AddMessage(TextManager.Get("InsufficientSkills")
- .Replace("[requiredskill]", TextManager.Get("SkillName." + requiredSkill.Identifier))
- .Replace("[requiredlevel]", ((int)requiredSkill.Level).ToString()), Color.Red);
+ GUI.AddMessage(TextManager.GetWithVariables("InsufficientSkills", new string[2] { "[requiredskill]", "[requiredlevel]" },
+ new string[2] { TextManager.Get("SkillName." + requiredSkill.Identifier), ((int)requiredSkill.Level).ToString() }, new bool[2] { true, false }), Color.Red);
}
}
#endif
@@ -2033,8 +2032,8 @@ namespace Barotrauma
XElement element = new XElement("Item");
element.Add(
- new XAttribute("name", prefab.Name),
- new XAttribute("identifier", prefab.Identifier),
+ new XAttribute("name", Prefab.OriginalName),
+ new XAttribute("identifier", Prefab.Identifier),
new XAttribute("ID", ID));
if (FlippedX) element.Add(new XAttribute("flippedx", true));
diff --git a/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs b/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs
index 15f3074a6..39c924710 100644
--- a/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs
+++ b/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs
@@ -145,6 +145,11 @@ namespace Barotrauma
private List fabricationRecipeElements = new List();
+ ///
+ /// Original, non-translated name as defined in the xml
+ ///
+ public readonly string OriginalName;
+
public string ConfigFile
{
get { return configFile; }
@@ -440,7 +445,7 @@ namespace Barotrauma
configFile = filePath;
ConfigElement = element;
- string nonTranslatedName = element.GetAttributeString("name", "");
+ OriginalName = element.GetAttributeString("name", "");
identifier = element.GetAttributeString("identifier", "");
//nameidentifier can be used to make multiple items use the same names and descriptions
@@ -448,11 +453,11 @@ namespace Barotrauma
if (string.IsNullOrEmpty(nameIdentifier))
{
- name = TextManager.Get("EntityName." + identifier, true) ?? nonTranslatedName;
+ name = TextManager.Get("EntityName." + identifier, true) ?? OriginalName;
}
else
{
- name = TextManager.Get("EntityName." + nameIdentifier, true) ?? nonTranslatedName;
+ name = TextManager.Get("EntityName." + nameIdentifier, true) ?? OriginalName;
}
if (name == "") { DebugConsole.ThrowError("Unnamed item in " + filePath + "!"); }
@@ -462,7 +467,7 @@ namespace Barotrauma
Aliases = new HashSet
(element.GetAttributeStringArray("aliases", null, convertToLowerInvariant: true) ??
element.GetAttributeStringArray("Aliases", new string[0], convertToLowerInvariant: true));
- Aliases.Add(nonTranslatedName.ToLowerInvariant());
+ Aliases.Add(OriginalName.ToLowerInvariant());
if (!Enum.TryParse(element.GetAttributeString("category", "Misc"), true, out MapEntityCategory category))
{
diff --git a/Barotrauma/BarotraumaShared/Source/Map/Structure.cs b/Barotrauma/BarotraumaShared/Source/Map/Structure.cs
index ea5fb139f..61f475d8f 100644
--- a/Barotrauma/BarotraumaShared/Source/Map/Structure.cs
+++ b/Barotrauma/BarotraumaShared/Source/Map/Structure.cs
@@ -366,14 +366,18 @@ namespace Barotrauma
public override MapEntity Clone()
{
- var clone = new Structure(rect, Prefab, Submarine);
+ var clone = new Structure(rect, Prefab, Submarine)
+ {
+ defaultRect = defaultRect
+ };
foreach (KeyValuePair property in SerializableProperties)
{
- if (!property.Value.Attributes.OfType().Any()) continue;
+ if (!property.Value.Attributes.OfType().Any()) { continue; }
clone.SerializableProperties[property.Key].TrySetValue(clone, property.Value.GetValue(this));
}
if (FlippedX) clone.FlipX(false);
if (FlippedY) clone.FlipY(false);
+
return clone;
}
diff --git a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs
index f9620770f..2cb8f3192 100644
--- a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs
+++ b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs
@@ -730,7 +730,15 @@ namespace Barotrauma
return closestBody;
}
- public static List PickBodies(Vector2 rayStart, Vector2 rayEnd, IEnumerable ignoredBodies = null, Category? collisionCategory = null, bool ignoreSensors = true, Predicate customPredicate = null, bool allowInsideFixture = false)
+ private static readonly Dictionary bodyDist = new Dictionary();
+ private static readonly List bodies = new List();
+
+ ///
+ /// Returns a list of physics bodies the ray intersects with, sorted according to distance (the closest body is at the beginning of the list).
+ ///
+ /// Can be used to filter the bodies based on some condition. If the predicate returns false, the body isignored.
+ /// Should fixtures that the start of the ray is inside be returned
+ public static IEnumerable PickBodies(Vector2 rayStart, Vector2 rayEnd, IEnumerable ignoredBodies = null, Category? collisionCategory = null, bool ignoreSensors = true, Predicate customPredicate = null, bool allowInsideFixture = false)
{
if (Vector2.DistanceSquared(rayStart, rayEnd) < 0.00001f)
{
@@ -738,20 +746,25 @@ namespace Barotrauma
}
float closestFraction = 1.0f;
- List bodies = new List();
+ bodies.Clear();
+ bodyDist.Clear();
GameMain.World.RayCast((fixture, point, normal, fraction) =>
{
if (!CheckFixtureCollision(fixture, ignoredBodies, collisionCategory, ignoreSensors, customPredicate)) { return -1; }
- if (fixture.Body != null) { bodies.Add(fixture.Body); }
+ if (fixture.Body != null)
+ {
+ bodies.Add(fixture.Body);
+ bodyDist[fixture.Body] = fraction;
+ }
if (fraction < closestFraction)
{
lastPickedPosition = rayStart + (rayEnd - rayStart) * fraction;
lastPickedFraction = fraction;
lastPickedNormal = normal;
}
-
- return fraction;
+ //continue
+ return -1;
}, rayStart, rayEnd);
if (allowInsideFixture)
@@ -770,10 +783,12 @@ namespace Barotrauma
lastPickedFraction = 0.0f;
lastPickedNormal = Vector2.Normalize(rayEnd - rayStart);
bodies.Add(fixture.Body);
+ bodyDist[fixture.Body] = 0.0f;
return false;
}, ref aabb);
}
+ bodies.Sort((b1, b2) => { return bodyDist[b1].CompareTo(bodyDist[b2]); });
return bodies;
}
diff --git a/Barotrauma/BarotraumaShared/Source/Map/WayPoint.cs b/Barotrauma/BarotraumaShared/Source/Map/WayPoint.cs
index 7d1dac36e..e2df8eafb 100644
--- a/Barotrauma/BarotraumaShared/Source/Map/WayPoint.cs
+++ b/Barotrauma/BarotraumaShared/Source/Map/WayPoint.cs
@@ -91,7 +91,7 @@ namespace Barotrauma
public WayPoint(MapEntityPrefab prefab, Rectangle rectangle)
: this (rectangle, Submarine.MainSub)
{
- if (prefab.Name.Contains("Spawn"))
+ if (prefab.Identifier.Contains("spawn"))
{
spawnType = SpawnType.Human;
}
diff --git a/Barotrauma/BarotraumaShared/Source/Networking/ServerSettings.cs b/Barotrauma/BarotraumaShared/Source/Networking/ServerSettings.cs
index 5dd5f1546..01ccc1c0e 100644
--- a/Barotrauma/BarotraumaShared/Source/Networking/ServerSettings.cs
+++ b/Barotrauma/BarotraumaShared/Source/Networking/ServerSettings.cs
@@ -656,7 +656,7 @@ namespace Barotrauma.Networking
private set;
} = new List>();
- public void ReadMonsterEnabled(NetBuffer inc)
+ private void InitMonstersEnabled()
{
//monster spawn settings
if (MonsterEnabled == null)
@@ -673,7 +673,11 @@ namespace Barotrauma.Networking
if (!MonsterEnabled.ContainsKey(s)) MonsterEnabled.Add(s, true);
}
}
+ }
+ public void ReadMonsterEnabled(NetBuffer inc)
+ {
+ InitMonstersEnabled();
List monsterNames = MonsterEnabled.Keys.ToList();
foreach (string s in monsterNames)
{
@@ -681,7 +685,7 @@ namespace Barotrauma.Networking
}
inc.ReadPadBits();
}
-
+
public void WriteMonsterEnabled(NetBuffer msg, Dictionary monsterEnabled = null)
{
//monster spawn settings
@@ -703,13 +707,17 @@ namespace Barotrauma.Networking
Dictionary extraCargo = new Dictionary();
for (int i = 0; i < count; i++)
{
+ string prefabIdentifier = msg.ReadString();
string prefabName = msg.ReadString();
byte amount = msg.ReadByte();
- ItemPrefab ip = MapEntityPrefab.List.Find(p => p is ItemPrefab && p.Name.Equals(prefabName, StringComparison.InvariantCulture)) as ItemPrefab;
- if (ip != null && amount > 0)
+
+ var itemPrefab = string.IsNullOrEmpty(prefabIdentifier) ?
+ MapEntityPrefab.Find(prefabName, null, showErrorMessages: false) as ItemPrefab :
+ MapEntityPrefab.Find(prefabName, prefabIdentifier, showErrorMessages: false) as ItemPrefab;
+ if (itemPrefab != null && amount > 0)
{
- if (changed || !ExtraCargo.ContainsKey(ip) || ExtraCargo[ip] != amount) changed = true;
- extraCargo.Add(ip, amount);
+ if (changed || !ExtraCargo.ContainsKey(itemPrefab) || ExtraCargo[itemPrefab] != amount) changed = true;
+ extraCargo.Add(itemPrefab, amount);
}
}
if (changed) ExtraCargo = extraCargo;
@@ -727,7 +735,9 @@ namespace Barotrauma.Networking
msg.Write((UInt32)ExtraCargo.Count);
foreach (KeyValuePair kvp in ExtraCargo)
{
- msg.Write(kvp.Key.Name); msg.Write((byte)kvp.Value);
+ msg.Write(kvp.Key.Identifier ?? "");
+ msg.Write(kvp.Key.OriginalName ?? "");
+ msg.Write((byte)kvp.Value);
}
}
}
diff --git a/Barotrauma/BarotraumaShared/Source/TextManager.cs b/Barotrauma/BarotraumaShared/Source/TextManager.cs
index 60ff00a43..5091040a0 100644
--- a/Barotrauma/BarotraumaShared/Source/TextManager.cs
+++ b/Barotrauma/BarotraumaShared/Source/TextManager.cs
@@ -176,6 +176,107 @@ namespace Barotrauma
}
}
+ public static string GetWithVariables(string textTag, string[] variableTags, string[] variableValues, bool[] formatCapitals = null, bool returnNull = false, string fallBackTag = null)
+ {
+ string text = Get(textTag, returnNull, fallBackTag);
+
+ if (text == null || text.Length == 0 || variableTags.Length != variableValues.Length)
+ {
+#if DEBUG
+ if (variableTags.Length != variableValues.Length)
+ {
+ DebugConsole.ThrowError("variableTags.Length and variableValues.Length do not match for \"" + textTag + "\".");
+ }
+
+ if (formatCapitals != null && formatCapitals.Length != variableTags.Length)
+ {
+ DebugConsole.ThrowError("variableTags.Length and formatCapitals.Length do not match for \"" + textTag + "\".");
+ }
+#endif
+ if (returnNull)
+ {
+ return null;
+ }
+ else
+ {
+ return textTag;
+ }
+ }
+
+ if (formatCapitals != null && !GameMain.Config.Language.Contains("Chinese"))
+ {
+ for (int i = 0; i < variableTags.Length; i++)
+ {
+ if (formatCapitals[i])
+ {
+ variableValues[i] = HandleVariableCapitalization(text, variableTags[i], variableValues[i]);
+ }
+ }
+ }
+
+ for (int i = 0; i < variableTags.Length; i++)
+ {
+ text = text.Replace(variableTags[i], variableValues[i]);
+ }
+
+ return text;
+ }
+
+ public static string GetWithVariable(string textTag, string variableTag, string variableValue, bool formatCapitals = false, bool returnNull = false, string fallBackTag = null)
+ {
+ string text = Get(textTag, returnNull, fallBackTag);
+
+ if (text == null || text.Length == 0)
+ {
+ if (returnNull)
+ {
+ return null;
+ }
+ else
+ {
+ return textTag;
+ }
+ }
+
+ if (formatCapitals && !GameMain.Config.Language.Contains("Chinese"))
+ {
+ variableValue = HandleVariableCapitalization(text, variableTag, variableValue);
+ }
+
+ return text.Replace(variableTag, variableValue);
+ }
+
+ private static string HandleVariableCapitalization(string text, string variableTag, string variableValue)
+ {
+ int index = text.IndexOf(variableTag) - 1;
+ if (index == -1)
+ {
+ return variableValue;
+ }
+
+ for (int i = index; i >= 0; i--)
+ {
+ if (text[i] == ' ')
+ {
+ continue;
+ }
+ else
+ {
+ if (text[i] != '.')
+ {
+ variableValue = variableValue.ToLower();
+ }
+ else
+ {
+ variableValue = Capitalize(variableValue);
+ break;
+ }
+ }
+ }
+
+ return variableValue;
+ }
+
public static string ParseInputTypes(string text)
{
foreach (InputType inputType in Enum.GetValues(typeof(InputType)))
diff --git a/Barotrauma/BarotraumaShared/Submarines/Orca.sub b/Barotrauma/BarotraumaShared/Submarines/Orca.sub
index 311edf3e7..c77d6144d 100644
Binary files a/Barotrauma/BarotraumaShared/Submarines/Orca.sub and b/Barotrauma/BarotraumaShared/Submarines/Orca.sub differ
diff --git a/Barotrauma/BarotraumaShared/Submarines/Remora.sub b/Barotrauma/BarotraumaShared/Submarines/Remora.sub
index 6e3afa65c..6f29eb586 100644
Binary files a/Barotrauma/BarotraumaShared/Submarines/Remora.sub and b/Barotrauma/BarotraumaShared/Submarines/Remora.sub differ
diff --git a/Barotrauma/BarotraumaShared/Submarines/RemoraDrone.sub b/Barotrauma/BarotraumaShared/Submarines/RemoraDrone.sub
index ec48ad330..49ade4d29 100644
Binary files a/Barotrauma/BarotraumaShared/Submarines/RemoraDrone.sub and b/Barotrauma/BarotraumaShared/Submarines/RemoraDrone.sub differ
diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt
index 893423726..745a25aea 100644
--- a/Barotrauma/BarotraumaShared/changelog.txt
+++ b/Barotrauma/BarotraumaShared/changelog.txt
@@ -1,3 +1,50 @@
+---------------------------------------------------------------------------------------------------------
+v0.9.0.4
+---------------------------------------------------------------------------------------------------------
+
+- Fixed "Steam authentication failed" errors when trying to reconnect to a server after cancelling the
+connection.
+- Fixed clients occasionally failing to spawn items when playing using a different language than the server,
+which caused them to get kicked.
+- Fixed extra cargo failing to spawn in multiplayer when playing using a different language than the server.
+- Fixed legacy items failing to load if a sub is saved with a language other than English and the language
+then changed to something else.
+- Fixed excessively small password input box when connecting to servers.
+- Fixed a bug that occasionally caused items to drop from the inventory when moving items between
+inventory slots in the multiplayer.
+- Prevent junction boxes from getting damaged due to overvoltage in the engineering tutorial.
+- Fixed structures getting scaled incorrectly when cloning a structure with a non-default scale in the
+submarine editor.
+- Fixed occasional crashes when leaving a multiplayer session while the "cinematic" at the end of the round
+is still playing.
+- Fixed items not being moved to the humanhusk's inventory when a huskified player dies (= clothes and
+other gear seemed to magically disappear when the character "resurrected" as an AI husk).
+- Fixed clients not seeing turrets rotating at their end when another client is operating the turret.
+- Fixed hitscan projectiles (revolver rounds) going through walls if the weapon is fired while its
+barrel is partially inside the wall.
+- Fixed welding tools being able to weld doors and burn characters through walls.
+- Fixed bots reporting leaks when there are holes in the interior walls.
+- Fixes to the colliders of some of the shuttle wall pieces.
+- Fixed Linux version crashing when attempting to browse for files in the Steam Workshop menu.
+- Fixed credits not resizing when resolution is changed.
+- Added an upper limit to impact damage done to ragdolls, preventing characters from getting instakilled if
+a Moloch or another large monster smashes against the sub hard enough.
+
+---------------------------------------------------------------------------------------------------------
+v0.9.0.3
+---------------------------------------------------------------------------------------------------------
+
+- Fixed captain tutorial not continuing after the part where the mechanic has to be ordered to do repairs.
+- Fixed mechanic tutorial getting stuck if repairing the devices is interrupted before they're fully repaired.
+- Fixed Workshop item preview images not working on Mac or Linux.
+- Fixed "Add file" and "Browse preview image" file dialogs crashing some Mac/Linux systems.
+- Unlock tutorials one by one.
+- Fixed crashing when clicking on the "no matching servers found" message in the server list.
+- Fixed loading screen being dismissable when the window is not active.
+- Fixed connection panel overlay overlapping with the connections on resolutions higher than 1080p.
+- Fixed incorrect "mission completed" text in the combat missions.
+- Fixed "a swarm of [monster]" description in the crawler swarm mission.
+
---------------------------------------------------------------------------------------------------------
v0.9.0.2
---------------------------------------------------------------------------------------------------------