diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterHUD.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterHUD.cs index 4f7210ae1..2f2b23ece 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterHUD.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterHUD.cs @@ -94,7 +94,7 @@ namespace Barotrauma { if (character.Info != null && !character.ShouldLockHud()) { - bool mouseOnPortrait = HUDLayoutSettings.PortraitArea.Contains(PlayerInput.MousePosition) && GUI.MouseOn == null; + bool mouseOnPortrait = HUDLayoutSettings.BottomRightInfoArea.Contains(PlayerInput.MousePosition) && GUI.MouseOn == null; if (mouseOnPortrait && PlayerInput.PrimaryMouseButtonClicked()) { CharacterHealth.OpenHealthWindow = character.CharacterHealth; @@ -300,16 +300,21 @@ namespace Barotrauma { if (CharacterHealth.OpenHealthWindow == null && character.SelectedCharacter == null) { - if (character.Info != null) + if (character.Info != null && !character.ShouldLockHud()) { character.Info.DrawBackground(spriteBatch); - character.Info.DrawJobIcon(spriteBatch, scale: 1.25f); + character.Info.DrawJobIcon(spriteBatch, + new Rectangle( + (int)(HUDLayoutSettings.BottomRightInfoArea.X + HUDLayoutSettings.BottomRightInfoArea.Width * 0.05f), + (int)(HUDLayoutSettings.BottomRightInfoArea.Y + HUDLayoutSettings.BottomRightInfoArea.Height * 0.1f), + (int)(HUDLayoutSettings.BottomRightInfoArea.Width / 2), + (int)(HUDLayoutSettings.BottomRightInfoArea.Height * 0.7f))); character.Info.DrawPortrait(spriteBatch, HUDLayoutSettings.PortraitArea.Location.ToVector2(), new Vector2((int)(-4 * GUI.Scale), (int)(2 * GUI.Scale)), targetWidth: HUDLayoutSettings.PortraitArea.Width, true); } - mouseOnPortrait = HUDLayoutSettings.PortraitArea.Contains(PlayerInput.MousePosition) && !character.ShouldLockHud(); + mouseOnPortrait = HUDLayoutSettings.BottomRightInfoArea.Contains(PlayerInput.MousePosition) && !character.ShouldLockHud(); if (mouseOnPortrait) { - GUI.UIGlow.Draw(spriteBatch, HUDLayoutSettings.PortraitArea, GUI.Style.Green * 0.5f); + GUI.UIGlow.Draw(spriteBatch, HUDLayoutSettings.BottomRightInfoArea, GUI.Style.Green * 0.5f); } } if (ShouldDrawInventory(character)) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterInfo.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterInfo.cs index a21fcc04e..9758686d7 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterInfo.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterInfo.cs @@ -12,21 +12,12 @@ namespace Barotrauma { public const float BgScale = 1.2f; private static Sprite infoAreaPortraitBG; - private static Vector2 infoBGPosition; - private static Vector2 jobIconPos; public static void Init() { - GameMain.Instance.OnResolutionChanged += SetUILayout; infoAreaPortraitBG = new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(833, 298, 142, 98), null, 0); - SetUILayout(); } - private static void SetUILayout() - { - jobIconPos = HUDLayoutSettings.BottomRightInfoArea.Center.ToVector2() + new Vector2(12 * GUI.Scale, 24 * GUI.Scale); - infoBGPosition = HUDLayoutSettings.BottomRightInfoArea.Location.ToVector2(); - } public GUIFrame CreateInfoFrame(GUIFrame frame) { @@ -180,7 +171,7 @@ namespace Barotrauma public void DrawBackground(SpriteBatch spriteBatch) { - infoAreaPortraitBG.Draw(spriteBatch, infoBGPosition, Color.White, Vector2.Zero, 0.0f, + infoAreaPortraitBG.Draw(spriteBatch, HUDLayoutSettings.BottomRightInfoArea.Location.ToVector2(), Color.White, Vector2.Zero, 0.0f, scale: new Vector2( HUDLayoutSettings.BottomRightInfoArea.Width / (float)infoAreaPortraitBG.SourceRect.Width, HUDLayoutSettings.BottomRightInfoArea.Height / (float)infoAreaPortraitBG.SourceRect.Height)); @@ -232,11 +223,20 @@ namespace Barotrauma } } - public void DrawJobIcon(SpriteBatch spriteBatch, Vector2? pos = null, float scale = 1.0f) + public void DrawJobIcon(SpriteBatch spriteBatch, Vector2 pos, float scale = 1.0f) { - if (jobIcon == null) return; - float combinedScale = .5f * GUI.Scale * scale; - jobIcon.Draw(spriteBatch, pos ?? jobIconPos, Job.Prefab.UIColor, scale: combinedScale); + var icon = Job?.Prefab?.Icon; + if (icon == null) { return; } + icon.Draw(spriteBatch, pos, Job.Prefab.UIColor, scale: scale); + } + public void DrawJobIcon(SpriteBatch spriteBatch, Rectangle area) + { + var icon = Job?.Prefab?.Icon; + if (icon == null) { return; } + icon.Draw(spriteBatch, + area.Center.ToVector2(), + Job.Prefab.UIColor, + scale: Math.Min(area.Width / (float)icon.SourceRect.Width, area.Height / (float)icon.SourceRect.Height)); } private void DrawAttachmentSprite(SpriteBatch spriteBatch, WearableSprite attachment, Sprite head, Vector2 drawPos, float scale, float depthStep, SpriteEffects spriteEffects = SpriteEffects.None) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs index f6df55185..28ca04741 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs @@ -365,7 +365,11 @@ namespace Barotrauma { character = Create(speciesName, position, seed, null, true); character.ID = id; - character.ReadStatus(inc); + bool containsStatusData = inc.ReadBoolean(); + if (containsStatusData) + { + character.ReadStatus(inc); + } } else { @@ -380,7 +384,11 @@ namespace Barotrauma character = Create(speciesName, position, seed, info, GameMain.Client.ID != ownerId, hasAi); character.ID = id; character.TeamID = (TeamType)teamID; - character.ReadStatus(inc); + bool containsStatusData = inc.ReadBoolean(); + if (containsStatusData) + { + character.ReadStatus(inc); + } if (character.IsHuman && character.TeamID != TeamType.FriendlyNPC && !character.IsDead) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs index 70add5052..360e81399 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs @@ -24,7 +24,7 @@ namespace Barotrauma private float uiScale, inventoryScale; - private Alignment alignment = Alignment.Left; + private Alignment alignment = Alignment.Right; public Alignment Alignment { get { return alignment; } @@ -245,6 +245,23 @@ namespace Barotrauma set { healthBarPulsateTimer = MathHelper.Clamp(value, 0.0f, 10.0f); } } + private GUIFrame healthBarHolder; + private Point healthBarOffset + { + get + { + return new Point(5 - (int)Math.Ceiling(1 - 1 * GUI.Scale), (int)Math.Min(Math.Ceiling(17 * GUI.Scale), 20)); + } + } + + private Point healthBarSize + { + get + { + return new Point(healthBarHolder.Rect.Width - (int)Math.Ceiling(Math.Min(46 * GUI.Scale, 53)), (int)(healthBarHolder.Rect.Height - Math.Min(23 * GUI.Scale, 25)) / 2); + } + } + partial void InitProjSpecific(XElement element, Character character) { DisplayedVitality = MaxVitality; @@ -263,22 +280,38 @@ namespace Barotrauma bool horizontal = true; - healthBar = new GUIProgressBar(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.HealthBarArea, GUI.Canvas), - barSize: 1.0f, color: GUIColorSettings.HealthBarColorHigh, style: horizontal ? "GUIProgressBar" : "GUIProgressBarVertical") + healthBarHolder = new GUIFrame(new RectTransform(Point.Zero, GUI.Canvas), style: null) { - Enabled = true, - HoverCursor = CursorState.Hand, - IsHorizontal = horizontal - }; + HoverCursor = CursorState.Hand + }; - healthBarShadow = new GUIProgressBar(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.HealthBarArea, GUI.Canvas), - barSize: 1.0f, color: Color.Green, style: horizontal ? "GUIProgressBar" : "GUIProgressBarVertical", showFrame: false) + healthBarHolder.RectTransform.AbsoluteOffset = HUDLayoutSettings.HealthBarArea.Location; + healthBarHolder.RectTransform.NonScaledSize = HUDLayoutSettings.HealthBarArea.Size; + healthBarHolder.RectTransform.RelativeOffset = Vector2.Zero; + + GUIFrame healthBarBG = new GUIFrame(new RectTransform(Vector2.One, healthBarHolder.RectTransform), style: "CharacterHealthBarBG") + { + CanBeFocused = false + }; + + healthBarShadow = new GUIProgressBar(new RectTransform(healthBarSize, healthBarHolder.RectTransform, Anchor.BottomRight), + barSize: 1.0f, color: Color.Green, style: horizontal ? "CharacterHealthBarSlider" : "GUIProgressBarVertical", showFrame: false) { IsHorizontal = horizontal }; healthBarShadow.Visible = false; healthShadowSize = 1.0f; + healthBar = new GUIProgressBar(new RectTransform(healthBarSize, healthBarHolder.RectTransform, Anchor.BottomRight), + barSize: 1.0f, color: GUIColorSettings.HealthBarColorHigh, style: horizontal ? "CharacterHealthBarSlider" : "GUIProgressBarVertical", showFrame: false) + { + HoverCursor = CursorState.Hand, + Enabled = true, + IsHorizontal = horizontal + }; + + healthBar.RectTransform.AbsoluteOffset = healthBarShadow.RectTransform.AbsoluteOffset = healthBarOffset; + healthInterfaceFrame = new GUIFrame(new RectTransform(new Vector2(0.7f, 0.55f), GUI.Canvas, anchor: Anchor.Center, scaleBasis: ScaleBasis.Smallest), style: "ItemUI"); var healthInterfaceLayout = new GUILayoutGroup(new RectTransform(Vector2.One / 1.05f, healthInterfaceFrame.RectTransform, anchor: Anchor.Center), true); @@ -379,10 +412,11 @@ namespace Barotrauma var textContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.6f), infoLayout.RectTransform), style: "GUIFrameListBox"); - var textLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 1.0f), textContainer.RectTransform, Anchor.Center, Pivot.Center)) + var textLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.98f), textContainer.RectTransform, Anchor.Center, Pivot.Center)) { Stretch = true, - RelativeSpacing = 0.03f + RelativeSpacing = 0.03f, + CanBeFocused = true }; var nameContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.2f), textLayout.RectTransform) { MinSize = new Point(0, 20) }, isHorizontal: true) @@ -390,16 +424,21 @@ namespace Barotrauma Stretch = true }; - new GUICustomComponent(new RectTransform(new Vector2(0.15f, 1.0f), nameContainer.RectTransform), + new GUICustomComponent(new RectTransform(new Vector2(0.2f, 1.0f), nameContainer.RectTransform), onDraw: (spriteBatch, component) => { - character.Info.DrawPortrait(spriteBatch, new Vector2(component.Rect.X, component.Rect.Center.Y - component.Rect.Width / 2), character.Info.Portrait.size * .25f, component.Rect.Width); - character.Info.DrawJobIcon(spriteBatch, new Vector2(component.Rect.Right + component.Rect.Width, (float)component.Rect.Top + component.Rect.Height * 0.75f), 0.75f); + character.Info.DrawPortrait(spriteBatch, new Vector2(component.Rect.X, component.Rect.Center.Y - component.Rect.Width / 2), Vector2.Zero, component.Rect.Width); }); - characterName = new GUITextBlock(new RectTransform(new Vector2(0.85f, 1.0f), nameContainer.RectTransform), "", textAlignment: Alignment.BottomLeft, font: GUI.SubHeadingFont) + characterName = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), nameContainer.RectTransform), "", textAlignment: Alignment.CenterLeft, font: GUI.SubHeadingFont) { AutoScaleHorizontal = true }; + new GUICustomComponent(new RectTransform(new Vector2(0.2f, 1.0f), nameContainer.RectTransform), + onDraw: (spriteBatch, component) => + { + character.Info.DrawJobIcon(spriteBatch, component.Rect); + }); + new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), textLayout.RectTransform), style: "HorizontalLine"); @@ -482,7 +521,7 @@ namespace Barotrauma UpdateAlignment(); suicideButton = new GUIButton(new RectTransform(new Vector2(0.06f, 0.02f), GUI.Canvas, Anchor.TopCenter) - { MinSize = new Point(120, 20), RelativeOffset = new Vector2(0.0f, 0.01f) }, + { MinSize = new Point(150, 20), RelativeOffset = new Vector2(0.0f, 0.01f) }, TextManager.Get("GiveInButton"), style: "GUIButtonLarge") { ToolTip = TextManager.Get(GameMain.NetworkMember == null ? "GiveInHelpSingleplayer" : "GiveInHelpMultiplayer"), @@ -505,6 +544,7 @@ namespace Barotrauma return true; } }; + suicideButton.TextBlock.AutoScaleHorizontal = true; if (element != null) { @@ -545,13 +585,12 @@ namespace Barotrauma inventoryScale = Inventory.UIScale; uiScale = GUI.Scale; - healthBar.RectTransform.AbsoluteOffset = HUDLayoutSettings.HealthBarArea.Location; - healthBar.RectTransform.NonScaledSize = HUDLayoutSettings.HealthBarArea.Size; - healthBar.RectTransform.RelativeOffset = Vector2.Zero; + healthBarHolder.RectTransform.AbsoluteOffset = HUDLayoutSettings.HealthBarArea.Location; + healthBarHolder.RectTransform.NonScaledSize = HUDLayoutSettings.HealthBarArea.Size; + healthBarHolder.RectTransform.RelativeOffset = Vector2.Zero; - healthBarShadow.RectTransform.AbsoluteOffset = HUDLayoutSettings.HealthBarArea.Location; - healthBarShadow.RectTransform.NonScaledSize = HUDLayoutSettings.HealthBarArea.Size; - healthBarShadow.RectTransform.RelativeOffset = Vector2.Zero; + healthBar.RectTransform.NonScaledSize = healthBarShadow.RectTransform.NonScaledSize = healthBarSize; + healthBar.RectTransform.AbsoluteOffset = healthBarShadow.RectTransform.AbsoluteOffset = healthBarOffset; switch (alignment) { @@ -633,7 +672,7 @@ namespace Barotrauma return; } } - + bool forceAfflictionContainerUpdate = false; if (updateDisplayedAfflictionsTimer > 0.0f) { @@ -882,7 +921,7 @@ namespace Barotrauma Rectangle hoverArea = Rectangle.Union(HUDLayoutSettings.AfflictionAreaLeft, HUDLayoutSettings.HealthBarArea); - healthBar.CanBeFocused = healthBarShadow.CanBeFocused = !Character.ShouldLockHud(); + healthBarHolder.CanBeFocused = healthBar.CanBeFocused = healthBarShadow.CanBeFocused = !Character.ShouldLockHud(); if (Character.AllowInput && UseHealthWindow && healthBar.Enabled && healthBar.CanBeFocused && hoverArea.Contains(PlayerInput.MousePosition) && Inventory.SelectedSlot == null) { @@ -924,8 +963,7 @@ namespace Barotrauma } else if (Character.Controlled == Character) { - healthBarShadow.AddToGUIUpdateList(); - healthBar.AddToGUIUpdateList(); + healthBarHolder.AddToGUIUpdateList(); } if (suicideButton.Visible && Character == Character.Controlled) suicideButton.AddToGUIUpdateList(); if (cprButton != null && cprButton.Visible) cprButton.AddToGUIUpdateList(); @@ -963,6 +1001,9 @@ namespace Barotrauma { healthBar.RectTransform.ScreenSpaceOffset = healthBarShadow.RectTransform.ScreenSpaceOffset = Point.Zero; } + + // If manning a turret the portrait doesn't get rendered so we push the health bar to remove the empty gap + healthBarHolder.RectTransform.ScreenSpaceOffset = Character.ShouldLockHud() ? new Point(0, HUDLayoutSettings.PortraitArea.Height) : Point.Zero; DrawStatusHUD(spriteBatch); } @@ -970,7 +1011,7 @@ namespace Barotrauma public void DrawStatusHUD(SpriteBatch spriteBatch) { //Rectangle interactArea = healthBar.Rect; - if (Character.Controlled?.SelectedCharacter == null) + if (Character.Controlled?.SelectedCharacter == null && openHealthWindow == null) { List> statusIcons = new List>(); if (Character.CurrentHull == null || Character.CurrentHull.LethalPressure > 5.0f) @@ -987,6 +1028,12 @@ namespace Barotrauma Vector2 highlightedIconPos = Vector2.Zero; Rectangle afflictionArea = HUDLayoutSettings.AfflictionAreaLeft; + // Push the icons down since the portrait doesn't get rendered + if (Character.ShouldLockHud()) + { + afflictionArea.Y += HUDLayoutSettings.PortraitArea.Height; + } + bool horizontal = afflictionArea.Width > afflictionArea.Height; int iconSize = horizontal ? afflictionArea.Height : afflictionArea.Width; @@ -1001,14 +1048,14 @@ namespace Barotrauma if (afflictionIconRect.Contains(PlayerInput.MousePosition) && !Character.ShouldLockHud()) { highlightedIcon = statusIcon; - highlightedIconPos = afflictionIconRect.Center.ToVector2(); + highlightedIconPos = afflictionIconRect.Location.ToVector2(); } if (affliction.DamagePerSecond > 1.0f) { Rectangle glowRect = afflictionIconRect; - glowRect.Inflate((int)(25 * GUI.Scale), (int)(25 * GUI.Scale)); - var glow = GUI.Style.GetComponentStyle("OuterGlow"); + glowRect.Inflate((int)(20 * GUI.Scale), (int)(20 * GUI.Scale)); + var glow = GUI.Style.GetComponentStyle("OuterGlowCircular"); glow.Sprites[GUIComponent.ComponentState.None][0].Draw( spriteBatch, glowRect, GUI.Style.Red * (float)((Math.Sin(affliction.DamagePerSecondTimer * MathHelper.TwoPi - MathHelper.PiOver2) + 1.0f) * 0.5f)); @@ -1037,9 +1084,12 @@ namespace Barotrauma if (highlightedIcon != null) { + string nameTooltip = highlightedIcon.Second; + Vector2 offset = GUI.Font.MeasureString(nameTooltip); + GUI.DrawString(spriteBatch, - alignment == Alignment.Left ? highlightedIconPos + new Vector2(60 * GUI.Scale, 5) : highlightedIconPos + new Vector2(iconSize * 0.4f, 0.0f), - highlightedIcon.Second, + alignment == Alignment.Left ? highlightedIconPos + offset : highlightedIconPos - offset, + nameTooltip, Color.White * 0.8f, Color.Black * 0.5f); } @@ -1258,7 +1308,8 @@ namespace Barotrauma var afflictionName = new GUITextBlock(new RectTransform(new Vector2(0.65f, 1.0f), labelContainer.RectTransform), affliction.Prefab.Name, textAlignment: Alignment.CenterLeft, font: GUI.LargeFont) { - CanBeFocused = false + CanBeFocused = false, + AutoScaleHorizontal = true }; var afflictionStrength = new GUITextBlock(new RectTransform(new Vector2(0.35f, 0.6f), labelContainer.RectTransform), "", textAlignment: Alignment.TopRight, font: GUI.SubHeadingFont) { @@ -1286,13 +1337,15 @@ namespace Barotrauma Point nameDims = new Point(afflictionName.Rect.Width, (int)(GUI.LargeFont.Size * 1.5f)); - labelContainer.RectTransform.Resize(new Point(labelContainer.Rect.Width, nameDims.Y)); - afflictionName.RectTransform.Resize(nameDims); - afflictionStrength.RectTransform.Resize(new Point(afflictionStrength.Rect.Width, nameDims.Y)); - afflictionStrength.Text = strengthTexts[ MathHelper.Clamp((int)Math.Floor((affliction.Strength / affliction.Prefab.MaxStrength) * strengthTexts.Length), 0, strengthTexts.Length - 1)]; + Vector2 strengthDims = GUI.SubHeadingFont.MeasureString(afflictionStrength.Text); + + labelContainer.RectTransform.Resize(new Point(labelContainer.Rect.Width, nameDims.Y)); + afflictionName.RectTransform.Resize(new Point((int)(labelContainer.Rect.Width - strengthDims.X * 0.99f), nameDims.Y)); + afflictionStrength.RectTransform.Resize(new Point(labelContainer.Rect.Width - afflictionName.Rect.Width, nameDims.Y)); + afflictionStrength.TextColor = Color.Lerp(GUI.Style.Orange, GUI.Style.Red, affliction.Strength / affliction.Prefab.MaxStrength); @@ -1815,8 +1868,7 @@ namespace Barotrauma public void SetHealthBarVisibility(bool value) { - healthBar.Visible = value; - healthBarShadow.Visible = value; + healthBarHolder.Visible = value; } public void ClientRead(IReadMessage inc) @@ -1826,9 +1878,16 @@ namespace Barotrauma byte afflictionCount = inc.ReadByte(); for (int i = 0; i < afflictionCount; i++) { - AfflictionPrefab afflictionPrefab = AfflictionPrefab.Prefabs[inc.ReadString()]; + uint afflictionID = inc.ReadUInt32(); + AfflictionPrefab afflictionPrefab = AfflictionPrefab.Prefabs.Find(p => p.UIntIdentifier == afflictionID); + if (afflictionPrefab == null) + { + DebugConsole.ThrowError("Error while reading character health data: affliction with the uint ID " + afflictionID + " not found."); + //read the 8 bytes for affliction strength anyway to prevent messing up reading rest of the message + _ = inc.ReadRangedSingle(0.0f, 100.0f, 8); + continue; + } float afflictionStrength = inc.ReadRangedSingle(0.0f, afflictionPrefab.MaxStrength, 8); - newAfflictions.Add(new Pair(afflictionPrefab, afflictionStrength)); } @@ -1860,9 +1919,16 @@ namespace Barotrauma for (int i = 0; i < limbAfflictionCount; i++) { int limbIndex = inc.ReadRangedInteger(0, limbHealths.Count - 1); - AfflictionPrefab afflictionPrefab = AfflictionPrefab.Prefabs[inc.ReadString()]; + uint afflictionID = inc.ReadUInt32(); + AfflictionPrefab afflictionPrefab = AfflictionPrefab.Prefabs.Find(p => p.UIntIdentifier == afflictionID); + if (afflictionPrefab == null) + { + DebugConsole.ThrowError("Error while reading character health data: affliction with the uint ID " + afflictionID + " not found."); + //read the 8 bytes for affliction strength anyway to prevent messing up reading rest of the message + _ = inc.ReadRangedSingle(0.0f, 100.0f, 8); + continue; + } float afflictionStrength = inc.ReadRangedSingle(0.0f, afflictionPrefab.MaxStrength, 8); - newLimbAfflictions.Add(new Triplet(limbHealths[limbIndex], afflictionPrefab, afflictionStrength)); } diff --git a/Barotrauma/BarotraumaClient/ClientSource/DebugConsole.cs b/Barotrauma/BarotraumaClient/ClientSource/DebugConsole.cs index 4a3cac799..70b15fe92 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/DebugConsole.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/DebugConsole.cs @@ -446,6 +446,7 @@ namespace Barotrauma AssignRelayToServer("verboselogging", false); AssignRelayToServer("freecam", false); #if DEBUG + AssignRelayToServer("crash", false); AssignRelayToServer("simulatedlatency", false); AssignRelayToServer("simulatedloss", false); AssignRelayToServer("simulatedduplicateschance", false); @@ -1184,7 +1185,6 @@ namespace Barotrauma GameMain.Client.PrintReceiverTransters(); })); - commands.Add(new Command("spamchatmessages", "", (string[] args) => { int msgCount = 1000; diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/ChatBox.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/ChatBox.cs index 0bc04763b..d3e45860b 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/ChatBox.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/ChatBox.cs @@ -88,6 +88,16 @@ namespace Barotrauma InputBox.OnDeselected += (gui, Keys) => { ChatManager.Clear(); + ChatMessage.GetChatMessageCommand(InputBox.Text, out var message); + if (string.IsNullOrEmpty(message)) + { + if (CloseAfterMessageSent) + { + _toggleOpen = false; + CloseAfterMessageSent = false; + } + } + //gui.Text = ""; }; diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs index 4ab4c2ca3..e03665277 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs @@ -133,6 +133,7 @@ namespace Barotrauma public static ScalableFont LargeFont => Style?.LargeFont; public static ScalableFont SubHeadingFont => Style?.SubHeadingFont; public static ScalableFont DigitalFont => Style?.DigitalFont; + public static ScalableFont HotkeyFont => Style?.HotkeyFont; public static ScalableFont CJKFont { get; private set; } @@ -802,14 +803,19 @@ namespace Barotrauma case CharacterEditorScreen editor: return editor.GetMouseCursorState(); // Portrait area during gameplay - case GameScreen _ when HUDLayoutSettings.PortraitArea.Contains(PlayerInput.MousePosition) && !(Character.Controlled?.ShouldLockHud() ?? true): - return CursorState.Hand; + case GameScreen _ when !(Character.Controlled?.ShouldLockHud() ?? true): + if (HUDLayoutSettings.BottomRightInfoArea.Contains(PlayerInput.MousePosition) || + Rectangle.Union(HUDLayoutSettings.AfflictionAreaLeft, HUDLayoutSettings.HealthBarArea).Contains(PlayerInput.MousePosition)) + { + return CursorState.Hand; + } + break; // Sub editor drag and highlight case SubEditorScreen editor: { // Portrait area if ((editor.CharacterMode || editor.WiringMode) && - HUDLayoutSettings.PortraitArea.Contains(PlayerInput.MousePosition)) + HUDLayoutSettings.BottomRightInfoArea.Contains(PlayerInput.MousePosition)) { return CursorState.Hand; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIButton.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIButton.cs index f866a16b6..42bcfd05b 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIButton.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIButton.cs @@ -171,6 +171,14 @@ namespace Barotrauma TextBlock.SetTextPos(); } GUI.Style.Apply(textBlock, "", this); + + //if the text is in chinese/korean/japanese and we're not using a CJK-compatible font, + //use the default CJK font as a fallback + if (TextManager.IsCJK(textBlock.Text) && !textBlock.Font.IsCJK) + { + textBlock.Font = GUI.CJKFont; + } + Enabled = true; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIStyle.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIStyle.cs index 9d14505ed..96191e3be 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIStyle.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIStyle.cs @@ -24,6 +24,7 @@ namespace Barotrauma public ScalableFont LargeFont { get; private set; } public ScalableFont SubHeadingFont { get; private set; } public ScalableFont DigitalFont { get; private set; } + public ScalableFont HotkeyFont { get; private set; } public Dictionary ForceFontUpperCase { @@ -148,6 +149,10 @@ namespace Barotrauma DigitalFont = LoadFont(subElement, graphicsDevice); ForceFontUpperCase[DigitalFont] = subElement.GetAttributeBool("forceuppercase", false); break; + case "hotkeyfont": + HotkeyFont = LoadFont(subElement, graphicsDevice); + ForceFontUpperCase[HotkeyFont] = subElement.GetAttributeBool("forceuppercase", false); + break; case "objectivetitle": case "subheading": SubHeadingFont = LoadFont(subElement, graphicsDevice); @@ -209,6 +214,10 @@ namespace Barotrauma if (LargeFont == null) { continue; } LargeFont.Size = GetFontSize(subElement); break; + case "hotkeyfont": + if (HotkeyFont == null) { continue; } + HotkeyFont.Size = GetFontSize(subElement); + break; case "objectivetitle": case "subheading": if (SubHeadingFont == null) { continue; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/HUDLayoutSettings.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/HUDLayoutSettings.cs index 99016a02f..a67480d28 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/HUDLayoutSettings.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/HUDLayoutSettings.cs @@ -119,11 +119,10 @@ namespace Barotrauma PortraitArea = new Rectangle(GameMain.GraphicsWidth - Padding - portraitSize, GameMain.GraphicsHeight - Padding - portraitSize, portraitSize, portraitSize); //horizontal slices at the corners of the screen for health bar and affliction icons - int healthBarHeight = (int)Math.Max(25f * GUI.Scale, 12.5f); int afflictionAreaHeight = (int)(50 * GUI.Scale); - int healthBarWidth = BottomRightInfoArea.Width; - //int healthBarWidth = (int)((BottomRightInfoArea.Width + CharacterInventory.SlotSize.X + CharacterInventory.Spacing) * 1.1f); - HealthBarArea = new Rectangle(BottomRightInfoArea.X, BottomRightInfoArea.Y - healthBarHeight - (int)(8 * GUI.Scale), healthBarWidth, healthBarHeight); + int healthBarWidth = (int)((BottomRightInfoArea.Width + CharacterInventory.SlotSize.X + CharacterInventory.Spacing) * 1.1f); + int healthBarHeight = (int)Math.Max(50f * GUI.Scale, 25f); + HealthBarArea = new Rectangle(BottomRightInfoArea.X - (healthBarWidth - BottomRightInfoArea.Width) + (int)(2 * GUI.Scale), BottomRightInfoArea.Y - healthBarHeight + (int)(10 * GUI.Scale), healthBarWidth, healthBarHeight); AfflictionAreaLeft = new Rectangle(HealthBarArea.X, HealthBarArea.Y - Padding - afflictionAreaHeight, HealthBarArea.Width, afflictionAreaHeight); //HealthBarAreaRight = new Rectangle(Padding, GameMain.GraphicsHeight - healthBarHeight - Padding, healthBarWidth, healthBarHeight); diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameMain.cs b/Barotrauma/BarotraumaClient/ClientSource/GameMain.cs index ed5021ac0..8d86b74b2 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameMain.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameMain.cs @@ -199,7 +199,17 @@ namespace Barotrauma ConnectEndpoint = null; ConnectLobby = 0; - ToolBox.ParseConnectCommand(ConsoleArguments, out ConnectName, out ConnectEndpoint, out ConnectLobby); + try + { + ToolBox.ParseConnectCommand(ConsoleArguments, out ConnectName, out ConnectEndpoint, out ConnectLobby); + } + catch (IndexOutOfRangeException e) + { + DebugConsole.ThrowError($"Failed to parse console arguments ({string.Join(' ', ConsoleArguments)})", e); + ConnectName = null; + ConnectEndpoint = null; + ConnectLobby = 0; + } GUI.KeyboardDispatcher = new EventInput.KeyboardDispatcher(Window); @@ -631,9 +641,21 @@ namespace Barotrauma public void OnInvitedToGame(string connectCommand) { - ToolBox.ParseConnectCommand(connectCommand.Split(' '), out ConnectName, out ConnectEndpoint, out ConnectLobby); + try + { + ToolBox.ParseConnectCommand(ToolBox.SplitCommand(connectCommand), out ConnectName, out ConnectEndpoint, out ConnectLobby); + } + catch (IndexOutOfRangeException e) + { +#if DEBUG + DebugConsole.ThrowError($"Failed to parse a Steam friend's connect invitation command ({connectCommand})", e); +#endif + ConnectName = null; + ConnectEndpoint = null; + ConnectLobby = 0; + } - DebugConsole.NewMessage(ConnectName+", "+ConnectEndpoint,Color.Yellow); + DebugConsole.NewMessage(ConnectName + ", " + ConnectEndpoint, Color.Yellow); } public void OnLobbyJoinRequested(Steamworks.Data.Lobby lobby, Steamworks.SteamId friendId) diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/CrewManager.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/CrewManager.cs index 42c753b22..9e87390d5 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/CrewManager.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/CrewManager.cs @@ -210,13 +210,17 @@ namespace Barotrauma #region Reports var chatBox = ChatBox ?? GameMain.Client?.ChatBox; - chatBox.ToggleButton = new GUIButton(new RectTransform(new Point((int)(182f * GUI.Scale * 0.4f), (int)(99f * GUI.Scale * 0.4f)), guiFrame.RectTransform), style: "ChatToggleButton"); - chatBox.ToggleButton.RectTransform.AbsoluteOffset = new Point(0, HUDLayoutSettings.ChatBoxArea.Height - chatBox.ToggleButton.Rect.Height); - chatBox.ToggleButton.OnClicked += (GUIButton btn, object userdata) => + if (chatBox != null) { - chatBox.ToggleOpen = !chatBox.ToggleOpen; - return true; - }; + chatBox.ToggleButton = new GUIButton(new RectTransform(new Point((int)(182f * GUI.Scale * 0.4f), (int)(99f * GUI.Scale * 0.4f)), guiFrame.RectTransform), style: "ChatToggleButton"); + chatBox.ToggleButton.RectTransform.AbsoluteOffset = new Point(0, HUDLayoutSettings.ChatBoxArea.Height - chatBox.ToggleButton.Rect.Height); + chatBox.ToggleButton.OnClicked += (GUIButton btn, object userdata) => + { + chatBox.ToggleOpen = !chatBox.ToggleOpen; + chatBox.CloseAfterMessageSent = false; + return true; + }; + } var reports = Order.PrefabList.FindAll(o => o.TargetAllCharacters && o.SymbolSprite != null); if (reports.None()) @@ -257,7 +261,7 @@ namespace Barotrauma ToolTip = order.Name }; - new GUIFrame(new RectTransform(new Vector2(1.5f), btn.RectTransform, Anchor.Center), "InnerGlowCircular") + new GUIFrame(new RectTransform(new Vector2(1.5f), btn.RectTransform, Anchor.Center), "OuterGlowCircular") { Color = GUI.Style.Red * 0.8f, HoverColor = GUI.Style.Red * 1.0f, @@ -728,18 +732,28 @@ namespace Barotrauma if (characterFrame == null) { return; } GUILayoutGroup layoutGroup = (GUILayoutGroup)characterFrame.FindChild(c => c is GUILayoutGroup); - layoutGroup.RemoveChild(GetPreviousOrderComponent(layoutGroup)); var currentOrderComponent = GetCurrentOrderComponent(layoutGroup); - if (order != null && currentOrderComponent != null) + if (order != null) { - var currentOrderInfo = (OrderInfo)currentOrderComponent.UserData; + var prevOrderComponent = GetPreviousOrderComponent(layoutGroup); + if (currentOrderComponent?.UserData is OrderInfo currentOrderInfo) + { + if (order.Identifier == currentOrderInfo.Order.Identifier && + option == currentOrderInfo.OrderOption && + order.TargetEntity == currentOrderInfo.Order.TargetEntity) { return; } - if (order.Identifier == currentOrderInfo.Order.Identifier && - option == currentOrderInfo.OrderOption && - order.TargetEntity == currentOrderInfo.Order.TargetEntity) { return; } - - DisplayPreviousCharacterOrder(character, layoutGroup, currentOrderInfo); + layoutGroup.RemoveChild(prevOrderComponent); + DisplayPreviousCharacterOrder(character, layoutGroup, currentOrderInfo); + } + else if (order.Identifier != dismissedOrderPrefab.Identifier && + prevOrderComponent?.UserData is OrderInfo prevOrderInfo && + order.Identifier == prevOrderInfo.Order.Identifier && + option == prevOrderInfo.OrderOption && + order.TargetEntity == prevOrderInfo.Order.TargetEntity) + { + layoutGroup.RemoveChild(prevOrderComponent); + } } layoutGroup.RemoveChild(currentOrderComponent); @@ -973,7 +987,7 @@ namespace Barotrauma if (PlayerInput.KeyDown(InputType.Command) && (GUI.KeyboardDispatcher.Subscriber == null || GUI.KeyboardDispatcher.Subscriber == crewList) && commandFrame == null && !clicklessSelectionActive && CanIssueOrders) { - CreateCommandUI(GUI.MouseOn?.UserData as Character); + CreateCommandUI(HUDLayoutSettings.PortraitArea.Contains(PlayerInput.MousePosition) ? Character.Controlled : GUI.MouseOn?.UserData as Character); clicklessSelectionActive = isOpeningClick = true; } @@ -1152,8 +1166,11 @@ namespace Barotrauma { ChatBox.InputBox.AddToGUIUpdateList(); ChatBox.GUIFrame.Flash(Color.DarkGreen, 0.5f); - ChatBox.CloseAfterMessageSent = !ChatBox.ToggleOpen; - ChatBox.ToggleOpen = true; + if (!ChatBox.ToggleOpen) + { + ChatBox.CloseAfterMessageSent = !ChatBox.ToggleOpen; + ChatBox.ToggleOpen = true; + } ChatBox.InputBox.Select(ChatBox.InputBox.Text.Length); } @@ -1161,8 +1178,11 @@ namespace Barotrauma { ChatBox.InputBox.AddToGUIUpdateList(); ChatBox.GUIFrame.Flash(Color.YellowGreen, 0.5f); - ChatBox.CloseAfterMessageSent = !ChatBox.ToggleOpen; - ChatBox.ToggleOpen = true; + if (!ChatBox.ToggleOpen) + { + ChatBox.CloseAfterMessageSent = !ChatBox.ToggleOpen; + ChatBox.ToggleOpen = true; + } if (!ChatBox.InputBox.Text.StartsWith(ChatBox.RadioChatString)) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/SinglePlayerCampaign.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/SinglePlayerCampaign.cs index aace0ea25..833b5693b 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/SinglePlayerCampaign.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/SinglePlayerCampaign.cs @@ -293,7 +293,7 @@ namespace Barotrauma summaryScreen.RemoveChild(summaryScreen.Children.FirstOrDefault(c => c is GUIButton)); - var okButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonArea.RectTransform), + var okButton = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonArea.RectTransform), TextManager.Get("LoadGameButton")) { OnClicked = (GUIButton button, object obj) => @@ -305,7 +305,7 @@ namespace Barotrauma } }; - var quitButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonArea.RectTransform), + var quitButton = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonArea.RectTransform), TextManager.Get("QuitButton")); quitButton.OnClicked += GameMain.LobbyScreen.QuitToMainMenu; quitButton.OnClicked += (GUIButton button, object obj) => diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/DoctorTutorial.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/DoctorTutorial.cs index a191ce067..28999e871 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/DoctorTutorial.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/DoctorTutorial.cs @@ -368,7 +368,10 @@ namespace Barotrauma.Tutorials { //Disabled pulse until it's replaced by a better effect //CharacterHealth.OpenHealthWindow.CPRButton.Pulsate(Vector2.One, Vector2.One * 1.5f, 1.0f); - CharacterHealth.OpenHealthWindow.CPRButton.Flash(); + if (CharacterHealth.OpenHealthWindow.CPRButton.FlashTimer <= 0.0f) + { + CharacterHealth.OpenHealthWindow.CPRButton.Flash(highlightColor); + } } yield return null; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/OfficerTutorial.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/OfficerTutorial.cs index 8354277d3..b11083859 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/OfficerTutorial.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/OfficerTutorial.cs @@ -124,6 +124,11 @@ namespace Barotrauma.Tutorials officer_gunIcon = gunOrder.SymbolSprite; officer_gunIconColor = gunOrder.Color; + var bandage = FindOrGiveItem(officer, "antibleeding1"); + bandage.Unequip(officer); + officer.Inventory.RemoveItem(bandage); + FindOrGiveItem(officer, "antibleeding1"); + // Other tutorial items tutorial_mechanicFinalDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_mechanicfinaldoorlight")).GetComponent(); tutorial_submarineSteering = Item.ItemList.Find(i => i.HasTag("command")).GetComponent(); @@ -200,6 +205,8 @@ namespace Barotrauma.Tutorials { while (GameMain.Instance.LoadingScreenOpen) yield return null; + yield return new WaitForSeconds(0.01f); + // Room 1 SoundPlayer.PlayDamageSound("StructureBlunt", 10, Character.Controlled.WorldPosition); while (shakeTimer > 0.0f) // Wake up, shake diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/ScenarioTutorial.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/ScenarioTutorial.cs index 40b0294db..8434baceb 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/ScenarioTutorial.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/ScenarioTutorial.cs @@ -302,11 +302,11 @@ namespace Barotrauma.Tutorials protected Item FindOrGiveItem(Character character, string identifier) { var item = character.Inventory.FindItemByIdentifier(identifier); - if (item != null) { return item; } + if (item != null && !item.Removed) { return item; } ItemPrefab itemPrefab = MapEntityPrefab.Find(name: null, identifier: identifier) as ItemPrefab; item = new Item(itemPrefab, Vector2.Zero, submarine: null); - character.Inventory.TryPutItem(item, character); + character.Inventory.TryPutItem(item, character, item.AllowedSlots); return item; } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Reactor.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Reactor.cs index 40895e0f3..1604387a7 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Reactor.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Reactor.cs @@ -123,23 +123,22 @@ namespace Barotrauma.Items.Components var topLeftArea = new GUILayoutGroup(new RectTransform(new Vector2(1, 0.2f), columnLeft.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { - Stretch = true, - RelativeSpacing = 0.02f + Stretch = true }; - Point maxIndicatorSize = new Point(int.MaxValue, (int)(50 * GUI.Scale)); - criticalHeatWarning = new GUITickBox(new RectTransform(new Vector2(0.3f, 1.0f), topLeftArea.RectTransform) { MaxSize = maxIndicatorSize }, + Point maxIndicatorSize = new Point(int.MaxValue, (int)(40 * GUI.Scale)); + criticalHeatWarning = new GUITickBox(new RectTransform(new Vector2(0.33f, 1.0f), topLeftArea.RectTransform) { MaxSize = maxIndicatorSize }, TextManager.Get("ReactorWarningCriticalTemp"), font: GUI.SubHeadingFont, style: "IndicatorLightRed") { CanBeFocused = false }; - lowTemperatureWarning = new GUITickBox(new RectTransform(new Vector2(0.4f, 1.0f), topLeftArea.RectTransform) { MaxSize = maxIndicatorSize }, + lowTemperatureWarning = new GUITickBox(new RectTransform(new Vector2(0.33f, 1.0f), topLeftArea.RectTransform) { MaxSize = maxIndicatorSize }, TextManager.Get("ReactorWarningCriticalLowTemp"), font: GUI.SubHeadingFont, style: "IndicatorLightRed") { CanBeFocused = false }; - criticalOutputWarning = new GUITickBox(new RectTransform(new Vector2(0.3f, 1.0f), topLeftArea.RectTransform) { MaxSize = maxIndicatorSize }, + criticalOutputWarning = new GUITickBox(new RectTransform(new Vector2(0.33f, 1.0f), topLeftArea.RectTransform) { MaxSize = maxIndicatorSize }, TextManager.Get("ReactorWarningCriticalOutput"), font: GUI.SubHeadingFont, style: "IndicatorLightRed") { CanBeFocused = false diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Steering.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Steering.cs index fa90ef51f..4254f0534 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Steering.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Steering.cs @@ -336,7 +336,7 @@ namespace Barotrauma.Items.Components float elementScale = 0.6f; dockingContainer = new GUIFrame(new RectTransform(Sonar.controlBoxSize, GuiFrame.RectTransform, Anchor.BottomLeft, scaleBasis: ScaleBasis.Smallest) { - RelativeOffset = Sonar.controlBoxOffset + RelativeOffset = new Vector2(Sonar.controlBoxOffset.X + 0.05f, Sonar.controlBoxOffset.Y) }, style: null); dockText = TextManager.Get("label.navterminaldock", fallBackTag: "captain.dock"); @@ -358,6 +358,8 @@ namespace Barotrauma.Items.Components } }; dockingButton.Font = GUI.SubHeadingFont; + dockingButton.TextBlock.RectTransform.MaxSize = new Point((int)(dockingButton.Rect.Width * 0.7f), int.MaxValue); + dockingButton.TextBlock.AutoScaleHorizontal = true; var style = GUI.Style.GetComponentStyle("DockingButtonUp"); Sprite buttonSprite = style.Sprites.FirstOrDefault().Value.FirstOrDefault()?.Sprite; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Power/PowerTransfer.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Power/PowerTransfer.cs index c010891d3..809f7b497 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Power/PowerTransfer.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Power/PowerTransfer.cs @@ -22,21 +22,20 @@ namespace Barotrauma.Items.Components var lightsArea = new GUILayoutGroup(new RectTransform(new Vector2(0.4f, 1), paddedFrame.RectTransform, Anchor.CenterLeft)) { - Stretch = true, - RelativeSpacing = 0.05f + Stretch = true }; - powerIndicator = new GUITickBox(new RectTransform(new Vector2(1, 0.3f), lightsArea.RectTransform), + powerIndicator = new GUITickBox(new RectTransform(new Vector2(1, 0.33f), lightsArea.RectTransform), TextManager.Get("PowerTransferPowered"), font: GUI.SubHeadingFont, style: "IndicatorLightGreen") { CanBeFocused = false }; - highVoltageIndicator = new GUITickBox(new RectTransform(new Vector2(1, 0.3f), lightsArea.RectTransform), + highVoltageIndicator = new GUITickBox(new RectTransform(new Vector2(1, 0.33f), lightsArea.RectTransform), TextManager.Get("PowerTransferHighVoltage"), font: GUI.SubHeadingFont, style: "IndicatorLightRed") { ToolTip = TextManager.Get("PowerTransferTipOvervoltage"), Enabled = false }; - lowVoltageIndicator = new GUITickBox(new RectTransform(new Vector2(1, 0.3f), lightsArea.RectTransform), + lowVoltageIndicator = new GUITickBox(new RectTransform(new Vector2(1, 0.33f), lightsArea.RectTransform), TextManager.Get("PowerTransferLowVoltage"), font: GUI.SubHeadingFont, style: "IndicatorLightRed") { ToolTip = TextManager.Get("PowerTransferTipLowvoltage"), diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/CustomInterface.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/CustomInterface.cs index be8ef5baf..214ac75b3 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/CustomInterface.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/CustomInterface.cs @@ -13,7 +13,7 @@ namespace Barotrauma.Items.Components private readonly List uiElements = new List(); private GUILayoutGroup uiElementContainer; - private Point ElementMaxSize => new Point(uiElementContainer.Rect.Width, (int)(60 * GUI.yScale)); + private Point ElementMaxSize => new Point(uiElementContainer.Rect.Width, (int)(65 * GUI.yScale)); partial void InitProjSpecific(XElement element) { @@ -25,6 +25,7 @@ namespace Barotrauma.Items.Components { GuiFrame.ClearChildren(); CreateGUI(); + UpdateLabelsProjSpecific(); } private void CreateGUI() @@ -42,7 +43,6 @@ namespace Barotrauma.Items.Components }; float elementSize = Math.Min(1.0f / visibleElements.Count(), 1); - var textBlocks = new List(); foreach (CustomInterfaceElement ciElement in visibleElements) { if (ciElement.ContinuousSignal) @@ -55,7 +55,6 @@ namespace Barotrauma.Items.Components { UserData = ciElement }; - textBlocks.Add(tickBox.TextBlock); tickBox.OnSelected += (tBox) => { if (GameMain.Client == null) @@ -80,7 +79,6 @@ namespace Barotrauma.Items.Components { UserData = ciElement }; - textBlocks.Add(btn.TextBlock); btn.OnClicked += (_, userdata) => { if (GameMain.Client == null) @@ -97,11 +95,9 @@ namespace Barotrauma.Items.Components //reset size restrictions set by the Style to make sure the elements can fit the interface btn.RectTransform.MinSize = btn.Frame.RectTransform.MinSize = new Point(0, 0); btn.RectTransform.MaxSize = btn.Frame.RectTransform.MaxSize = ElementMaxSize; - btn.TextBlock.Wrap = true; uiElements.Add(btn); } - GUITextBlock.AutoScaleAndNormalize(textBlocks); } } @@ -183,14 +179,36 @@ namespace Barotrauma.Items.Components button.Text = string.IsNullOrWhiteSpace(customInterfaceElementList[i].Label) ? TextManager.GetWithVariable("connection.signaloutx", "[num]", (i + 1).ToString()) : customInterfaceElementList[i].Label; + button.TextBlock.Wrap = button.Text.Contains(' '); } else if (uiElements[i] is GUITickBox tickBox) { tickBox.Text = string.IsNullOrWhiteSpace(customInterfaceElementList[i].Label) ? TextManager.GetWithVariable("connection.signaloutx", "[num]", (i + 1).ToString()) : customInterfaceElementList[i].Label; + tickBox.TextBlock.Wrap = tickBox.Text.Contains(' '); } } + + uiElementContainer.Recalculate(); + var textBlocks = new List(); + foreach (GUIComponent element in uiElementContainer.Children) + { + if (element is GUIButton btn) + { + if (btn.TextBlock.TextSize.Y > btn.Rect.Height - btn.TextBlock.Padding.Y - btn.TextBlock.Padding.W) + { + btn.RectTransform.RelativeSize = new Vector2(btn.RectTransform.RelativeSize.X, btn.RectTransform.RelativeSize.Y * 1.5f); + } + textBlocks.Add(btn.TextBlock); + } + else if (element is GUITickBox tickBox) + { + textBlocks.Add(tickBox.TextBlock); + } + } + uiElementContainer.Recalculate(); + GUITextBlock.AutoScaleAndNormalize(textBlocks); } public void ClientWrite(IWriteMessage msg, object[] extraData = null) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs index b2d5d08e5..b7b4eb4d5 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs @@ -776,7 +776,8 @@ namespace Barotrauma for (int i = 0; i < selInv.slots.Length; i++) { InventorySlot slot = selInv.slots[i]; - if (slot.InteractRect.Contains(PlayerInput.MousePosition) || (slot.EquipButtonRect.Contains(PlayerInput.MousePosition) && selInv.Items[i].AllowedSlots.Any(a => a == InvSlotType.Any))) + if (slot.InteractRect.Contains(PlayerInput.MousePosition) || + (slot.EquipButtonRect.Contains(PlayerInput.MousePosition) && selInv.Items[i] != null && selInv.Items[i].AllowedSlots.Any(a => a == InvSlotType.Any))) { return CursorState.Hand; } @@ -804,7 +805,7 @@ namespace Barotrauma for (int i = 0; i < inv.slots.Length; i++) { InventorySlot slot = inv.slots[i]; - if (slot.EquipButtonRect.Contains(PlayerInput.MousePosition) && inv.Items[i].AllowedSlots.Any(a => a == InvSlotType.Any)) + if (slot.EquipButtonRect.Contains(PlayerInput.MousePosition) && inv.Items[i] != null && inv.Items[i].AllowedSlots.Any(a => a == InvSlotType.Any)) { return CursorState.Hand; } @@ -1299,7 +1300,7 @@ namespace Barotrauma slot.QuickUseKey != Keys.None) { spriteBatch.Draw(slotHotkeySprite.Texture, rect.ScaleSize(1.15f), slotHotkeySprite.SourceRect, slotColor); - GUI.DrawString(spriteBatch, rect.Location.ToVector2() + new Vector2((int)(4 * UIScale), (int)(-1.25f * UIScale)), slot.QuickUseKey.ToString().Substring(1, 1), Color.Black, font: GUI.SmallFont); + GUI.DrawString(spriteBatch, rect.Location.ToVector2() + new Vector2((int)(4.25f * UIScale), (int)Math.Ceiling(-1.5f * UIScale)), slot.QuickUseKey.ToString().Substring(1, 1), Color.Black, font: GUI.HotkeyFont); } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs index a8810ee82..47ff63bfb 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs @@ -248,6 +248,14 @@ namespace Barotrauma.Networking private void ConnectToServer(object endpoint, string hostName) { + LastClientListUpdateID = 0; + foreach (var c in ConnectedClients) + { + GameMain.NetLobbyScreen.RemovePlayer(c); + c.Dispose(); + } + ConnectedClients.Clear(); + chatBox.InputBox.Enabled = false; if (GameMain.NetLobbyScreen?.ChatInput != null) { @@ -2449,17 +2457,23 @@ namespace Barotrauma.Networking { msgBox.AddToGUIUpdateList(); ChatBox.GUIFrame.Flash(Color.DarkGreen, 0.5f); - ChatBox.CloseAfterMessageSent = !ChatBox.ToggleOpen; - ChatBox.ToggleOpen = true; - ChatBox.CloseAfterMessageSent = !ChatBox.ToggleOpen; + if (!chatBox.ToggleOpen) + { + ChatBox.CloseAfterMessageSent = !ChatBox.ToggleOpen; + ChatBox.ToggleOpen = true; + } } if (radioKeyHit) { msgBox.AddToGUIUpdateList(); ChatBox.GUIFrame.Flash(Color.YellowGreen, 0.5f); - ChatBox.CloseAfterMessageSent = !ChatBox.ToggleOpen; - ChatBox.ToggleOpen = true; + if (!chatBox.ToggleOpen) + { + ChatBox.CloseAfterMessageSent = !ChatBox.ToggleOpen; + ChatBox.ToggleOpen = true; + } + if (!msgBox.Text.StartsWith(ChatBox.RadioChatString)) { msgBox.Text = ChatBox.RadioChatString; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/SteamP2PClientPeer.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/SteamP2PClientPeer.cs index 2413223e9..d8a94ef28 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/SteamP2PClientPeer.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/SteamP2PClientPeer.cs @@ -392,6 +392,12 @@ namespace Barotrauma.Networking OnDisconnect?.Invoke(); } + ~SteamP2PClientPeer() + { + OnDisconnect = null; + Close(); + } + #if DEBUG public override void ForceTimeOut() { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/SteamP2POwnerPeer.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/SteamP2POwnerPeer.cs index 04c664c92..c334482f2 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/SteamP2POwnerPeer.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/SteamP2POwnerPeer.cs @@ -408,6 +408,7 @@ namespace Barotrauma.Networking OnDisconnect?.Invoke(); + SteamManager.LeaveLobby(); Steamworks.SteamNetworking.ResetActions(); Steamworks.SteamUser.OnValidateAuthTicketResponse -= OnAuthChange; } @@ -429,6 +430,12 @@ namespace Barotrauma.Networking ChildServerRelay.Write(bufToSend); } + ~SteamP2POwnerPeer() + { + OnDisconnect = null; + Close(); + } + #if DEBUG public override void ForceTimeOut() { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Program.cs b/Barotrauma/BarotraumaClient/ClientSource/Program.cs index d0d1b41c5..ed8e7afa5 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Program.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Program.cs @@ -162,7 +162,7 @@ namespace Barotrauma } sb.AppendLine("\n"); - sb.AppendLine("Exception: " + exception.Message); + sb.AppendLine("Exception: " + exception.Message + " (" + exception.GetType().ToString() + ")"); #if WINDOWS if (exception is SharpDXException sharpDxException && ((uint)sharpDxException.HResult) == 0x887A0005) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs index 5820c166a..1ff4d6a40 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs @@ -933,7 +933,7 @@ namespace Barotrauma.CharacterEditor bool useSpritesheetOrientation = float.IsNaN(lastLimb.Params.SpriteOrientation); GUI.DrawString(spriteBatch, new Vector2(topLeft.X + 350 * GUI.xScale, GameMain.GraphicsHeight - 95 * GUI.yScale), GetCharacterEditorTranslation("SpriteOrientation") + ":", useSpritesheetOrientation ? Color.White : Color.Yellow, Color.Gray * 0.5f, 10, GUI.Font); float orientation = useSpritesheetOrientation ? RagdollParams.SpritesheetOrientation : lastLimb.Params.SpriteOrientation; - DrawRadialWidget(spriteBatch, new Vector2(topLeft.X + 560 * GUI.xScale, GameMain.GraphicsHeight - 75 * GUI.yScale), orientation, string.Empty, useSpritesheetOrientation ? Color.White : Color.Yellow, + DrawRadialWidget(spriteBatch, new Vector2(topLeft.X + 610 * GUI.xScale, GameMain.GraphicsHeight - 75 * GUI.yScale), orientation, string.Empty, useSpritesheetOrientation ? Color.White : Color.Yellow, angle => { TryUpdateSubParam(lastLimb.Params, "spriteorientation", angle); @@ -948,7 +948,7 @@ namespace Barotrauma.CharacterEditor { var topLeft = spriteSheetControls.RectTransform.TopLeft; GUI.DrawString(spriteBatch, new Vector2(topLeft.X + 350 * GUI.xScale, GameMain.GraphicsHeight - 95 * GUI.yScale), GetCharacterEditorTranslation("SpriteSheetOrientation") + ":", Color.White, Color.Gray * 0.5f, 10, GUI.Font); - DrawRadialWidget(spriteBatch, new Vector2(topLeft.X + 560 * GUI.xScale, GameMain.GraphicsHeight - 75 * GUI.yScale), RagdollParams.SpritesheetOrientation, string.Empty, Color.White, + DrawRadialWidget(spriteBatch, new Vector2(topLeft.X + 610 * GUI.xScale, GameMain.GraphicsHeight - 75 * GUI.yScale), RagdollParams.SpritesheetOrientation, string.Empty, Color.White, angle => TryUpdateRagdollParam("spritesheetorientation", angle), circleRadius: 40, widgetSize: 15, rotationOffset: MathHelper.Pi, autoFreeze: false, rounding: 10); } } @@ -1823,7 +1823,6 @@ namespace Barotrauma.CharacterEditor #endregion #region GUI - private static Point outerMargin = new Point(0, 0); private static Vector2 innerScale = new Vector2(0.95f, 0.95f); private GUILayoutGroup rightArea, leftArea; @@ -1903,7 +1902,7 @@ namespace Barotrauma.CharacterEditor }; centerArea = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.95f), parent: Frame.RectTransform, anchor: Anchor.TopRight) { - AbsoluteOffset = new Point((int)(rightArea.RectTransform.ScaledSize.X + rightArea.RectTransform.RelativeOffset.X * rightArea.RectTransform.Parent.ScaledSize.X + 20), outerMargin.Y + 20) + AbsoluteOffset = new Point((int)(rightArea.RectTransform.ScaledSize.X + rightArea.RectTransform.RelativeOffset.X * rightArea.RectTransform.Parent.ScaledSize.X + (int)(20 * GUI.xScale)), (int)(20 * GUI.yScale)) }, style: null) { CanBeFocused = false }; @@ -2213,22 +2212,25 @@ namespace Barotrauma.CharacterEditor private void CreateContextualControls() { - Point elementSize = new Point(120, 20); + Point elementSize = new Point(120, 20).Multiply(GUI.Scale); int textAreaHeight = 20; // General controls backgroundColorPanel = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.1f), centerArea.RectTransform, Anchor.TopRight) { - AbsoluteOffset = new Point(10, 0) + AbsoluteOffset = new Point(10, 0).Multiply(GUI.Scale) }, style: null) { CanBeFocused = false }; // Background color - var frame = new GUIFrame(new RectTransform(new Point(500, 80), backgroundColorPanel.RectTransform, Anchor.TopRight), style: null, color: Color.Black * 0.4f); - new GUITextBlock(new RectTransform(new Vector2(0.2f, 1), frame.RectTransform) { MinSize = new Point(80, 26) }, GetCharacterEditorTranslation("BackgroundColor") + ":", textColor: Color.WhiteSmoke); + var frame = new GUIFrame(new RectTransform(new Point(500, 80).Multiply(GUI.Scale), backgroundColorPanel.RectTransform, Anchor.TopRight), style: null, color: Color.Black * 0.4f); + new GUITextBlock(new RectTransform(new Vector2(0.2f, 1), frame.RectTransform) + { + MinSize = new Point(80, 26) + }, GetCharacterEditorTranslation("BackgroundColor") + ":", textColor: Color.WhiteSmoke); var inputArea = new GUILayoutGroup(new RectTransform(new Vector2(0.7f, 1), frame.RectTransform, Anchor.TopRight) { - AbsoluteOffset = new Point(20, 0) + AbsoluteOffset = new Point(20, 0).Multiply(GUI.Scale) }, isHorizontal: true, childAnchor: Anchor.CenterRight) { Stretch = true, @@ -2275,16 +2277,20 @@ namespace Barotrauma.CharacterEditor // Spritesheet controls spriteSheetControls = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.1f), centerArea.RectTransform, Anchor.BottomLeft) { - RelativeOffset = new Vector2(0, 0.05f) + RelativeOffset = new Vector2(0, 0.1f) }, style: null) { CanBeFocused = false }; - var layoutGroupSpriteSheet = new GUILayoutGroup(new RectTransform(Vector2.One, spriteSheetControls.RectTransform)) { AbsoluteSpacing = 5, CanBeFocused = false }; + var layoutGroupSpriteSheet = new GUILayoutGroup(new RectTransform(Vector2.One, spriteSheetControls.RectTransform)) + { + AbsoluteSpacing = 5, + CanBeFocused = false + }; new GUITextBlock(new RectTransform(new Point(elementSize.X, textAreaHeight), layoutGroupSpriteSheet.RectTransform), GetCharacterEditorTranslation("SpriteSheetZoom") + ":", Color.White); var spriteSheetControlElement = new GUIFrame(new RectTransform(new Point(elementSize.X * 2, textAreaHeight), layoutGroupSpriteSheet.RectTransform), style: null); CalculateSpritesheetZoom(); - spriteSheetZoomBar = new GUIScrollBar(new RectTransform(new Vector2(0.75f, 1), spriteSheetControlElement.RectTransform, Anchor.CenterLeft), barSize: 0.2f) + spriteSheetZoomBar = new GUIScrollBar(new RectTransform(new Vector2(0.69f, 1), spriteSheetControlElement.RectTransform, Anchor.CenterLeft), barSize: 0.2f, style: "GUISlider") { BarScroll = MathHelper.Lerp(0, 1, MathUtils.InverseLerp(spriteSheetMinZoom, spriteSheetMaxZoom, spriteSheetZoom)), Step = 0.01f, @@ -2294,8 +2300,7 @@ namespace Barotrauma.CharacterEditor return true; } }; - new GUIButton(new RectTransform(new Vector2(0.3f, 1), spriteSheetControlElement.RectTransform, Anchor.CenterLeft) { RelativeOffset = new Vector2(0.75f, 0.0f) }, - GetCharacterEditorTranslation("Reset")) + new GUIButton(new RectTransform(new Vector2(0.3f, 1.25f), spriteSheetControlElement.RectTransform, Anchor.CenterRight), GetCharacterEditorTranslation("Reset"), style: "GUIButtonFreeScale") { OnClicked = (box, data) => { @@ -2344,17 +2349,22 @@ namespace Barotrauma.CharacterEditor }; resetSpriteOrientationButtonParent = new GUIFrame(new RectTransform(new Vector2(0.1f, 0.025f), centerArea.RectTransform, Anchor.BottomCenter) { - AbsoluteOffset = new Point(0, -5), + AbsoluteOffset = new Point(0, -5).Multiply(GUI.Scale), RelativeOffset = new Vector2(-0.05f, 0) }, style: null) { CanBeFocused = false }; - new GUIButton(new RectTransform(Vector2.One, resetSpriteOrientationButtonParent.RectTransform, Anchor.TopRight), GetCharacterEditorTranslation("Reset")) + new GUIButton(new RectTransform(Vector2.One, resetSpriteOrientationButtonParent.RectTransform, Anchor.TopRight), GetCharacterEditorTranslation("Reset"), style: "GUIButtonFreeScale") { OnClicked = (box, data) => { - foreach (var limb in selectedLimbs) + IEnumerable limbs = selectedLimbs; + if (limbs.None()) + { + limbs = selectedJoints.Select(j => PlayerInput.KeyDown(Keys.LeftAlt) ? j.LimbB : j.LimbA); + } + foreach (var limb in limbs) { TryUpdateSubParam(limb.Params, "spriteorientation", float.NaN); if (limbPairEditing) @@ -2421,7 +2431,7 @@ namespace Barotrauma.CharacterEditor }; // Joint controls - Point sliderSize = new Point(300, 20); + Point sliderSize = new Point(300, 20).Multiply(GUI.Scale); jointControls = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.075f), centerArea.RectTransform), style: null) { CanBeFocused = false }; var layoutGroupJoints = new GUILayoutGroup(new RectTransform(Vector2.One, jointControls.RectTransform), childAnchor: Anchor.TopLeft) { CanBeFocused = false }; copyJointsToggle = new GUITickBox(new RectTransform(new Point(elementSize.X, textAreaHeight), layoutGroupJoints.RectTransform), GetCharacterEditorTranslation("CopyJointSettings")) @@ -2453,7 +2463,7 @@ namespace Barotrauma.CharacterEditor var jointScaleText = new GUITextBlock(new RectTransform(new Point(elementSize.X, textAreaHeight), jointScaleElement.RectTransform), $"{GetCharacterEditorTranslation("JointScale")}: {RagdollParams.JointScale.FormatDoubleDecimal()}", Color.WhiteSmoke, textAlignment: Alignment.Center); var limbScaleElement = new GUIFrame(new RectTransform(sliderSize + new Point(0, textAreaHeight), layoutGroupRagdoll.RectTransform), style: null); var limbScaleText = new GUITextBlock(new RectTransform(new Point(elementSize.X, textAreaHeight), limbScaleElement.RectTransform), $"{GetCharacterEditorTranslation("LimbScale")}: {RagdollParams.LimbScale.FormatDoubleDecimal()}", Color.WhiteSmoke, textAlignment: Alignment.Center); - jointScaleBar = new GUIScrollBar(new RectTransform(sliderSize, jointScaleElement.RectTransform, Anchor.BottomLeft), barSize: 0.1f) + jointScaleBar = new GUIScrollBar(new RectTransform(sliderSize, jointScaleElement.RectTransform, Anchor.BottomLeft), barSize: 0.1f, style: "GUISlider") { BarScroll = MathHelper.Lerp(0, 1, MathUtils.InverseLerp(RagdollParams.MIN_SCALE, RagdollParams.MAX_SCALE, RagdollParams.JointScale)), Step = 0.001f, @@ -2469,7 +2479,7 @@ namespace Barotrauma.CharacterEditor return true; } }; - limbScaleBar = new GUIScrollBar(new RectTransform(sliderSize, limbScaleElement.RectTransform, Anchor.BottomLeft), barSize: 0.1f) + limbScaleBar = new GUIScrollBar(new RectTransform(sliderSize, limbScaleElement.RectTransform, Anchor.BottomLeft), barSize: 0.1f, style: "GUISlider") { BarScroll = MathHelper.Lerp(0, 1, MathUtils.InverseLerp(RagdollParams.MIN_SCALE, RagdollParams.MAX_SCALE, RagdollParams.LimbScale)), Step = 0.001f, @@ -2514,64 +2524,58 @@ namespace Barotrauma.CharacterEditor return true; }; - Point buttonSize = new Point(180, 30); - int innerMargin = 5; - int outerMargin = 10; - extraRagdollControls = new GUIFrame(new RectTransform(new Point(buttonSize.X + outerMargin * 2, buttonSize.Y * 4 + innerMargin * 3 + outerMargin * 2), centerArea.RectTransform, Anchor.BottomRight) + // Just an approximation + Point buttonSize = new Point(200, 40).Multiply(GUI.Scale); + extraRagdollControls = new GUIFrame(new RectTransform(new Point(buttonSize.X, buttonSize.Y * 4), centerArea.RectTransform, Anchor.BottomRight) { - AbsoluteOffset = new Point(30, 0) + AbsoluteOffset = new Point(30, 0).Multiply(GUI.Scale), + MinSize = new Point(0, 120) }, style: null, color: Color.Black) { CanBeFocused = false }; - var extraRagdollLayout = new GUILayoutGroup(new RectTransform(new Point(extraRagdollControls.Rect.Width - outerMargin * 2, extraRagdollControls.Rect.Height - outerMargin * 2), extraRagdollControls.RectTransform, anchor: Anchor.Center)) + var paddedFrame = new GUILayoutGroup(new RectTransform(Vector2.One * 0.95f, extraRagdollControls.RectTransform, Anchor.Center)) { - AbsoluteSpacing = innerMargin + Stretch = true, + AbsoluteSpacing = 5 }; - deleteSelectedButton = new GUIButton(new RectTransform(buttonSize, extraRagdollLayout.RectTransform), GetCharacterEditorTranslation("DeleteSelected")) + var buttons = GUI.CreateButtons(4, new Vector2(1, 0.25f), paddedFrame.RectTransform, Anchor.TopCenter, style: "GUIButtonSmallFreeScale"); + deleteSelectedButton = buttons[0]; + deleteSelectedButton.Text = GetCharacterEditorTranslation("DeleteSelected"); + deleteSelectedButton.OnClicked = (button, data) => { - OnClicked = (button, data) => - { - DeleteSelected(); - return true; - } + DeleteSelected(); + return true; }; - duplicateLimbButton = new GUIButton(new RectTransform(buttonSize, extraRagdollLayout.RectTransform), GetCharacterEditorTranslation("DuplicateLimb")) + duplicateLimbButton = buttons[1]; + duplicateLimbButton.Text = GetCharacterEditorTranslation("DuplicateLimb"); + duplicateLimbButton.OnClicked = (button, data) => { - OnClicked = (button, data) => - { - CopyLimb(selectedLimbs.FirstOrDefault()); - return true; - } + CopyLimb(selectedLimbs.FirstOrDefault()); + return true; }; - createJointButton = new GUIButton(new RectTransform(buttonSize, extraRagdollLayout.RectTransform), GetCharacterEditorTranslation("CreateJoint")) + createJointButton = buttons[2]; + createJointButton.Text = GetCharacterEditorTranslation("CreateJoint"); + createJointButton.OnClicked = (button, data) => { - OnClicked = (button, data) => - { - ToggleJointCreationMode(); - return true; - } + ToggleJointCreationMode(); + return true; }; - createLimbButton = new GUIButton(new RectTransform(buttonSize, extraRagdollLayout.RectTransform), GetCharacterEditorTranslation("CreateLimb")) + createLimbButton = buttons[3]; + createLimbButton.Text = GetCharacterEditorTranslation("CreateLimb"); + createLimbButton.OnClicked = (button, data) => { - OnClicked = (button, data) => - { - ToggleLimbCreationMode(); - return true; - } + ToggleLimbCreationMode(); + return true; }; - - extraRagdollLayout.RectTransform.Resize( - new Point(extraRagdollLayout.Rect.Width, extraRagdollLayout.RectTransform.Children.Sum(c => c.MinSize.Y + extraRagdollLayout.AbsoluteSpacing))); - extraRagdollControls.RectTransform.Resize(new Point(extraRagdollControls.Rect.Width, extraRagdollLayout.Rect.Height + outerMargin * 2)); - GUITextBlock.AutoScaleAndNormalize(extraRagdollLayout.Children.Where(c => c is GUIButton).Select(b => ((GUIButton)b).TextBlock)); + GUITextBlock.AutoScaleAndNormalize(buttons.Select(b => b.TextBlock)); // Animation animationControls = new GUIFrame(new RectTransform(Vector2.One, centerArea.RectTransform), style: null) { CanBeFocused = false }; var layoutGroupAnimation = new GUILayoutGroup(new RectTransform(Vector2.One, animationControls.RectTransform), childAnchor: Anchor.TopLeft) { CanBeFocused = false }; - var animationSelectionElement = new GUIFrame(new RectTransform(new Point(elementSize.X * 2 - 5, elementSize.Y), layoutGroupAnimation.RectTransform), style: null); + var animationSelectionElement = new GUIFrame(new RectTransform(new Point(elementSize.X * 2 - (int)(5 * GUI.xScale), elementSize.Y), layoutGroupAnimation.RectTransform), style: null); var animationSelectionText = new GUITextBlock(new RectTransform(new Point(elementSize.X, elementSize.Y), animationSelectionElement.RectTransform), GetCharacterEditorTranslation("SelectedAnimation") + ": ", Color.WhiteSmoke, textAlignment: Alignment.Center); - animSelection = new GUIDropDown(new RectTransform(new Point(100, elementSize.Y), animationSelectionElement.RectTransform, Anchor.TopRight), elementCount: 4); + animSelection = new GUIDropDown(new RectTransform(new Point((int)(100 * GUI.xScale), elementSize.Y), animationSelectionElement.RectTransform, Anchor.TopRight), elementCount: 4); if (character.AnimController.CanWalk) { animSelection.AddItem(AnimationType.Walk.ToString(), AnimationType.Walk); @@ -2762,7 +2766,7 @@ namespace Barotrauma.CharacterEditor saveRagdollButton.OnClicked += (button, userData) => { var box = new GUIMessageBox(GetCharacterEditorTranslation("SaveRagdoll"), $"{GetCharacterEditorTranslation("ProvideFileName")}: ", new string[] { TextManager.Get("Cancel"), TextManager.Get("Save") }, messageBoxRelSize); - var inputField = new GUITextBox(new RectTransform(new Point(box.Content.Rect.Width, 30), box.Content.RectTransform, Anchor.Center), RagdollParams.Name.RemoveWhitespace()); + var inputField = new GUITextBox(new RectTransform(new Point(box.Content.Rect.Width, (int)(30 * GUI.yScale)), box.Content.RectTransform, Anchor.Center), RagdollParams.Name.RemoveWhitespace()); box.Buttons[0].OnClicked += (b, d) => { box.Close(); @@ -3216,13 +3220,13 @@ namespace Barotrauma.CharacterEditor CharacterParams.AddToEditor(mainEditor, space: 10); var characterEditor = CharacterParams.SerializableEntityEditor; // Add some space after the title - characterEditor.AddCustomContent(new GUIFrame(new RectTransform(new Point(characterEditor.Rect.Width, 10), characterEditor.RectTransform), style: null) { CanBeFocused = false }, 1); + characterEditor.AddCustomContent(new GUIFrame(new RectTransform(new Point(characterEditor.Rect.Width, (int)(10 * GUI.yScale)), characterEditor.RectTransform), style: null) { CanBeFocused = false }, 1); if (CharacterParams.AI != null) { CreateAddButton(CharacterParams.AI.SerializableEntityEditor, () => CharacterParams.AI.TryAddEmptyTarget(out _), GetCharacterEditorTranslation("AddAITarget")); foreach (var target in CharacterParams.AI.Targets) { - CreateCloseButton(target.SerializableEntityEditor, () => CharacterParams.AI.RemoveTarget(target)); + CreateCloseButton(target.SerializableEntityEditor, () => CharacterParams.AI.RemoveTarget(target), size: 0.8f); } } foreach (var emitter in CharacterParams.BloodEmitters) @@ -3247,7 +3251,7 @@ namespace Barotrauma.CharacterEditor CreateCloseButton(editor, () => CharacterParams.RemoveInventory(inventory)); foreach (var item in inventory.Items) { - CreateCloseButton(item.SerializableEntityEditor, () => inventory.RemoveItem(item)); + CreateCloseButton(item.SerializableEntityEditor, () => inventory.RemoveItem(item), size: 0.8f); } CreateAddButton(editor, () => inventory.AddItem(), GetCharacterEditorTranslation("AddInventoryItem")); } @@ -3319,13 +3323,13 @@ namespace Barotrauma.CharacterEditor { if (attackParams.AfflictionEditors.TryGetValue(affliction.Key, out SerializableEntityEditor afflictionEditor)) { - CreateCloseButton(afflictionEditor, () => attackParams.RemoveAffliction(affliction.Value)); + CreateCloseButton(afflictionEditor, () => attackParams.RemoveAffliction(affliction.Value), size: 0.8f); } } var attackEditor = attackParams.SerializableEntityEditor; CreateAddButton(attackEditor, () => attackParams.AddNewAffliction(), GetCharacterEditorTranslation("AddAffliction")); CreateCloseButton(attackEditor, () => limb.Params.RemoveAttack()); - var space = new GUIFrame(new RectTransform(new Point(attackEditor.RectTransform.Rect.Width, 20), attackEditor.RectTransform), style: null, color: ParamsEditor.Color) + var space = new GUIFrame(new RectTransform(new Point(attackEditor.RectTransform.Rect.Width, (int)(20 * GUI.yScale)), attackEditor.RectTransform), style: null, color: ParamsEditor.Color) { CanBeFocused = false }; @@ -3341,13 +3345,14 @@ namespace Barotrauma.CharacterEditor } } - void CreateCloseButton(SerializableEntityEditor editor, Action onButtonClicked) + void CreateCloseButton(SerializableEntityEditor editor, Action onButtonClicked, float size = 1) { - var parent = new GUIFrame(new RectTransform(new Point(editor.Rect.Width, 30), editor.RectTransform), style: null) + int height = 30; + var parent = new GUIFrame(new RectTransform(new Point(editor.Rect.Width, (int)(height * size * GUI.yScale)), editor.RectTransform, isFixedSize: true), style: null) { CanBeFocused = false }; - new GUIButton(new RectTransform(new Vector2(0.08f, 0.8f), parent.RectTransform, Anchor.BottomRight, scaleBasis: ScaleBasis.BothHeight), style: "GUICancelButton", color: GUI.Style.Red) + new GUIButton(new RectTransform(new Vector2(0.9f), parent.RectTransform, Anchor.BottomRight, scaleBasis: ScaleBasis.BothHeight), style: "GUICancelButton", color: GUI.Style.Red) { OnClicked = (button, data) => { @@ -3361,7 +3366,7 @@ namespace Barotrauma.CharacterEditor void CreateAddButtonAtLast(ParamsEditor editor, Action onButtonClicked, string text) { - var parentFrame = new GUIFrame(new RectTransform(new Point(editor.EditorBox.Rect.Width, 50), editor.EditorBox.Content.RectTransform), style: null, color: ParamsEditor.Color) + var parentFrame = new GUIFrame(new RectTransform(new Point(editor.EditorBox.Rect.Width, (int)(50 * GUI.yScale)), editor.EditorBox.Content.RectTransform), style: null, color: ParamsEditor.Color) { CanBeFocused = false }; @@ -3378,11 +3383,11 @@ namespace Barotrauma.CharacterEditor void CreateAddButton(SerializableEntityEditor editor, Action onButtonClicked, string text) { - var parent = new GUIFrame(new RectTransform(new Point(editor.Rect.Width, 40), editor.RectTransform), style: null) + var parent = new GUIFrame(new RectTransform(new Point(editor.Rect.Width, (int)(60 * GUI.yScale)), editor.RectTransform), style: null) { CanBeFocused = false }; - new GUIButton(new RectTransform(new Vector2(0.45f, 0.6f), parent.RectTransform, Anchor.CenterLeft), text) + new GUIButton(new RectTransform(new Vector2(0.45f, 0.4f), parent.RectTransform, Anchor.CenterLeft), text) { OnClicked = (button, data) => { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs index 8f1d91a21..7ef7322d3 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs @@ -269,7 +269,8 @@ namespace Barotrauma if (selectedParams != null) { - var commonnessContainer = new GUILayoutGroup(new RectTransform(new Point(editor.Rect.Width, 70)), isHorizontal: false, childAnchor: Anchor.TopCenter) + var commonnessContainer = new GUILayoutGroup(new RectTransform(new Point(editor.Rect.Width, 70)) { IsFixedSize = true }, + isHorizontal: false, childAnchor: Anchor.TopCenter) { AbsoluteSpacing = 5, Stretch = true @@ -293,7 +294,7 @@ namespace Barotrauma Sprite sprite = levelObjectPrefab.Sprites.FirstOrDefault() ?? levelObjectPrefab.DeformableSprite?.Sprite; if (sprite != null) { - editor.AddCustomContent(new GUIButton(new RectTransform(new Point(editor.Rect.Width / 2, 20)), + editor.AddCustomContent(new GUIButton(new RectTransform(new Point(editor.Rect.Width / 2, (int)(25 * GUI.Scale))) { IsFixedSize = true }, TextManager.Get("leveleditor.editsprite")) { OnClicked = (btn, userdata) => diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs index 2976f29f5..d49a95eda 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs @@ -1428,7 +1428,10 @@ namespace Barotrauma GUITextBlock.AutoScaleAndNormalize(jobPreferencesButton.TextBlock, appearanceButton.TextBlock); + // Unsubscribe from previous events, not even sure if this matters here but it doesn't hurt so why not + if (characterInfoFrame != null) { characterInfoFrame.RectTransform.SizeChanged -= RecalculateSubDescription; } characterInfoFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.2f), infoContainer.RectTransform), style: null); + characterInfoFrame.RectTransform.SizeChanged += RecalculateSubDescription; JobList = new GUIListBox(new RectTransform(Vector2.One, characterInfoFrame.RectTransform), true) { @@ -2166,12 +2169,13 @@ namespace Barotrauma OnClicked = ClosePlayerFrame }; - buttonAreaLower.RectTransform.MinSize = new Point(0, buttonAreaLower.RectTransform.Children.Max(c => c.MinSize.Y)); - + buttonAreaLower.RectTransform.NonScaledSize = new Point(buttonAreaLower.Rect.Width, buttonAreaLower.RectTransform.Children.Max(c => c.NonScaledSize.Y)); + if (buttonAreaTop != null) { - buttonAreaTop.RectTransform.MinSize = buttonAreaLower.RectTransform.MinSize = - new Point(0, Math.Max(buttonAreaLower.RectTransform.MinSize.Y, buttonAreaTop.RectTransform.Children.Max(c => c.MinSize.Y))); + buttonAreaTop.RectTransform.NonScaledSize = + buttonAreaLower.RectTransform.NonScaledSize = + new Point(buttonAreaLower.Rect.Width, Math.Max(buttonAreaLower.RectTransform.NonScaledSize.Y, buttonAreaTop.RectTransform.Children.Max(c => c.NonScaledSize.Y))); } return false; @@ -3301,13 +3305,21 @@ namespace Barotrauma private void CreateSubPreview(Submarine sub) { - subPreviewContainer.ClearChildren(); + subPreviewContainer?.ClearChildren(); sub.CreatePreviewWindow(subPreviewContainer); - var descriptionBox = subPreviewContainer.FindChild("descriptionbox", recursive: true); - //if description box and character info box are roughly the same size, scale them to the same size - if (characterInfoFrame != null && Math.Abs(descriptionBox.Rect.Height - characterInfoFrame.Rect.Height) < 80 * GUI.Scale) + RecalculateSubDescription(); + } + + private void RecalculateSubDescription() + { + var descriptionBox = subPreviewContainer?.FindChild("descriptionbox", recursive: true); + if (descriptionBox != null && characterInfoFrame != null) { - descriptionBox.RectTransform.MaxSize = new Point(descriptionBox.Rect.Width, characterInfoFrame.Rect.Height); + //if description box and character info box are roughly the same size, scale them to the same size + if (Math.Abs(descriptionBox.Rect.Height - characterInfoFrame.Rect.Height) < 80 * GUI.Scale) + { + descriptionBox.RectTransform.MaxSize = new Point(descriptionBox.Rect.Width, characterInfoFrame.Rect.Height); + } } } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/ServerListScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/ServerListScreen.cs index 58dc10929..7bd320d68 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/ServerListScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/ServerListScreen.cs @@ -1295,7 +1295,20 @@ namespace Barotrauma { info.StatusText = friend.GetRichPresence("status") ?? ""; string connectCommand = friend.GetRichPresence("connect") ?? ""; - ToolBox.ParseConnectCommand(connectCommand.Split(' '), out info.ConnectName, out info.ConnectEndpoint, out info.ConnectLobby); + + try + { + ToolBox.ParseConnectCommand(ToolBox.SplitCommand(connectCommand), out info.ConnectName, out info.ConnectEndpoint, out info.ConnectLobby); + } + catch (IndexOutOfRangeException e) + { +#if DEBUG + DebugConsole.ThrowError($"Failed to parse a Steam friend's connect command ({connectCommand})", e); +#endif + info.ConnectName = null; + info.ConnectEndpoint = null; + info.ConnectLobby = 0; + } } else { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/SteamWorkshopScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/SteamWorkshopScreen.cs index 78a1f11d7..59ef3ab77 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/SteamWorkshopScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/SteamWorkshopScreen.cs @@ -1558,9 +1558,9 @@ namespace Barotrauma }; msgBox.Buttons[1].OnClicked += msgBox.Close; #else + itemEditor = itemEditor?.WithoutTag("unstable"); var workshopPublishStatus = SteamManager.StartPublishItem(itemContentPackage, itemEditor); if (workshopPublishStatus == null) { return; } - if (itemEditor.Value.Tags.Contains("unstable")) { itemEditor.Value.Tags.Remove("unstable"); } CoroutineManager.StartCoroutine(WaitForPublish(workshopPublishStatus), "WaitForPublish"); #endif diff --git a/Barotrauma/BarotraumaClient/ClientSource/Serialization/SerializableEntityEditor.cs b/Barotrauma/BarotraumaClient/ClientSource/Serialization/SerializableEntityEditor.cs index 2c442a4b0..1976a0158 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Serialization/SerializableEntityEditor.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Serialization/SerializableEntityEditor.cs @@ -476,7 +476,8 @@ namespace Barotrauma { if (property.TrySetValue(entity, numInput.FloatValue)) { - numInput.FloatValue = (float)property.GetValue(entity); + // This causes stack overflow. What's the purpose of it? + //numInput.FloatValue = (float)property.GetValue(entity); TrySendNetworkUpdate(entity, property); } }; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Sprite/DeformableSprite.cs b/Barotrauma/BarotraumaClient/ClientSource/Sprite/DeformableSprite.cs index fa10d1840..6d54711f8 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Sprite/DeformableSprite.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Sprite/DeformableSprite.cs @@ -330,14 +330,18 @@ namespace Barotrauma { var container = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.0f), parent.RectTransform)) { - AbsoluteSpacing = 5 + AbsoluteSpacing = 5, + CanBeFocused = true }; - new GUITextBlock(new RectTransform(new Point(container.Rect.Width, 30), container.RectTransform), "Sprite Deformations"); + new GUITextBlock(new RectTransform(new Point(container.Rect.Width, (int)(60 * GUI.Scale)), container.RectTransform) { IsFixedSize = true }, + "Sprite Deformations", textAlignment: Alignment.BottomCenter, font: GUI.LargeFont); - var resolutionField = GUI.CreatePointField(new Point(subDivX + 1, subDivY + 1), 26, "Resolution", container.RectTransform, + var resolutionField = GUI.CreatePointField(new Point(subDivX + 1, subDivY + 1), (int)(30 * GUI.Scale), "Resolution", container.RectTransform, "How many vertices the deformable sprite has on the x and y axes. Larger values make the deformations look smoother, but are more performance intensive."); + resolutionField.RectTransform.IsFixedSize = true; GUINumberInput xField = null, yField = null; + foreach (GUIComponent child in resolutionField.GetAllChildren()) { if (yField == null) @@ -372,7 +376,8 @@ namespace Barotrauma foreach (SpriteDeformation deformation in deformations) { - var deformEditor = new SerializableEntityEditor(container.RectTransform, deformation.Params, false, true); + var deformEditor = new SerializableEntityEditor(container.RectTransform, deformation.Params, + inGame: false, showName: true, titleFont: GUI.SubHeadingFont); deformEditor.RectTransform.MinSize = new Point(deformEditor.Rect.Width, deformEditor.Rect.Height); } @@ -391,7 +396,10 @@ namespace Barotrauma container.RectTransform.Resize(new Point( container.Rect.Width, container.Children.Sum(c => c.Rect.Height + container.AbsoluteSpacing)), false); + + container.RectTransform.MinSize = new Point(0, container.Rect.Height); container.RectTransform.MaxSize = new Point(int.MaxValue, container.Rect.Height); + container.RectTransform.IsFixedSize = true; container.Recalculate(); return container; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Utils/LocalizationCSVtoXML.cs b/Barotrauma/BarotraumaClient/ClientSource/Utils/LocalizationCSVtoXML.cs index 6f412a170..d67ad68b2 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Utils/LocalizationCSVtoXML.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Utils/LocalizationCSVtoXML.cs @@ -81,7 +81,7 @@ namespace Barotrauma DebugConsole.ThrowError("NPCConversation Localization .csv to .xml conversion failed for: " + conversationFiles[j]); continue; } - string xmlFileFullPath = $"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}/NpcConversations_{languageNoWhitespace}_NEW.xml"; + string xmlFileFullPath = $"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}/NpcConversations_{languageNoWhitespace}.xml"; File.WriteAllLines(xmlFileFullPath, xmlContent, Encoding.UTF8); DebugConsole.NewMessage("Conversation localization .xml file successfully created at: " + xmlFileFullPath); } @@ -94,7 +94,7 @@ namespace Barotrauma DebugConsole.ThrowError("InfoText Localization .csv to .xml conversion failed for: " + infoTextFiles[j]); continue; } - string xmlFileFullPath = $"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}/{languageNoWhitespace}Vanilla_NEW.xml"; + string xmlFileFullPath = $"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}/{languageNoWhitespace}Vanilla.xml"; File.WriteAllLines(xmlFileFullPath, xmlContent, Encoding.UTF8); DebugConsole.NewMessage("InfoText localization .xml file successfully created at: " + xmlFileFullPath); } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Utils/ToolBox.cs b/Barotrauma/BarotraumaClient/ClientSource/Utils/ToolBox.cs index 4d14e506d..ad2518771 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Utils/ToolBox.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Utils/ToolBox.cs @@ -239,49 +239,16 @@ namespace Barotrauma { name = null; endpoint = null; lobbyId = 0; if (args == null || args.Length < 2) { return; } - for (int i = 0; i < args.Length - 1; i++) - { - if (i < args.Length-2 && args[i].Trim().ToLowerInvariant().Equals("-connect", StringComparison.InvariantCultureIgnoreCase)) - { - int j = i + 2; - name = ""; - if (args[i + 1].Trim()[0] == '"') - { - name = args[i + 1].Trim().Substring(1); - if (!(name[name.Length - 1] == '"' && (name.Length < 2 || name[name.Length - 1] != '\\'))) - { - for (; j < args.Length - 1; j++) - { - name += " " + args[j].Trim(); - if (name[name.Length - 1] == '"' && (name.Length < 2 || name[name.Length - 1] != '\\')) - { - name = name.Substring(0, name.Length - 1).Replace("\\\"", "\""); - j++; - break; - } - } - } - else - { - name = name.Substring(0, name.Length - 1); - } - } - else - { - name = args[i + 1].Trim(); - } - endpoint = args[j].Trim(); - - break; - } - else if (i < args.Length-1 && args[i].Trim().ToLower().Equals("+connect_lobby", StringComparison.InvariantCultureIgnoreCase)) - { - UInt64.TryParse(args[i + 1].Trim(), out lobbyId); - endpoint = null; - name = null; - break; - } + if (args[0].Equals("-connect", StringComparison.InvariantCultureIgnoreCase)) + { + if (args.Length < 3) { return; } + name = args[1]; + endpoint = args[2]; + } + else if (args[0].Equals("+connect_lobby", StringComparison.InvariantCultureIgnoreCase)) + { + UInt64.TryParse(args[1], out lobbyId); } } } diff --git a/Barotrauma/BarotraumaClient/LinuxClient.csproj b/Barotrauma/BarotraumaClient/LinuxClient.csproj index ccd0387ff..b5fd4f6d5 100644 --- a/Barotrauma/BarotraumaClient/LinuxClient.csproj +++ b/Barotrauma/BarotraumaClient/LinuxClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.9.708.0 + 0.9.7.1 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/MacClient.csproj b/Barotrauma/BarotraumaClient/MacClient.csproj index 1c96d7533..de068fa67 100644 --- a/Barotrauma/BarotraumaClient/MacClient.csproj +++ b/Barotrauma/BarotraumaClient/MacClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.9.708.0 + 0.9.7.1 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/WindowsClient.csproj b/Barotrauma/BarotraumaClient/WindowsClient.csproj index 876df0718..6db530ef8 100644 --- a/Barotrauma/BarotraumaClient/WindowsClient.csproj +++ b/Barotrauma/BarotraumaClient/WindowsClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.9.708.0 + 0.9.7.1 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/libfreetype6.dylib b/Barotrauma/BarotraumaClient/libfreetype6.dylib index 2a8285484..213b65bcf 100644 Binary files a/Barotrauma/BarotraumaClient/libfreetype6.dylib and b/Barotrauma/BarotraumaClient/libfreetype6.dylib differ diff --git a/Barotrauma/BarotraumaServer/LinuxServer.csproj b/Barotrauma/BarotraumaServer/LinuxServer.csproj index 84eeef185..55665f547 100644 --- a/Barotrauma/BarotraumaServer/LinuxServer.csproj +++ b/Barotrauma/BarotraumaServer/LinuxServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.9.708.0 + 0.9.7.1 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/MacServer.csproj b/Barotrauma/BarotraumaServer/MacServer.csproj index 1c79749b1..94e78064c 100644 --- a/Barotrauma/BarotraumaServer/MacServer.csproj +++ b/Barotrauma/BarotraumaServer/MacServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.9.708.0 + 0.9.7.1 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs index b9bb39875..e537f50db 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs @@ -438,7 +438,7 @@ namespace Barotrauma } } - public void WriteSpawnData(IWriteMessage msg, UInt16 entityId) + public void WriteSpawnData(IWriteMessage msg, UInt16 entityId, bool restrictMessageSize) { if (GameMain.Server == null) return; @@ -465,7 +465,7 @@ namespace Barotrauma //character with no characterinfo (e.g. some monster) if (Info == null) { - WriteStatus(msg); + TryWriteStatus(msg); return; } @@ -489,7 +489,23 @@ namespace Barotrauma msg.Write(this is AICharacter); msg.Write(info.SpeciesName); info.ServerWrite(msg); - WriteStatus(msg); + TryWriteStatus(msg); + + void TryWriteStatus(IWriteMessage msg) + { + var tempBuffer = new ReadWriteMessage(); + WriteStatus(tempBuffer); + if (msg.LengthBytes + tempBuffer.LengthBytes >= 255 && restrictMessageSize) + { + msg.Write(false); + DebugConsole.ThrowError($"Error when writing character spawn data: status data caused the length of the message to exceed 255 bytes ({msg.LengthBytes} + {tempBuffer.LengthBytes})"); + } + else + { + msg.Write(true); + WriteStatus(msg); + } + } DebugConsole.Log("Character spawn message length: " + (msg.LengthBytes - msgLength)); } diff --git a/Barotrauma/BarotraumaServer/ServerSource/DebugConsole.cs b/Barotrauma/BarotraumaServer/ServerSource/DebugConsole.cs index 8a3ce2122..b4ed048c7 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/DebugConsole.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/DebugConsole.cs @@ -1970,7 +1970,7 @@ namespace Barotrauma return; } - string[] splitCommand = SplitCommand(command); + string[] splitCommand = ToolBox.SplitCommand(command); Command matchingCommand = commands.Find(c => c.names.Contains(splitCommand[0].ToLowerInvariant())); if (matchingCommand != null && !client.PermittedConsoleCommands.Contains(matchingCommand) && client.Connection != GameMain.Server.OwnerConnection) { diff --git a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/MonsterMission.cs b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/MonsterMission.cs index ef0be14e2..9fb51ef6b 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/MonsterMission.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/MonsterMission.cs @@ -15,7 +15,7 @@ namespace Barotrauma msg.Write((byte)monsters.Count); foreach (Character monster in monsters) { - monster.WriteSpawnData(msg, monster.ID); + monster.WriteSpawnData(msg, monster.ID, restrictMessageSize: false); } } } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/EntitySpawner.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/EntitySpawner.cs index 6c417c34f..ac4111dea 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/EntitySpawner.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/EntitySpawner.cs @@ -41,7 +41,7 @@ namespace Barotrauma { message.Write((byte)SpawnableType.Character); DebugConsole.Log("Writing character spawn data: " + entities.Entity.ToString() + " (original ID: " + entities.OriginalID + ", current ID: " + entities.Entity.ID + ")"); - ((Character)entities.Entity).WriteSpawnData(message, entities.OriginalID); + ((Character)entities.Entity).WriteSpawnData(message, entities.OriginalID, restrictMessageSize: true); } } } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs index 9f8f75f83..d3df8d576 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs @@ -2587,8 +2587,8 @@ namespace Barotrauma.Networking public void SendOrderChatMessage(OrderChatMessage message) { - if (message.Sender == null || message.Sender.SpeechImpediment >= 100.0f) return; - ChatMessageType messageType = ChatMessage.CanUseRadio(message.Sender) ? ChatMessageType.Radio : ChatMessageType.Default; + if (message.Sender == null || message.Sender.SpeechImpediment >= 100.0f) { return; } + //ChatMessageType messageType = ChatMessage.CanUseRadio(message.Sender) ? ChatMessageType.Radio : ChatMessageType.Default; //check which clients can receive the message and apply distance effects foreach (Client client in ConnectedClients) @@ -2598,13 +2598,8 @@ namespace Barotrauma.Networking if (message.Sender != null && client.Character != null && !client.Character.IsDead) { - if (message.Sender != client.Character) - { - modifiedMessage = ChatMessage.ApplyDistanceEffect(message.Text, messageType, message.Sender, client.Character); - } - //too far to hear the msg -> don't send - if (string.IsNullOrWhiteSpace(modifiedMessage)) continue; + if (!client.Character.CanHearCharacter(message.Sender)) { continue; } } SendDirectChatMessage(new OrderChatMessage(message.Order, message.OrderOption, message.TargetEntity, message.TargetCharacter, message.Sender), client); diff --git a/Barotrauma/BarotraumaServer/ServerSource/Program.cs b/Barotrauma/BarotraumaServer/ServerSource/Program.cs index ccdf0b14b..2506ea91f 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Program.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Program.cs @@ -97,7 +97,7 @@ namespace Barotrauma sb.AppendLine("System info:"); sb.AppendLine(" Operating system: " + System.Environment.OSVersion + (System.Environment.Is64BitOperatingSystem ? " 64 bit" : " x86")); sb.AppendLine("\n"); - sb.AppendLine("Exception: "+exception.Message); + sb.AppendLine("Exception: " + exception.Message + " (" + exception.GetType().ToString() + ")"); sb.AppendLine("Target site: " +exception.TargetSite.ToString()); sb.AppendLine("Stack trace: "); sb.AppendLine(exception.StackTrace); diff --git a/Barotrauma/BarotraumaServer/WindowsServer.csproj b/Barotrauma/BarotraumaServer/WindowsServer.csproj index a75336fe6..53ebc9350 100644 --- a/Barotrauma/BarotraumaServer/WindowsServer.csproj +++ b/Barotrauma/BarotraumaServer/WindowsServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.9.708.0 + 0.9.7.1 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaShared/Data/karmasettings.xml b/Barotrauma/BarotraumaShared/Data/karmasettings.xml index 46ae210ba..a29ef9dd9 100644 --- a/Barotrauma/BarotraumaShared/Data/karmasettings.xml +++ b/Barotrauma/BarotraumaShared/Data/karmasettings.xml @@ -6,8 +6,8 @@ karmadecaythreshold="50" karmaincrease="0.05" karmaincreasethreshold="50" - structurerepairkarmaincrease="0.05" - structuredamagekarmadecrease="0.08" + structurerepairkarmaincrease="0.01" + structuredamagekarmadecrease="0.05" itemrepairkarmaincrease="0.03" reactoroverheatkarmadecrease="0.5" reactormeltdownkarmadecrease="30" @@ -29,8 +29,8 @@ karmadecaythreshold="50" karmaincrease="0.04" karmaincreasethreshold="45" - structurerepairkarmaincrease="0.05" - structuredamagekarmadecrease="0.15" + structurerepairkarmaincrease="0.01" + structuredamagekarmadecrease="0.2" itemrepairkarmaincrease="0.03" reactoroverheatkarmadecrease="1.0" reactormeltdownkarmadecrease="35" @@ -52,8 +52,8 @@ karmadecaythreshold="50" karmaincrease="0.05" karmaincreasethreshold="50" - structurerepairkarmaincrease="0.05" - structuredamagekarmadecrease="0.08" + structurerepairkarmaincrease="0.01" + structuredamagekarmadecrease="0.05" itemrepairkarmaincrease="0.03" reactoroverheatkarmadecrease="0.5" reactormeltdownkarmadecrease="30" diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs index 184ef4d2a..44bfc5ad5 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs @@ -1271,16 +1271,42 @@ namespace Barotrauma if (attackResult.Damage > 0.0f) { + bool canAttack = attacker.Submarine == Character.Submarine && canAttackCharacters || attacker.Submarine != null && canAttackSub; if (Character.Params.AI.AttackWhenProvoked) { - if (attacker.Submarine == Character.Submarine && canAttackCharacters || attacker.Submarine != null && canAttackSub) + if (canAttack) { ChangeTargetState(attacker, AIState.Attack, 100); } } else if (!AIParams.HasTag(attacker.SpeciesName)) { - ChangeTargetState(attacker, AIState.Flee, 100); + if (attacker.AIController is EnemyAIController enemyAI) + { + if (enemyAI.CombatStrength > CombatStrength) + { + if (!AIParams.HasTag("stronger")) + { + ChangeTargetState(attacker, AIState.Escape, 100); + } + } + else if (enemyAI.CombatStrength < CombatStrength) + { + if (!AIParams.HasTag("weaker")) + { + ChangeTargetState(attacker, canAttack ? AIState.Attack : AIState.Escape, 100); + } + } + else + { + // Equal strength + ChangeTargetState(attacker, canAttack ? AIState.Attack : AIState.Escape, 100); + } + } + else + { + ChangeTargetState(attacker, AIState.Escape, 100); + } } } @@ -1850,7 +1876,7 @@ namespace Barotrauma SetStateResetTimer(); ChangeParams(target.SpeciesName); // Target also items, because if we are blind and the target doesn't move, we can only perceive the target when it uses items - if (state == AIState.Attack || state == AIState.Flee) + if (state == AIState.Attack || state == AIState.Escape) { ChangeParams("weapon"); ChangeParams("tool"); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs index be117f22e..27950b88d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs @@ -100,6 +100,14 @@ namespace Barotrauma return; } } + if (targetItem == null || targetItem.Removed) + { +#if DEBUG + DebugConsole.NewMessage($"{character.Name}: Target null or removed. Aborting.", Color.Red); +#endif + Abandon = true; + return; + } if (character.IsItemTakenBySomeoneElse(targetItem)) { #if DEBUG diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs index 3f241fd08..c88604bcc 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs @@ -2307,6 +2307,7 @@ namespace Barotrauma public bool CanHearCharacter(Character speaker) { if (speaker == null || speaker.SpeechImpediment > 100.0f) { return false; } + if (speaker == this) { return true; } ChatMessageType messageType = ChatMessage.CanUseRadio(speaker) && ChatMessage.CanUseRadio(this) ? ChatMessageType.Radio : ChatMessageType.Default; @@ -2321,8 +2322,16 @@ namespace Barotrauma if (!CanHearCharacter(orderGiver)) { return; } } - HumanAIController humanAI = AIController as HumanAIController; - humanAI?.SetOrder(order, orderOption, orderGiver, speak); + if (AIController is HumanAIController humanAI) + { + humanAI.SetOrder(order, orderOption, orderGiver, speak); + } +#if CLIENT + else + { + GameMain.GameSession?.CrewManager?.DisplayCharacterOrder(this, order, orderOption); + } +#endif CurrentOrder = order; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs index d228105c6..37d41d47e 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs @@ -260,10 +260,6 @@ namespace Barotrauma } } -#if CLIENT - private Sprite jobIcon; -#endif - private List attachmentSprites; public List AttachmentSprites { @@ -421,9 +417,6 @@ namespace Barotrauma CalculateHeadSpriteRange(); Head.HeadSpriteId = GetRandomHeadID(); Job = (jobPrefab == null) ? Job.Random(Rand.RandSync.Server) : new Job(jobPrefab, variant); -#if CLIENT - jobIcon = Job.Prefab.Icon; -#endif if (!string.IsNullOrEmpty(name)) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionPrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionPrefab.cs index 82316ab38..5785866d5 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionPrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionPrefab.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Reflection; using System.Xml.Linq; using System.Linq; +using System.Security.Cryptography; namespace Barotrauma { @@ -167,8 +168,8 @@ namespace Barotrauma MaxSpeedMultiplier = element.GetAttributeFloat("maxspeedmultiplier", 1.0f); MaxSpeedMultiplier = Math.Max(MinSpeedMultiplier, MaxSpeedMultiplier); - MinBuffMultiplier = element.GetAttributeFloat("minmultiplier", 1.0f); - MaxBuffMultiplier = element.GetAttributeFloat("maxmultiplier", 1.0f); + MinBuffMultiplier = element.GetAttributeFloat("minbuffmultiplier", 1.0f); + MaxBuffMultiplier = element.GetAttributeFloat("maxbuffmultiplier", 1.0f); MaxBuffMultiplier = Math.Max(MinBuffMultiplier, MaxBuffMultiplier); DialogFlag = element.GetAttributeString("dialogflag", ""); @@ -218,6 +219,12 @@ namespace Barotrauma public string FilePath { get; private set; } + /// + /// Unique identifier that's generated by hashing the prefab's string identifier. + /// Used to reduce the amount of bytes needed to write affliction data into network messages in multiplayer. + /// + public uint UIntIdentifier; + // Arbitrary string that is used to identify the type of the affliction. public readonly string AfflictionType; @@ -453,6 +460,20 @@ namespace Barotrauma Prefabs.Add(prefab, isOverride); } } + + using MD5 md5 = MD5.Create(); + foreach (AfflictionPrefab prefab in Prefabs) + { + prefab.UIntIdentifier = ToolBox.StringToUInt32Hash(prefab.Identifier, md5); + + //it's theoretically possible for two different values to generate the same hash, but the probability is astronomically small + var collision = Prefabs.Find(p => p != prefab && p.UIntIdentifier == prefab.UIntIdentifier); + if (collision != null) + { + DebugConsole.ThrowError("Hashing collision when generating uint identifiers for Afflictions: " + prefab.Identifier + " has the same identifier as " + collision.Identifier + " (" + prefab.UIntIdentifier + ")"); + collision.UIntIdentifier++; + } + } } public static void RemoveByFile(string filePath) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs index cd23e345b..1b0dd640d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs @@ -840,7 +840,7 @@ namespace Barotrauma msg.Write((byte)activeAfflictions.Count); foreach (Affliction affliction in activeAfflictions) { - msg.Write(affliction.Prefab.Identifier); + msg.Write(affliction.Prefab.UIntIdentifier); msg.WriteRangedSingle( MathHelper.Clamp(affliction.Strength, 0.0f, affliction.Prefab.MaxStrength), 0.0f, affliction.Prefab.MaxStrength, 8); @@ -860,7 +860,7 @@ namespace Barotrauma foreach (var limbAffliction in limbAfflictions) { msg.WriteRangedInteger(limbHealths.IndexOf(limbAffliction.First), 0, limbHealths.Count - 1); - msg.Write(limbAffliction.Second.Prefab.Identifier); + msg.Write(limbAffliction.Second.Prefab.UIntIdentifier); msg.WriteRangedSingle( MathHelper.Clamp(limbAffliction.Second.Strength, 0.0f, limbAffliction.Second.Prefab.MaxStrength), 0.0f, limbAffliction.Second.Prefab.MaxStrength, 8); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs index 8f5194ccc..8e3333721 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs @@ -195,7 +195,7 @@ namespace Barotrauma } if (space > 0) { - new GUIFrame(new RectTransform(new Point(editor.EditorBox.Rect.Width, space), editor.EditorBox.Content.RectTransform), style: null, color: ParamsEditor.Color) + new GUIFrame(new RectTransform(new Point(editor.EditorBox.Rect.Width, (int)(space * GUI.yScale)), editor.EditorBox.Content.RectTransform), style: null, color: ParamsEditor.Color) { CanBeFocused = false }; @@ -464,7 +464,7 @@ namespace Barotrauma private bool TryAddTarget(XElement targetElement, out TargetParams target) { string tag = targetElement.GetAttributeString("tag", null); - if (!HasTag(tag)) + if (HasTag(tag)) { target = null; DebugConsole.ThrowError($"Multiple targets with the same tag ('{tag}') defined! Only the first will be used!"); @@ -498,7 +498,7 @@ namespace Barotrauma public bool HasTag(string tag) { if (tag == null) { return false; } - return targets.None(t => t.Tag.Equals(tag, StringComparison.OrdinalIgnoreCase)); + return targets.Any(t => t.Tag.Equals(tag, StringComparison.OrdinalIgnoreCase)); } public bool RemoveTarget(TargetParams target) => RemoveSubParam(target, targets); diff --git a/Barotrauma/BarotraumaShared/SharedSource/ContentPackage.cs b/Barotrauma/BarotraumaShared/SharedSource/ContentPackage.cs index b40ae00f6..7087bfb5b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/ContentPackage.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/ContentPackage.cs @@ -121,12 +121,14 @@ namespace Barotrauma { if (md5Hash == null) { - md5Hash = Md5Hash.FetchFromCache(Path); + //TODO: before re-enabling content package hash caching, make sure the hash gets recalculated when any file in the content package changes, not just when the filelist.xml changes. + /*md5Hash = Md5Hash.FetchFromCache(Path); if (md5Hash == null) { CalculateHash(); md5Hash.SaveToCache(Path); - } + }*/ + CalculateHash(); } return md5Hash; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs b/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs index b6aaadb47..455ebca33 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs @@ -1118,45 +1118,9 @@ namespace Barotrauma commands.Sort((c1, c2) => c1.names[0].CompareTo(c2.names[0])); } - private static string[] SplitCommand(string command) - { - command = command.Trim(); - - List commands = new List(); - int escape = 0; - bool inQuotes = false; - string piece = ""; - - for (int i = 0; i < command.Length; i++) - { - if (command[i] == '\\') - { - if (escape == 0) escape = 2; - else piece += '\\'; - } - else if (command[i] == '"') - { - if (escape == 0) inQuotes = !inQuotes; - else piece += '"'; - } - else if (command[i] == ' ' && !inQuotes) - { - if (!string.IsNullOrWhiteSpace(piece)) commands.Add(piece); - piece = ""; - } - else if (escape == 0) piece += command[i]; - - if (escape > 0) escape--; - } - - if (!string.IsNullOrWhiteSpace(piece)) commands.Add(piece); //add final piece - - return commands.ToArray(); - } - public static string AutoComplete(string command, int increment = 1) { - string[] splitCommand = SplitCommand(command); + string[] splitCommand = ToolBox.SplitCommand(command); string[] args = splitCommand.Skip(1).ToArray(); //if an argument is given or the last character is a space, attempt to autocomplete the argument @@ -1245,7 +1209,7 @@ namespace Barotrauma if (string.IsNullOrWhiteSpace(command) || command == "\\" || command == "\n") { return; } - string[] splitCommand = SplitCommand(command); + string[] splitCommand = ToolBox.SplitCommand(command); if (splitCommand.Length == 0) { ThrowError("Failed to execute command \"" + command + "\"!"); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/EventManager.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/EventManager.cs index 4493467e9..01dd3c557 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/EventManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/EventManager.cs @@ -370,7 +370,7 @@ namespace Barotrauma if (!selectedEvents.ContainsKey(eventSet)) { - DebugConsole.ThrowError("Error in EventManager.Update: pending event set \"" + eventSet.DebugIdentifier + "\" not present in selected event sets."); + //no events selected from this event set continue; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs index 18ed1b3e6..27e46c46d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs @@ -405,9 +405,24 @@ namespace Barotrauma.Items.Components { if (User != null && User.Removed) { User = null; return false; } if (IgnoredBodies.Contains(target.Body)) { return false; } - if (target.Body.UserData is Submarine submarine) + if (target.Body.UserData is Submarine sub) { - return !Hitscan; + Vector2 dir = item.body.LinearVelocity.LengthSquared() < 0.001f ? + contact.Manifold.LocalNormal : Vector2.Normalize(item.body.LinearVelocity); + + //do a raycast in the sub's coordinate space to see if it hit a structure + var wallBody = Submarine.PickBody( + item.body.SimPosition - ConvertUnits.ToSimUnits(sub.Position) - dir, + item.body.SimPosition - ConvertUnits.ToSimUnits(sub.Position) + dir, + collisionCategory: Physics.CollisionWall); + if (wallBody?.FixtureList?.First() != null && wallBody.UserData is Structure structure) + { + target = wallBody.FixtureList.First(); + } + else + { + return false; + } } else if (target.Body.UserData is Limb limb) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs index fbbb5dd2d..2310af049 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs @@ -1369,7 +1369,7 @@ namespace Barotrauma container = container.Container; } } - if (hasWaterStatusEffects && condition <= 0.0f) + if (hasWaterStatusEffects && condition > 0.0f) { ApplyStatusEffects(!waterProof && inWater ? ActionType.InWater : ActionType.NotInWater, deltaTime); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Md5Hash.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Md5Hash.cs index fa13b2d48..1deaed05e 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Md5Hash.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Md5Hash.cs @@ -25,6 +25,8 @@ namespace Barotrauma { if (string.IsNullOrWhiteSpace(line)) { continue; } string[] parts = line.Split('|'); + if (parts.Length < 3) { continue; } + string path = parts[0].CleanUpPath(); string hashStr = parts[1]; long timeLong = long.Parse(parts[2]); @@ -32,7 +34,7 @@ namespace Barotrauma Md5Hash hash = new Md5Hash(hashStr); DateTime time = DateTime.FromBinary(timeLong); - if (File.GetLastWriteTime(path) == time) + if (File.GetLastWriteTime(path) == time && !cache.ContainsKey(path)) { cache.Add(path, new Tuple(hash, timeLong)); } @@ -72,22 +74,22 @@ namespace Barotrauma public void SaveToCache(string filename, long? time = null) { - if (!string.IsNullOrWhiteSpace(filename)) + if (string.IsNullOrWhiteSpace(filename)) { return; } + + lock (cache) { - lock (cache) + filename = filename.CleanUpPath(); + Tuple cacheVal = new Tuple(this, time ?? File.GetLastWriteTime(filename).ToBinary()); + if (cache.ContainsKey(filename)) { - Tuple cacheVal = new Tuple(this, time ?? File.GetLastWriteTime(filename).ToBinary()); - if (cache.ContainsKey(filename)) - { - cache[filename] = cacheVal; - } - else - { - cache.Add(filename, cacheVal); - } - SaveCache(); + cache[filename] = cacheVal; } - } + else + { + cache.Add(filename, cacheVal); + } + SaveCache(); + } } public static Md5Hash FetchFromCache(string filename) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Networking/NetEntityEvent/NetEntityEventManager.cs b/Barotrauma/BarotraumaShared/SharedSource/Networking/NetEntityEvent/NetEntityEventManager.cs index b335e23c0..dcc0d4f82 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Networking/NetEntityEvent/NetEntityEventManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Networking/NetEntityEvent/NetEntityEventManager.cs @@ -46,10 +46,10 @@ namespace Barotrauma.Networking //the length of the data is written as a byte, so the data needs to be less than 255 bytes long if (tempEventBuffer.LengthBytes > 255) { - DebugConsole.ThrowError("Too much data in network event for entity \"" + e.Entity.ToString() + "\" (" + tempEventBuffer.LengthBytes + " bytes"); + DebugConsole.ThrowError("Too much data in network event for entity \"" + e.Entity.ToString() + "\" (" + tempEventBuffer.LengthBytes + " bytes, event ID " + e.ID + ")"); GameAnalyticsManager.AddErrorEventOnce("NetEntityEventManager.Write:TooLong" + e.Entity.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, - "Too much data in network event for entity \"" + e.Entity.ToString() + "\" (" + tempEventBuffer.LengthBytes + " bytes"); + "Too much data in network event for entity \"" + e.Entity.ToString() + "\" (" + tempEventBuffer.LengthBytes + " bytes, event ID " + e.ID + ")"); //write an empty event to prevent breaking the event syncing tempBuffer.Write(Entity.NullEntityID); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Utils/ToolBox.cs b/Barotrauma/BarotraumaShared/SharedSource/Utils/ToolBox.cs index 141909dca..6f31de524 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Utils/ToolBox.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Utils/ToolBox.cs @@ -490,59 +490,40 @@ namespace Barotrauma return retVal; } - public static string ParseQuotedArgument(string[] arguments, int startIndex, out int endIndex) + public static string[] SplitCommand(string command) { -#if WINDOWS - endIndex = startIndex + 1; - return arguments[startIndex]; -#else - string retVal = ""; - int currIndex = startIndex; - bool escaped = false; - if (arguments[startIndex][0] != '\"') + command = command.Trim(); + + List commands = new List(); + int escape = 0; + bool inQuotes = false; + string piece = ""; + + for (int i = 0; i < command.Length; i++) { - endIndex = startIndex+1; - return UnescapeCharacters(arguments[startIndex]); - } - while (currIndex < arguments.Length) - { - for (int i = currIndex == startIndex ? 1 : 0; i < arguments[currIndex].Length ;i++) + if (command[i] == '\\') { - if (!escaped) - { - if (arguments[currIndex][i] == '\\') - { - escaped = true; - } - else if (arguments[currIndex][i] == '\"') - { - endIndex = currIndex+1; - return UnescapeCharacters(retVal); - } - } - else - { - escaped = false; - } - retVal += arguments[currIndex][i]; + if (escape == 0) escape = 2; + else piece += '\\'; } - retVal += " "; - currIndex++; + else if (command[i] == '"') + { + if (escape == 0) inQuotes = !inQuotes; + else piece += '"'; + } + else if (command[i] == ' ' && !inQuotes) + { + if (!string.IsNullOrWhiteSpace(piece)) commands.Add(piece); + piece = ""; + } + else if (escape == 0) piece += command[i]; + + if (escape > 0) escape--; } - endIndex = arguments.Length; - return retVal; -#endif - } + if (!string.IsNullOrWhiteSpace(piece)) commands.Add(piece); //add final piece - public static string[] MergeArguments(string[] arguments) - { - List mergedArgs = new List(); - for (int i = 0; i < arguments.Length;) - { - mergedArgs.Add(ParseQuotedArgument(arguments, i, out i)); - } - return mergedArgs.ToArray(); + return commands.ToArray(); } public static void OpenFileWithShell(string filename) diff --git a/Barotrauma/BarotraumaShared/Submarines/Berilia.sub b/Barotrauma/BarotraumaShared/Submarines/Berilia.sub index c97dab01c..4968e0976 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Berilia.sub and b/Barotrauma/BarotraumaShared/Submarines/Berilia.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Dugong.sub b/Barotrauma/BarotraumaShared/Submarines/Dugong.sub index 0209d7448..bb3483879 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Dugong.sub and b/Barotrauma/BarotraumaShared/Submarines/Dugong.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Hemulen.sub b/Barotrauma/BarotraumaShared/Submarines/Hemulen.sub index 26f990be8..7aa3d0166 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Hemulen.sub and b/Barotrauma/BarotraumaShared/Submarines/Hemulen.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Humpback.sub b/Barotrauma/BarotraumaShared/Submarines/Humpback.sub index c653ca6cc..950e13ff9 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Humpback.sub and b/Barotrauma/BarotraumaShared/Submarines/Humpback.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Kastrull.sub b/Barotrauma/BarotraumaShared/Submarines/Kastrull.sub index 2b8a98c78..0fefa6c94 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Kastrull.sub and b/Barotrauma/BarotraumaShared/Submarines/Kastrull.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Orca.sub b/Barotrauma/BarotraumaShared/Submarines/Orca.sub index 4769c75fe..d51353ce9 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 76b066030..9a91693e5 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Remora.sub and b/Barotrauma/BarotraumaShared/Submarines/Remora.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Typhon.sub b/Barotrauma/BarotraumaShared/Submarines/Typhon.sub index 42f6bf116..5ef283918 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Typhon.sub and b/Barotrauma/BarotraumaShared/Submarines/Typhon.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Typhon2.sub b/Barotrauma/BarotraumaShared/Submarines/Typhon2.sub index 9aa5c5807..2925bd7cb 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Typhon2.sub and b/Barotrauma/BarotraumaShared/Submarines/Typhon2.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Venture.sub b/Barotrauma/BarotraumaShared/Submarines/Venture.sub index fb2ae2eec..20a6a4c51 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Venture.sub and b/Barotrauma/BarotraumaShared/Submarines/Venture.sub differ diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index e5b783ab6..4ab81f579 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,63 +1,8 @@ --------------------------------------------------------------------------------------------------------- -v0.9.708.0 +v0.9.7.1 --------------------------------------------------------------------------------------------------------- -- Minor UI improvements. -- Reverted "improved the way clients initialize rounds to prevent timeouts if loading the round takes too long". There were a couple of oversights in the logic that caused issues such as combat missions not starting and campaign failing to start after the first completed round. -- Fixed EventManager intensity being calculated incorrectly in multiplayer, causing monster spawns to be more sparse in multiplayer than in singleplayer. -- Updated tutorial videos. -- Increased duffel bag capacity to 20 to make sure it can hold all the items in a character's inventory (+ a couple more). -- Fixed "Commando" security officer variant spawning without an SMG magazine. -- Potential fix to crashes in "Body.SetTransformIgnoreContacts". -- Fixed bots spawned with the "spawn" console command being unable to communicate via headsets after the first round in the single player campaign. -- Fixed engine's AI target changing it's range too rapidly when the engine's force changes rapidly, causing monsters to often lose track of the sub after just spotting it. -- Do not allow steering input on the nav terminal while command interface is enabled. -- Fixed lobby command (which switches to the single player lobby) being usable in multiplayer. -- Prevented chat message popups (the individual messages that popup when the chatbox is hidden) from getting cursor focus and blocking turret usage. -- Made reactor's fuel rod panel a little larger. - ---------------------------------------------------------------------------------------------------------- -v0.9.707.0 ---------------------------------------------------------------------------------------------------------- - -- Whoops, fixed crashing in multiplayer due to CrewManager attempting to access the single player chatbox. - ---------------------------------------------------------------------------------------------------------- -v0.9.706.0 ---------------------------------------------------------------------------------------------------------- - -- Reverted back to the old inventory UI (with updated graphics) for now. -- Miscellaneous UI layout fixes and improvements. -- Visual improvements to the health interface. -- Fixed bots spawned using console commands not getting assigned the correct team id on their headsets, causing them to be disabled in the command interface. -- Fixed team ids of character's headsets resetting after the first campaign round, preventing them from communicating via radio with the players/bots who are playing their first round. -- Fixed collider tunneling when client is slow to send inputs. Caused characters to occasionally noclip through walls when the connection or framerate is poor. -- Improved the way clients initialize rounds to prevent timeouts if loading the round takes too long. -- Fixed enemy team being visible in the command UI in combat missions. -- Adjusted repair times to better suit current skill balance. -- Medical item balancing. -- Command button is hidden when it cannot be used. -- Added a button to give orders to crew members directly. -- Don't close item UI when opening crew list with keybind. -- Allow toggling crew list with keybind in spectator and freecam modes. -- Fixed command UI hotkey navigation triggering inventory hotkey in the last step. -- Fixed command UI being immediately re-enabled after giving an order in clickless mode. -- Fixed sonar beacon UI overlapping with the chatbox. -- Fixed nav terminal's docking button overlapping with the chatbox. -- Marked "editsubs" a cheat command. -- Fixed cursor getting stuck to the dragging or hand state if dragging/highlighting a wire is interrupted by any other reason than letting go of the left mouse button (electrocution, getting killed, ending the round...) -- Improved server lobby scaling when switching resolutions. -- Fixed some server-side console commands not sending anything back to the client executing them, making it seem as if the command did nothing (botcount, botspawnmode, killdisconnectedtimer, togglekarma). -- Fixed progress bars having a bunch of dead space at the beginning and end (causing battery/repair sliders to appear empty when below ~5%, and full when above ~95%). -- Fixed CustomInterface crashing the game when selected if it contains no buttons/tickboxes. -- Fixed a couple of unfair ruin traps (rooms with coil/sensor placement that makes it impossible to pass through without getting zapped). -- Fixed tutorial video scaling when opened more than once. -- Lock portrait area, health bar, affliction icons and report buttons when using a turret. -- Fixed lower docking port ladder on Typhon 2. -- Safeguards to prevent EventManager from crashing the game due to missing EventManagerSettings (#2066). -- Some safeguards and extra error logging for case where the world field of a physics body seems to be null when dropping an item (#2252). -- Fixed a rare crash with the message "Compare() method returns inconsistent results" when autoplacing items in the sub. -- Fixed mechanic tutorial getting softlocked if the player never has an oxygen tank (or aluminium) and sodium in their inventory at the same time. I.e. if they deconstruct the oxygen tanks first and put the aluminium in the fabricator, and then get the sodium and put it in the fabricator. +- Fixed crashing when attempting to publish Workshop items. --------------------------------------------------------------------------------------------------------- v0.9.7.0 @@ -224,6 +169,7 @@ Multiplayer: - Fixed a bunch of bugs that caused "missing entity" errors. However, there are many different reasons the error can occur, so even though we have not run into the issue anymore during out testing rounds, there is still a chance it may occur in some situations. - Fixed inventory items occasionally getting mixed up in the multiplayer campaign. - Fixed a bug that caused clients to get disconnected with an "invalid object header" error when a character has a large amount of different afflictions. +- Fixed collider tunneling when client is slow to send inputs. Caused characters to occasionally noclip through walls when the connection or framerate is poor. - Fixed server owner occasionally timing out if loading the round takes too long. - Fixed server owner's character occasionally being killed due to round start timeouts. - Fixed players not getting notified in any way when their connection to the server has timed out, allowing them to keep playing without being able to interact with anything. @@ -243,6 +189,7 @@ Multiplayer: - Increased default killdisconnectedtime to 2 minutes. - Player cap can be adjusted in the server settings. - Made "showseed" console command usable by clients. +- Fixed lobby command (which switches to the single player lobby) being usable in multiplayer. Bugfixes: - Fixes to render order oddities (structures with a depth > 0.5 always rendering behind all items, inconsistent render order between sub editor and in-game). Now structures with a depth of >= 0.9 are always behind everything (and visible through the LOS effect), and item's sprite depth is capped to 0.9. @@ -250,6 +197,7 @@ Bugfixes: - Fixed Kastrull flooding when the drone undocks. - Fixed ballast pumps deteriorating in Kastrull's drone despite being unreachable by the players. - Fixed sonar transducers consuming no power. +- Fixed EventManager intensity being calculated incorrectly in multiplayer, causing monster spawns to be more sparse in multiplayer than in singleplayer. - Fixed autopilot overshooting and compensating too heavily when attempting to maintain position, causing it to never fully stop on the target position. - Fixed charactes being unable to get through multi-layer walls from inside the sub (for example the walls above Humpback's command room). - Fixed plasma cutter not cutting through holes in walls. @@ -298,6 +246,8 @@ Bugfixes: - Fixed engine sound range being up to 20 times larger than it should be. - Fixed monsters occasionally being able to attack through walls. - Fixed alarm buzzer not returning to the original rotation when the alarm stops. +- Fixed a couple of unfair ruin traps (rooms with coil/sensor placement that makes it impossible to pass through without getting zapped). +- Fixed mechanic tutorial getting softlocked if the player never has an oxygen tank (or aluminium) and sodium in their inventory at the same time. I.e. if they deconstruct the oxygen tanks first and put the aluminium in the fabricator, and then get the sodium and put it in the fabricator. --------------------------------------------------------------------------------------------------------- v0.9.6.0