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 WaitForItemPreviewDownloaded(Facepunch.Steamworks.Workshop.Item item, GUIListBox listBox, string previewImagePath) { while (pendingPreviewImageDownloads.Contains(item.PreviewImageUrl)) @@ -710,7 +733,7 @@ namespace Barotrauma new GUIImage(new RectTransform(new Point(scoreContainer.Rect.Height), scoreContainer.RectTransform), i < starCount ? "GUIStarIconBright" : "GUIStarIconDark"); } - new GUITextBlock(new RectTransform(new Vector2(0.2f, 0.0f), scoreContainer.RectTransform), TextManager.Get("WorkshopItemVotes").Replace("[votecount]", (item.VotesUp + item.VotesDown).ToString())); + new GUITextBlock(new RectTransform(new Vector2(0.2f, 0.0f), scoreContainer.RectTransform), TextManager.GetWithVariable("WorkshopItemVotes", "[votecount]", (item.VotesUp + item.VotesDown).ToString())); //tags ------------------------------------ var tagContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), content.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) @@ -834,7 +857,7 @@ namespace Barotrauma if (!item.Installed) { new GUIMessageBox(TextManager.Get("Error"), - TextManager.Get("WorkshopErrorInstallRequiredToEdit").Replace("[itemname]", TextManager.EnsureUTF8(item.Title))); + TextManager.GetWithVariable("WorkshopErrorInstallRequiredToEdit", "[itemname]", TextManager.EnsureUTF8(item.Title))); return; } SteamManager.CreateWorkshopItemStaging(item, out itemEditor, out itemContentPackage); @@ -942,34 +965,38 @@ namespace Barotrauma { OnClicked = (btn, userdata) => { - OpenFileDialog ofd = new OpenFileDialog() + try { - InitialDirectory = Path.GetFullPath(SteamManager.WorkshopItemStagingFolder), - Filter = TextManager.Get("WorkshopItemPreviewImage")+"|*.png", - Title = TextManager.Get("WorkshopItemPreviewImageDialogTitle") - }; - if (ofd.ShowDialog() == DialogResult.OK) + Barotrauma.OpenFileDialog ofd = new Barotrauma.OpenFileDialog() + { + Multiselect = true, + InitialDirectory = Path.GetFullPath(SteamManager.WorkshopItemStagingFolder), + Filter = TextManager.Get("WorkshopItemPreviewImage") + "|*.png", + Title = TextManager.Get("WorkshopItemPreviewImageDialogTitle") + }; + if (ofd.ShowDialog() == DialogResult.OK) + { + OnPreviewImageSelected(previewIcon, ofd.FileName); + } + } + catch { - string previewImagePath = Path.GetFullPath(Path.Combine(SteamManager.WorkshopItemStagingFolder, SteamManager.PreviewImageName)); - if (new FileInfo(ofd.FileName).Length > 1024 * 1024) - { - new GUIMessageBox(TextManager.Get("Error"), TextManager.Get("WorkshopItemPreviewImageTooLarge")); - return false; - } - - if (ofd.FileName != previewImagePath) - { - File.Copy(ofd.FileName, previewImagePath, overwrite: true); - } + //use a custom prompt if OpenFileDialog fails (Linux/Mac) + var msgBox = new GUIMessageBox(TextManager.Get("WorkshopItemPreviewImageDialogTitle"), "", relativeSize: new Vector2(0.4f, 0.2f), + buttons: new string[] { TextManager.Get("Cancel"), TextManager.Get("OK") }); - if (itemPreviewSprites.ContainsKey(previewImagePath)) + var pathBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.5f), msgBox.Content.RectTransform, Anchor.Center) { MinSize = new Point(0,25) }); + + msgBox.Buttons[0].OnClicked += msgBox.Close; + msgBox.Buttons[1].OnClicked += msgBox.Close; + msgBox.Buttons[1].OnClicked += (btn2, userdata2) => { - itemPreviewSprites[previewImagePath].Remove(); - } - var newPreviewImage = new Sprite(previewImagePath, sourceRectangle: null); - previewIcon.Sprite = newPreviewImage; - itemPreviewSprites[previewImagePath] = newPreviewImage; - itemEditor.PreviewImage = previewImagePath; + if (File.Exists(pathBox.Text)) + { + OnPreviewImageSelected(previewIcon, pathBox.Text); + }; + return true; + }; } return true; } @@ -998,9 +1025,8 @@ namespace Barotrauma { new GUIMessageBox( TextManager.Get("Error"), - TextManager.Get("ContentPackageCantMakeCorePackage") - .Replace("[packagename]", itemContentPackage.Name) - .Replace("[missingfiletypes]", string.Join(", ", missingContentTypes))); + TextManager.GetWithVariables("ContentPackageCantMakeCorePackage", new string[2] { "[packagename]", "[missingfiletypes]" }, + new string[2] { itemContentPackage.Name, string.Join(", ", missingContentTypes) }, new bool[2] { false, true })); tickbox.Selected = false; } else @@ -1049,40 +1075,40 @@ namespace Barotrauma { OnClicked = (btn, userdata) => { - OpenFileDialog ofd = new OpenFileDialog() + try { - InitialDirectory = Path.GetFullPath(SteamManager.WorkshopItemStagingFolder), - Title = "Select the files you want to add to the Steam Workshop item", - }; - if (ofd.ShowDialog() == DialogResult.OK) - { - foreach (string file in ofd.FileNames) + Barotrauma.OpenFileDialog ofd = new Barotrauma.OpenFileDialog() { - string filePathRelativeToStagingFolder = UpdaterUtil.GetRelativePath(file, Path.Combine(Environment.CurrentDirectory, SteamManager.WorkshopItemStagingFolder)); - string filePathRelativeToBaseFolder = UpdaterUtil.GetRelativePath(file, Environment.CurrentDirectory); - //file is not inside the staging folder - if (filePathRelativeToStagingFolder.StartsWith("..")) - { - //submarines can be included in the content package directly - string basePath = Path.GetDirectoryName(filePathRelativeToBaseFolder.Replace("..", "")); - if (basePath == "Submarines") - { - string destinationPath = Path.Combine(SteamManager.WorkshopItemStagingFolder, "Submarines", Path.GetFileName(file)); - File.Copy(file, destinationPath); - itemContentPackage.AddFile(filePathRelativeToBaseFolder, ContentType.Submarine); - } - else - { - itemContentPackage.AddFile(filePathRelativeToBaseFolder, ContentType.None); - } - } - else - { - itemContentPackage.AddFile(filePathRelativeToStagingFolder, ContentType.None); - } + InitialDirectory = Path.GetFullPath(SteamManager.WorkshopItemStagingFolder), + Title = TextManager.Get("workshopitemaddfiles"), + }; + if (ofd.ShowDialog() == DialogResult.OK) + { + OnAddFilesSelected(ofd.FileNames); } - RefreshCreateItemFileList(); } + catch + { + //use a custom prompt if OpenFileDialog fails (Linux/Mac) + var msgBox = new GUIMessageBox(TextManager.Get("workshopitemaddfiles"), "", relativeSize: new Vector2(0.4f, 0.2f), + buttons: new string[] { TextManager.Get("Cancel"), TextManager.Get("OK") }); + + var pathBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.5f), msgBox.Content.RectTransform, Anchor.Center) { MinSize = new Point(0, 25) }); + + msgBox.Buttons[0].OnClicked += msgBox.Close; + msgBox.Buttons[1].OnClicked += msgBox.Close; + msgBox.Buttons[1].OnClicked += (btn2, userdata2) => + { + if (string.IsNullOrEmpty(pathBox?.Text)) { return true; } + string[] filePaths = pathBox.Text.Split(','); + if (File.Exists(pathBox.Text)) + { + OnAddFilesSelected(filePaths); + }; + return true; + }; + } + return true; } }; @@ -1127,7 +1153,7 @@ namespace Barotrauma OnClicked = (btn, userData) => { if (itemEditor == null) { return false; } - var deleteVerification = new GUIMessageBox("", TextManager.Get("WorkshopItemDeleteVerification").Replace("[itemname]", itemEditor.Title), + var deleteVerification = new GUIMessageBox("", TextManager.GetWithVariable("WorkshopItemDeleteVerification", "[itemname]", itemEditor.Title), new string[] { TextManager.Get("Yes"), TextManager.Get("No") }); deleteVerification.Buttons[0].OnClicked = (yesBtn, userdata) => { @@ -1144,7 +1170,7 @@ namespace Barotrauma } }; } - new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), bottomButtonContainer.RectTransform, Anchor.CenterRight), + var publishBtn = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), bottomButtonContainer.RectTransform, Anchor.CenterRight), TextManager.Get(itemEditor.Id > 0 ? "WorkshopItemUpdate" : "WorkshopItemPublish"), style: "GUIButtonLarge") { IgnoreLayoutGroups = true, @@ -1172,7 +1198,67 @@ namespace Barotrauma return true; } }; + publishBtn.TextBlock.AutoScale = true; + } + private void OnPreviewImageSelected(GUIImage previewImageElement, string filePath) + { + string previewImagePath = Path.GetFullPath(Path.Combine(SteamManager.WorkshopItemStagingFolder, SteamManager.PreviewImageName)); + if (new FileInfo(filePath).Length > 1024 * 1024) + { + new GUIMessageBox(TextManager.Get("Error"), TextManager.Get("WorkshopItemPreviewImageTooLarge")); + return; + } + + if (filePath != previewImagePath) + { + File.Copy(filePath, previewImagePath, overwrite: true); + } + + if (itemPreviewSprites.ContainsKey(previewImagePath)) + { + itemPreviewSprites[previewImagePath].Remove(); + } + var newPreviewImage = new Sprite(previewImagePath, sourceRectangle: null); + previewImageElement.Sprite = newPreviewImage; + itemPreviewSprites[previewImagePath] = newPreviewImage; + itemEditor.PreviewImage = previewImagePath; + } + + private void OnAddFilesSelected(string[] fileNames) + { + if (fileNames == null) { return; } + for(int i = 0; i < fileNames.Length; i++) + { + string file = fileNames[i]; + if (string.IsNullOrEmpty(file)) { continue; } + file = file.Trim(); + if (!File.Exists(file)) { continue; } + + string filePathRelativeToStagingFolder = UpdaterUtil.GetRelativePath(file, Path.Combine(Environment.CurrentDirectory, SteamManager.WorkshopItemStagingFolder)); + string filePathRelativeToBaseFolder = UpdaterUtil.GetRelativePath(file, Environment.CurrentDirectory); + //file is not inside the staging folder + if (filePathRelativeToStagingFolder.StartsWith("..")) + { + //submarines can be included in the content package directly + string basePath = Path.GetDirectoryName(filePathRelativeToBaseFolder.Replace("..", "")); + if (basePath == "Submarines") + { + string destinationPath = Path.Combine(SteamManager.WorkshopItemStagingFolder, "Submarines", Path.GetFileName(file)); + File.Copy(file, destinationPath); + itemContentPackage.AddFile(filePathRelativeToBaseFolder, ContentType.Submarine); + } + else + { + itemContentPackage.AddFile(filePathRelativeToBaseFolder, ContentType.None); + } + } + else + { + itemContentPackage.AddFile(filePathRelativeToStagingFolder, ContentType.None); + } + } + RefreshCreateItemFileList(); } private void RefreshCreateItemFileList() @@ -1269,7 +1355,7 @@ namespace Barotrauma string pleaseWaitText = TextManager.Get("WorkshopPublishPleaseWait"); var msgBox = new GUIMessageBox( pleaseWaitText, - TextManager.Get("WorkshopPublishInProgress").Replace("[itemname]", TextManager.EnsureUTF8(item.Title)), + TextManager.GetWithVariable("WorkshopPublishInProgress", "[itemname]", TextManager.EnsureUTF8(item.Title)), new string[] { TextManager.Get("Cancel") }); msgBox.Buttons[0].OnClicked = (btn, userdata) => @@ -1291,13 +1377,13 @@ namespace Barotrauma if (string.IsNullOrEmpty(item.Error)) { - new GUIMessageBox("", TextManager.Get("WorkshopItemPublished").Replace("[itemname]", TextManager.EnsureUTF8(item.Title))); + new GUIMessageBox("", TextManager.GetWithVariable("WorkshopItemPublished", "[itemname]", TextManager.EnsureUTF8(item.Title))); } else { new GUIMessageBox( TextManager.Get("Error"), - TextManager.Get("WorkshopItemPublishFailed").Replace("[itemname]", TextManager.EnsureUTF8(item.Title)) + item.Error); + TextManager.GetWithVariable("WorkshopItemPublishFailed", "[itemname]", TextManager.EnsureUTF8(item.Title)) + item.Error); } createItemFrame.ClearChildren(); diff --git a/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs index c45c37df1..ec29f34d8 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs @@ -115,7 +115,7 @@ namespace Barotrauma { if (buoyancyVol / selectedVol < 1.0f) { - retVal += " (" + TextManager.Get("OptimalBallastLevel").Replace("[value]", (buoyancyVol / selectedVol).ToString("0.000")) + ")"; + retVal += " (" + TextManager.GetWithVariable("OptimalBallastLevel", "[value]", (buoyancyVol / selectedVol).ToString("0.000")) + ")"; } else { @@ -572,7 +572,7 @@ namespace Barotrauma ItemAssemblyPrefab assemblyPrefab = userData as ItemAssemblyPrefab; var msgBox = new GUIMessageBox( TextManager.Get("DeleteDialogLabel"), - TextManager.Get("DeleteDialogQuestion").Replace("[file]", assemblyPrefab.Name), + TextManager.GetWithVariable("DeleteDialogQuestion", "[file]", assemblyPrefab.Name), new string[] { TextManager.Get("Yes"), TextManager.Get("Cancel") }); msgBox.Buttons[0].OnClicked += (deleteBtn, userData2) => { @@ -584,7 +584,7 @@ namespace Barotrauma } catch (Exception e) { - DebugConsole.ThrowError(TextManager.Get("DeleteFileError").Replace("[file]", assemblyPrefab.Name), e); + DebugConsole.ThrowError(TextManager.GetWithVariable("DeleteFileError", "[file]", assemblyPrefab.Name), e); } return true; }; @@ -861,7 +861,7 @@ namespace Barotrauma { if (nameBox.Text.Contains(illegalChar)) { - GUI.AddMessage(TextManager.Get("SubNameIllegalCharsWarning").Replace("[illegalchar]", illegalChar.ToString()), Color.Red); + GUI.AddMessage(TextManager.GetWithVariable("SubNameIllegalCharsWarning", "[illegalchar]", illegalChar.ToString()), Color.Red); nameBox.Flash(); return false; } @@ -907,7 +907,7 @@ namespace Barotrauma } Submarine.MainSub.CheckForErrors(); - GUI.AddMessage(TextManager.Get("SubSavedNotification").Replace("[filepath]", Submarine.MainSub.FilePath), Color.Green); + GUI.AddMessage(TextManager.GetWithVariable("SubSavedNotification", "[filepath]", Submarine.MainSub.FilePath), Color.Green); Submarine.RefreshSavedSub(savePath); if (prevSavePath != null && prevSavePath != savePath) @@ -1074,7 +1074,7 @@ namespace Barotrauma { OnClicked = (btn, userdata) => { - OpenFileDialog ofd = new OpenFileDialog() + Barotrauma.OpenFileDialog ofd = new Barotrauma.OpenFileDialog() { InitialDirectory = Path.GetFullPath(Submarine.SavePath), Filter = "PNG file|*.png", @@ -1259,7 +1259,7 @@ namespace Barotrauma { if (nameBox.Text.Contains(illegalChar)) { - GUI.AddMessage(TextManager.Get("ItemAssemblyNameIllegalCharsWarning").Replace("[illegalchar]", illegalChar.ToString()), Color.Red); + GUI.AddMessage(TextManager.GetWithVariable("ItemAssemblyNameIllegalCharsWarning", "[illegalchar]", illegalChar.ToString()), Color.Red); nameBox.Flash(); return false; } @@ -1476,7 +1476,7 @@ namespace Barotrauma var msgBox = new GUIMessageBox( TextManager.Get("DeleteDialogLabel"), - TextManager.Get("DeleteDialogQuestion").Replace("[file]", sub.Name), + TextManager.GetWithVariable("DeleteDialogQuestion", "[file]", sub.Name), new string[] { TextManager.Get("Yes"), TextManager.Get("Cancel") }); msgBox.Buttons[0].OnClicked += (btn, userData) => { @@ -1489,7 +1489,7 @@ namespace Barotrauma } catch (Exception e) { - DebugConsole.ThrowError(TextManager.Get("DeleteFileError").Replace("[file]", sub.FilePath), e); + DebugConsole.ThrowError(TextManager.GetWithVariable("DeleteFileError", "[file]", sub.FilePath), e); } return true; }; diff --git a/Barotrauma/BarotraumaClient/Source/Serialization/SerializableEntityEditor.cs b/Barotrauma/BarotraumaClient/Source/Serialization/SerializableEntityEditor.cs index 2ce6ff0d7..e7bac5c7c 100644 --- a/Barotrauma/BarotraumaClient/Source/Serialization/SerializableEntityEditor.cs +++ b/Barotrauma/BarotraumaClient/Source/Serialization/SerializableEntityEditor.cs @@ -536,12 +536,12 @@ namespace Barotrauma if (translatedText == null) { propertyBox.TextColor = Color.Gray; - propertyBox.ToolTip = TextManager.Get("StringPropertyCannotTranslate").Replace("[tag]", text ?? ""); + propertyBox.ToolTip = TextManager.GetWithVariable("StringPropertyCannotTranslate", "[tag]", text ?? string.Empty); } else { propertyBox.TextColor = Color.LightGreen; - propertyBox.ToolTip = TextManager.Get("StringPropertyTranslate").Replace("[translation]", translatedText); + propertyBox.ToolTip = TextManager.GetWithVariable("StringPropertyTranslate", "[translation]", translatedText); } return true; }; diff --git a/Barotrauma/BarotraumaClient/Source/Sounds/OpenAL/Al.cs b/Barotrauma/BarotraumaClient/Source/Sounds/OpenAL/Al.cs new file mode 100644 index 000000000..f2b3d6e9e --- /dev/null +++ b/Barotrauma/BarotraumaClient/Source/Sounds/OpenAL/Al.cs @@ -0,0 +1,467 @@ +/*** + +MIT License + +Copyright (c) 2018 Nathan Glover + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +**************** + +Further modified for use in Barotrauma. +Original source code at https://github.com/NathanielGlover/OpenAL.NETCore/ + +***/ + +using System; +using System.Runtime.InteropServices; + +namespace OpenAL +{ + public class Al + { +#if OSX + public const string OpenAlDll = "/System/Library/Frameworks/OpenAL.framework/OpenAL"; +#elif LINUX + public const string OpenAlDll = "libopenal.so.1"; +#elif WINDOWS +#if X86 + public const string OpenAlDll = "soft_oal_x86.dll"; +#elif X64 + public const string OpenAlDll = "soft_oal_x64.dll"; +#endif +#endif + + #region Enum + + public const int None = 0; + public const int False = 0; + public const int True = 1; + public const int SourceRelative = 0x202; + public const int ConeInnerAngle = 0x1001; + public const int ConeOuterAngle = 0x1002; + public const int Pitch = 0x1003; + public const int Position = 0x1004; + public const int Direction = 0x1005; + public const int Velocity = 0x1006; + public const int Looping = 0x1007; + public const int Buffer = 0x1009; + public const int Gain = 0x100A; + public const int MinGain = 0x100D; + public const int MaxGain = 0x100E; + public const int Orientation = 0x100F; + public const int SourceState = 0x1010; + public const int Initial = 0x1011; + public const int Playing = 0x1012; + public const int Paused = 0x1013; + public const int Stopped = 0x1014; + public const int BuffersQueued = 0x1015; + public const int BuffersProcessed = 0x1016; + public const int SecOffset = 0x1024; + public const int SampleOffset = 0x1025; + public const int ByteOffset = 0x1026; + public const int SourceType = 0x1027; + public const int Static = 0x1028; + public const int Streaming = 0x1029; + public const int Undetermined = 0x1030; + public const int FormatMono8 = 0x1100; + public const int FormatMono16 = 0x1101; + public const int FormatStereo8 = 0x1102; + public const int FormatStereo16 = 0x1103; + public const int ReferenceDistance = 0x1020; + public const int RolloffFactor = 0x1021; + public const int ConeOuterGain = 0x1022; + public const int MaxDistance = 0x1023; + public const int Frequency = 0x2001; + public const int Bits = 0x2002; + public const int Channels = 0x2003; + public const int Size = 0x2004; + public const int Unused = 0x2010; + public const int Pending = 0x2011; + public const int Processed = 0x2012; + public const int NoError = False; + public const int InvalidName = 0xA001; + public const int InvalidEnum = 0xA002; + public const int InvalidValue = 0xA003; + public const int InvalidOperation = 0xA004; + public const int OutOfMemory = 0xA005; + public const int Vendor = 0xB001; + public const int Version = 0xB002; + public const int Renderer = 0xB003; + public const int Extensions = 0xB004; + public const int EnumDopplerFactor = 0xC000; + public const int EnumDopplerVelocity = 0xC001; + public const int EnumSpeedOfSound = 0xC003; + public const int EnumDistanceModel = 0xD000; + public const int InverseDistance = 0xD001; + public const int InverseDistanceClamped = 0xD002; + public const int LinearDistance = 0xD003; + public const int LinearDistanceClamped = 0xD004; + public const int ExponentDistance = 0xD005; + public const int ExponentDistanceClamped = 0xD006; + + #endregion + + #region Functions + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alEnable")] + public static extern void Enable(int capability); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alDisable")] + public static extern void Disable(int capability); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alIsEnabled")] + public static extern bool IsEnabled(int capability); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetString")] + private static extern IntPtr _GetString(int param); + + public static string GetString(int param) => Marshal.PtrToStringAnsi(_GetString(param)); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetBooleanv")] + public static extern void GetBooleanv(int param, out bool data); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetIntegerv")] + public static extern void GetIntegerv(int param, out int data); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetFloatv")] + public static extern void GetFloatv(int param, out float data); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetDoublev")] + public static extern void GetDoublev(int param, out double data); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetBoolean")] + public static extern bool GetBoolean(int param); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetInteger")] + public static extern int GetInteger(int param); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetFloat")] + public static extern float GetFloat(int param); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetDouble")] + public static extern double GetDouble(int param); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetError")] + public static extern int GetError(); + + public static string GetErrorString(int error) + { + switch (error) + { + case NoError: + return "No error"; + case InvalidName: + return "Invalid name"; + case InvalidEnum: + return "Invalid enum"; + case InvalidValue: + return "Invalid value"; + case InvalidOperation: + return "Invalid operation"; + case OutOfMemory: + return "Out of memory"; + default: + return "Unknown error"; + } + } + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alIsExtensionPresent")] + public static extern bool IsExtensionPresent(string extname); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetProcAddress")] + public static extern IntPtr GetProcAddress(string fname); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetEnumValue")] + public static extern int GetEnumValue(string ename); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alListenerf")] + public static extern void Listenerf(int param, float value); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alListener3f")] + public static extern void Listener3f(int param, float value1, float value2, float value3); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alListenerfv")] + public static extern void Listenerfv(int param, float[] values); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetListenerf")] + public static extern void GetListenerf(int param, out float value); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetListener3f")] + public static extern void GetListener3f(int param, out float value1, out float value2, out float value3); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetListenerfv")] + private static extern void _GetListenerfv(int param, IntPtr values); + + public static void GetListenerfv(int param, out float[] values) + { + int len; + switch(param) + { + case Gain: + len = 1; + break; + case Position: + case Velocity: + len = 3; + break; + case Orientation: + len = 6; + break; + default: + len = 0; + break; + } + + values = new float[len]; + + GCHandle arrayHandle = GCHandle.Alloc(values, GCHandleType.Pinned); + _GetListenerfv(param, arrayHandle.AddrOfPinnedObject()); + arrayHandle.Free(); + } + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGenSources")] + private static extern void _GenSources(int n, IntPtr sources); + + public static void GenSources(int n, out uint[] sources) + { + sources = new uint[n]; + + GCHandle arrayHandle = GCHandle.Alloc(sources, GCHandleType.Pinned); + _GenSources(n, arrayHandle.AddrOfPinnedObject()); + arrayHandle.Free(); + } + + public static void GenSource(out uint source) + { + GenSources(1, out var sources); + source = sources[0]; + } + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alDeleteSources")] + public static extern void DeleteSources(int n, uint[] sources); + + public static void DeleteSource(uint source) => DeleteSources(1, new[] {source}); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alIsSource")] + public static extern bool IsSource(uint sid); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alSourcef")] + public static extern void Sourcef(uint sid, int param, float value); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alSource3f")] + public static extern void Source3f(uint sid, int param, float value1, float value2, float value3); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alSourcefv")] + public static extern void Sourcefv(uint sid, int param, float[] values); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alSourcei")] + public static extern void Sourcei(uint sid, int param, int value); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alSource3i")] + public static extern void Source3i(uint sid, int param, int value1, int value2, int value3); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alSourceiv")] + public static extern void Sourceiv(uint sid, int param, int[] values); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetSourcef")] + public static extern void GetSourcef(uint sid, int param, out float value); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetSource3f")] + public static extern void GetSource3f(uint sid, int param, out float value1, out float value2, out float value3); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetSourcefv")] + private static extern void _GetSourcefv(uint sid, int param, IntPtr values); + + public static void GetSourcefv(uint sid, int param, out float[] values) + { + int len; + switch(param) + { + case Pitch: + case Gain: + case MaxDistance: + case RolloffFactor: + case ReferenceDistance: + case MinGain: + case MaxGain: + case ConeOuterGain: + case ConeInnerAngle: + case ConeOuterAngle: + case SecOffset: + case SampleOffset: + case ByteOffset: + len = 1; + break; + case Position: + case Velocity: + case Direction: + len = 3; + break; + default: + len = 0; + break; + } + + values = new float[len]; + + GCHandle arrayHandle = GCHandle.Alloc(values, GCHandleType.Pinned); + _GetSourcefv(sid, param, arrayHandle.AddrOfPinnedObject()); + arrayHandle.Free(); + } + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetSourcei")] + public static extern void GetSourcei(uint sid, int param, out int value); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetSource3i")] + public static extern void GetSource3i(uint sid, int param, out int value1, out int value2, out int value3); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetSourceiv")] + private static extern void _GetSourceiv(uint sid, int param, IntPtr values); + + public static void GetSourceiv(uint sid, int param, out int[] values) + { + int len; + switch(param) + { + case MaxDistance: + case RolloffFactor: + case ReferenceDistance: + case ConeInnerAngle: + case ConeOuterAngle: + case SourceRelative: + case SourceType: + case Looping: + case Buffer: + case SourceState: + case BuffersQueued: + case BuffersProcessed: + case SecOffset: + case SampleOffset: + case ByteOffset: + len = 1; + break; + case Direction: + len = 3; + break; + default: + len = 0; + break; + } + + values = new int[len]; + + GCHandle arrayHandle = GCHandle.Alloc(values, GCHandleType.Pinned); + _GetSourceiv(sid, param, arrayHandle.AddrOfPinnedObject()); + arrayHandle.Free(); + } + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alSourcePlayv")] + public static extern void SourcePlayv(int ns, uint[] sids); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alSourceStopv")] + public static extern void SourceStopv(int ns, uint[] sids); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alSourceRewindv")] + public static extern void SourceRewindv(int ns, uint[] sids); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alSourcePausev")] + public static extern void SourcePausev(int ns, uint[] sids); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alSourcePlay")] + public static extern void SourcePlay(uint sid); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alSourceStop")] + public static extern void SourceStop(uint sid); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alSourceRewind")] + public static extern void SourceRewind(uint sid); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alSourcePause")] + public static extern void SourcePause(uint sid); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alSourceQueueBuffers")] + public static extern void SourceQueueBuffers(uint sid, int numEntries, uint[] bids); + + public static void SourceQueueBuffer(uint sid, uint bid) + { + uint[] bids = new uint[1]; bids[0] = bid; + SourceQueueBuffers(sid, 1, bids); + } + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alSourceUnqueueBuffers")] + public static extern void SourceUnqueueBuffers(uint sid, int numEntries, uint[] bids); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGenBuffers")] + private static extern void _GenBuffers(int n, IntPtr buffers); + + public static void GenBuffers(int n, out uint[] buffers) + { + buffers = new uint[n]; + + GCHandle arrayHandle = GCHandle.Alloc(buffers, GCHandleType.Pinned); + _GenBuffers(n, arrayHandle.AddrOfPinnedObject()); + arrayHandle.Free(); + } + + public static void GenBuffer(out uint buffer) + { + GenBuffers(1, out var buffers); + buffer = buffers[0]; + } + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alDeleteBuffers")] + public static extern void DeleteBuffers(int n, uint[] buffers); + + public static void DeleteBuffer(uint buffer) => DeleteBuffers(1, new[] {buffer}); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alIsBuffer")] + public static extern bool IsBuffer(uint bid); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alBufferData")] + public static extern void BufferData(uint bid, int format, IntPtr data, int size, int freq); + + public static void BufferData(uint bid, int format, T[] data, int len, int freq) + { + GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); + BufferData(bid, format, handle.AddrOfPinnedObject(), len, freq); + handle.Free(); + } + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alBufferi")] + public static extern void Bufferi(uint bid, int param, int value); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alGetBufferi")] + public static extern void GetBufferi(uint bid, int param, out int value); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alDopplerFactor")] + public static extern void DopplerFactor(float value); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alDopplerVelocity")] + public static extern void DopplerVelocity(float value); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alSpeedOfSound")] + public static extern void SpeedOfSound(float value); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alDistanceModel")] + public static extern void DistanceModel(int distanceModel); + + #endregion + } +} diff --git a/Barotrauma/BarotraumaClient/Source/Sounds/OpenAL/Alc.cs b/Barotrauma/BarotraumaClient/Source/Sounds/OpenAL/Alc.cs new file mode 100644 index 000000000..665c2c54a --- /dev/null +++ b/Barotrauma/BarotraumaClient/Source/Sounds/OpenAL/Alc.cs @@ -0,0 +1,220 @@ +/*** + +MIT License + +Copyright (c) 2018 Nathan Glover + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +**************** + +Further modified for use in Barotrauma. +Original source code at https://github.com/NathanielGlover/OpenAL.NETCore/ + +***/ + +using System; +using System.Runtime.InteropServices; +using System.Collections.Generic; +using System.Text; + +namespace OpenAL +{ + public class Alc + { +#if OSX + public const string OpenAlDll = "/System/Library/Frameworks/OpenAL.framework/OpenAL"; +#elif LINUX + public const string OpenAlDll = "libopenal.so.1"; +#elif WINDOWS +#if X86 + public const string OpenAlDll = "soft_oal_x86.dll"; +#elif X64 + public const string OpenAlDll = "soft_oal_x64.dll"; +#endif +#endif + + #region Enum + + public const int False = 0; + public const int True = 1; + public const int Frequency = 0x1007; + public const int Refresh = 0x1008; + public const int Sync = 0x1009; + public const int MonoSources = 0x1010; + public const int StereoSources = 0x1011; + public const int NoError = False; + public const int InvalidDevice = 0xA001; + public const int InvalidContext = 0xA002; + public const int InvalidEnum = 0xA003; + public const int InvalidValue = 0xA004; + public const int OutOfMemory = 0xA005; + public const int DefaultDeviceSpecifier = 0x1004; + public const int DeviceSpecifier = 0x1005; + public const int Extensions = 0x1006; + public const int MajorVersion = 0x1000; + public const int MinorVersion = 0x1001; + public const int AttributesSize = 0x1002; + public const int AllAttributes = 0x1003; + public const int DefaultAllDevicesSpecifier = 0x1012; + public const int AllDevicesSpecifier = 0x1013; + public const int CaptureDeviceSpecifier = 0x310; + public const int CaptureDefaultDeviceSpecifier = 0x311; + public const int EnumCaptureSamples = 0x312; + + #endregion + + #region Context Management Functions + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcCreateContext")] + private static extern IntPtr _CreateContext(IntPtr device, IntPtr attrlist); + + public static IntPtr CreateContext(IntPtr device, int[] attrList) + { + GCHandle handle = GCHandle.Alloc(attrList, GCHandleType.Pinned); + IntPtr retVal = _CreateContext(device, handle.AddrOfPinnedObject()); + handle.Free(); + return retVal; + } + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcMakeContextCurrent")] + public static extern bool MakeContextCurrent(IntPtr context); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcProcessContext")] + public static extern void ProcessContext(IntPtr context); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcSuspendContext")] + public static extern void SuspendContext(IntPtr context); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcDestroyContext")] + public static extern void DestroyContext(IntPtr context); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcGetCurrentContext")] + public static extern IntPtr GetCurrentContext(); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcGetContextsDevice")] + public static extern IntPtr GetContextsDevice(IntPtr context); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcOpenDevice")] + public static extern IntPtr OpenDevice(string deviceName); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcCloseDevice")] + public static extern bool CloseDevice(IntPtr device); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcGetError")] + public static extern int GetError(IntPtr device); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcIsExtensionPresent")] + public static extern bool IsExtensionPresent(IntPtr device, string extname); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcGetProcAddress")] + public static extern IntPtr GetProcAddress(IntPtr device, string funcname); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcGetEnumValue")] + public static extern int GetEnumValue(IntPtr device, string enumname); + + #endregion + + #region Query Functions + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcGetString")] + private static extern IntPtr _GetString(IntPtr device, int param); + + public static string GetString(IntPtr device, int param) + { + IntPtr strPtr = _GetString(device, param); + int strLen = 0; + while (Marshal.ReadByte(strPtr,strLen)!='\0') { strLen++; } + byte[] bytes = new byte[strLen]; + Marshal.Copy(strPtr, bytes, 0, strLen); + return Encoding.UTF8.GetString(bytes); + } + + public static IList GetStringList(IntPtr device, int param) + { + List retVal = new List(); + IntPtr strPtr = _GetString(device, param); + int strStart = 0; + int strEnd = 0; + byte currChar = Marshal.ReadByte(strPtr, strEnd); + if (currChar == '\0') { return retVal; } + byte prevChar = 255; + while (true) { + strEnd++; + prevChar = currChar; + currChar = Marshal.ReadByte(strPtr, strEnd); + + if (currChar == '\0') + { + if (prevChar == '\0') + { + break; + } + byte[] bytes = new byte[strEnd-strStart]; + Marshal.Copy(strPtr+strStart, bytes, 0, strEnd - strStart); + retVal.Add(Encoding.UTF8.GetString(bytes)); + strStart = strEnd+1; + } + } + return retVal; + } + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcGetIntegerv")] + public static extern void GetIntegerv(IntPtr device, int param, int size, IntPtr data); + + public static void GetInteger(IntPtr device, int param, out int data) + { + int[] dataArr = new int[1]; + GCHandle handle = GCHandle.Alloc(dataArr,GCHandleType.Pinned); + GetIntegerv(device, param, 1, handle.AddrOfPinnedObject()); + handle.Free(); + data = dataArr[0]; + } + + #endregion + + #region Capture Functions + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcCaptureOpenDevice")] + private static extern IntPtr CaptureOpenDevice(IntPtr devicename, uint frequency, int format, int buffersize); + + public static IntPtr CaptureOpenDevice(string devicename, uint frequency, int format, int buffersize) + { + byte[] devicenameBytes = Encoding.UTF8.GetBytes(devicename); + GCHandle devicenameHandle = GCHandle.Alloc(devicenameBytes, GCHandleType.Pinned); + IntPtr retVal = CaptureOpenDevice(devicenameHandle.AddrOfPinnedObject(), frequency, format, buffersize); + devicenameHandle.Free(); + return retVal; + } + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcCaptureCloseDevice")] + public static extern bool CaptureCloseDevice(IntPtr device); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcCaptureStart")] + public static extern void CaptureStart(IntPtr device); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcCaptureStop")] + public static extern void CaptureStop(IntPtr device); + + [DllImport(OpenAlDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "alcCaptureSamples")] + public static extern void CaptureSamples(IntPtr device, IntPtr buffer, int samples); + + #endregion + } +} diff --git a/Barotrauma/BarotraumaClient/Source/Utils/OpenFileDialog.cs b/Barotrauma/BarotraumaClient/Source/Utils/OpenFileDialog.cs new file mode 100644 index 000000000..b7e5dba5c --- /dev/null +++ b/Barotrauma/BarotraumaClient/Source/Utils/OpenFileDialog.cs @@ -0,0 +1,74 @@ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace Barotrauma +{ + public class OpenFileDialog + { + private System.Windows.Forms.OpenFileDialog ofd; + + public bool Multiselect; + public string InitialDirectory; + public string Filter; + public string Title; + public string FileName { get; private set; } + public string[] FileNames { get; private set; } + + public OpenFileDialog() + { + ofd = new System.Windows.Forms.OpenFileDialog(); + } + + public System.Windows.Forms.DialogResult ShowDialog() + { + ofd.Multiselect = Multiselect; + ofd.InitialDirectory = InitialDirectory; + ofd.Filter = Filter; + ofd.Title = Title; + +#if LINUX + var wrapperForm = new WrapperForm(ofd); + System.Windows.Forms.Application.Run(wrapperForm); + System.Windows.Forms.Application.Exit(); + FileName = wrapperForm.FileName; + FileNames = wrapperForm.FileNames; + return wrapperForm.Result; +#else + var result = ofd.ShowDialog(); + FileName = ofd.FileName; + FileNames = ofd.FileNames; + return result; +#endif + } + +#if LINUX + private class WrapperForm : System.Windows.Forms.Form + { + private System.Windows.Forms.OpenFileDialog ofd; + + public System.Windows.Forms.DialogResult Result { get; private set; } + public string FileName { get; private set; } + public string[] FileNames { get; private set; } + + public WrapperForm(System.Windows.Forms.OpenFileDialog dialog) + { + ofd = dialog; + Load += WrapperForm_Load; + } + + private void WrapperForm_Load(object sender, EventArgs e) + { + Result = ofd.ShowDialog(); + FileName = ofd.FileName; + FileNames = ofd.FileNames; + System.Threading.Thread.Sleep(100); + this.Close(); + } + } +#endif + } +} diff --git a/Barotrauma/BarotraumaClient/System.Windows.Forms.dll b/Barotrauma/BarotraumaClient/System.Windows.Forms.dll new file mode 100644 index 000000000..6338b395f Binary files /dev/null and b/Barotrauma/BarotraumaClient/System.Windows.Forms.dll differ diff --git a/Barotrauma/BarotraumaClient/System.Windows.Forms.dll.config b/Barotrauma/BarotraumaClient/System.Windows.Forms.dll.config new file mode 100644 index 000000000..54c6fd39c --- /dev/null +++ b/Barotrauma/BarotraumaClient/System.Windows.Forms.dll.config @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Barotrauma/BarotraumaClient/WindowsClient.csproj b/Barotrauma/BarotraumaClient/WindowsClient.csproj index 3466d3dd7..dc6b33c63 100644 --- a/Barotrauma/BarotraumaClient/WindowsClient.csproj +++ b/Barotrauma/BarotraumaClient/WindowsClient.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.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 ---------------------------------------------------------------------------------------------------------