diff --git a/Barotrauma/BarotraumaClient/ClientSource/Camera.cs b/Barotrauma/BarotraumaClient/ClientSource/Camera.cs index 5d855a04a..8d7e7d4e0 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Camera.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Camera.cs @@ -251,7 +251,7 @@ namespace Barotrauma /// public bool Freeze { get; set; } - public void MoveCamera(float deltaTime, bool allowMove = true, bool allowZoom = true) + public void MoveCamera(float deltaTime, bool allowMove = true, bool allowZoom = true, bool? followSub = null) { prevPosition = position; prevZoom = zoom; @@ -278,7 +278,7 @@ namespace Barotrauma velocity = Vector2.Lerp(velocity, moveInput, deltaTime * 10.0f); moveCam = velocity * moveSpeed * deltaTime * FreeCamMoveSpeed * 60.0f; - if (Screen.Selected == GameMain.GameScreen && FollowSub) + if (Screen.Selected == GameMain.GameScreen && (followSub ?? FollowSub)) { var closestSub = Submarine.FindClosest(WorldViewCenter); if (closestSub != null) @@ -313,9 +313,10 @@ namespace Barotrauma { Vector2 mousePos = PlayerInput.MousePosition; Vector2 offset = mousePos - Resolution.ToVector2() / 2; - offset.X = offset.X / (Resolution.X * 0.6f); - offset.Y = -offset.Y / (Resolution.Y * 0.6f); + offset.X = offset.X / (Resolution.X * 0.4f); + offset.Y = -offset.Y / (Resolution.Y * 0.3f); if (offset.LengthSquared() > 1.0f) offset.Normalize(); + float offsetUnscaledLen = offset.Length(); offset *= OffsetAmount; // Freeze the camera movement by default, when the cursor is on top of an ui element. // Setting a positive value to the OffsetAmount, will override this behaviour. @@ -330,21 +331,20 @@ namespace Barotrauma } if (Freeze) { - offset = previousOffset; + if (offset.LengthSquared() > 0.001f) { offset = previousOffset; } } else { previousOffset = offset; } - //TODO: remove magic numbers - float minMultiplier = OffsetAmount > 0f ? ((DefaultZoom * 8f * 250f) / OffsetAmount) : 15f; - - //how much to zoom out (0.0 = Default zoom, 1.0 = zoom completely out) + //how much to zoom out (zoom completely out when offset is 1000) float zoomOutAmount = GetZoomAmount(offset); - float newZoom = MathHelper.Lerp(DefaultZoom, MinZoom * minMultiplier, zoomOutAmount) * globalZoomScale; + //scaled zoom amount + float scaledZoom = MathHelper.Lerp(DefaultZoom, MinZoom, zoomOutAmount) * globalZoomScale; //zoom in further if zoomOutAmount is low and resolution is lower than reference - newZoom *= MathHelper.Lerp(0.5f * (1f - Math.Min(globalZoomScale, 1f)), 0f, zoomOutAmount) + 1f; + float newZoom = scaledZoom * (MathHelper.Lerp(0.3f * (1f - Math.Min(globalZoomScale, 1f)), 0f, + (GameMain.Config == null || GameMain.Config.EnableMouseLook) ? (float)Math.Sqrt(offsetUnscaledLen) : 0.3f) + 1f); Zoom += (newZoom - zoom) / ZoomSmoothness; @@ -416,7 +416,7 @@ namespace Barotrauma private float GetZoomAmount(Vector2 offset) { - return Math.Min(offset.Length() / Math.Max(1f, OffsetAmount), 1.0f); + return Math.Min(offset.Length() / 1000.0f, 1.0f); } public float GetZoomAmountFromPrevious() diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/Character.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/Character.cs index bbf7d80fc..cde732d28 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/Character.cs @@ -55,6 +55,11 @@ namespace Barotrauma set { if (controlled == value) return; + if ((!(controlled is null)) && (!(Screen.Selected?.Cam is null)) && value is null) + { + Screen.Selected.Cam.TargetPos = Vector2.Zero; + Lights.LightManager.ViewTarget = null; + } controlled = value; if (controlled != null) controlled.Enabled = true; CharacterHealth.OpenHealthWindow = null; @@ -122,6 +127,9 @@ namespace Barotrauma get { return gibEmitters; } } + public static bool IsMouseOnUI => GUI.MouseOn != null || + (CharacterInventory.IsMouseOnInventory() && !CharacterInventory.DraggingItemToWorld); + public class ObjectiveEntity { public Entity Entity; @@ -291,6 +299,10 @@ namespace Barotrauma cam.OffsetAmount = targetOffsetAmount = 0.0f; } } + else if (IsMouseOnUI) + { + targetOffsetAmount = cam.OffsetAmount; + } else if (Vector2.DistanceSquared(AnimController.Limbs[0].SimPosition, mouseSimPos) > 1.0f) { Body body = Submarine.CheckVisibility(AnimController.Limbs[0].SimPosition, mouseSimPos); @@ -417,6 +429,11 @@ namespace Barotrauma GameMain.NetworkMember.AddChatMessage(chatMessage, ChatMessageType.Dead); GameMain.LightManager.LosEnabled = false; controlled = null; + if (!(Screen.Selected?.Cam is null)) + { + Screen.Selected.Cam.TargetPos = Vector2.Zero; + Lights.LightManager.ViewTarget = null; + } } PlaySound(CharacterSound.SoundType.Die); @@ -424,7 +441,15 @@ namespace Barotrauma partial void DisposeProjSpecific() { - if (controlled == this) controlled = null; + if (controlled == this) + { + controlled = null; + if (!(Screen.Selected?.Cam is null)) + { + Screen.Selected.Cam.TargetPos = Vector2.Zero; + Lights.LightManager.ViewTarget = null; + } + } if (GameMain.GameSession?.CrewManager != null && GameMain.GameSession.CrewManager.GetCharacters().Contains(this)) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterHUD.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterHUD.cs index 54f48913e..b5dae7990 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterHUD.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterHUD.cs @@ -12,6 +12,40 @@ namespace Barotrauma { class CharacterHUD { + const float BossHealthBarDuration = 30.0f; + class BossHealthBar + { + public readonly Character Character; + public float FadeTimer; + + public readonly GUIComponent TopContainer; + public readonly GUIComponent SideContainer; + + public readonly GUIProgressBar TopHealthBar; + public readonly GUIProgressBar SideHealthBar; + + public BossHealthBar(Character character) + { + Character = character; + FadeTimer = BossHealthBarDuration; + + TopContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.18f, 0.03f), HUDFrame.RectTransform, Anchor.TopCenter) + { + MinSize = new Point(100, 50), + RelativeOffset = new Vector2(0.0f, 0.01f) + }, isHorizontal: false, childAnchor: Anchor.TopCenter); + new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.4f), TopContainer.RectTransform), character.DisplayName, textAlignment: Alignment.Center, textColor: GUI.Style.Red); + TopHealthBar = new GUIProgressBar(new RectTransform(new Vector2(1.0f, 0.6f), TopContainer.RectTransform), barSize: 0.0f, style: "CharacterHealthBarCentered"); + + SideContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), bossHealthContainer.RectTransform) + { + MinSize = new Point(80, 60) + }, isHorizontal: false, childAnchor: Anchor.TopRight); + new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), SideContainer.RectTransform), character.DisplayName, textAlignment: Alignment.CenterRight, textColor: GUI.Style.Red); + SideHealthBar = new GUIProgressBar(new RectTransform(new Vector2(1.0f, 0.7f), SideContainer.RectTransform), barSize: 0.0f, style: "CharacterHealthBar"); + } + } + private static readonly Dictionary orderIndicatorCount = new Dictionary(); const float ItemOverlayDelay = 1.0f; private static Item focusedItem; @@ -20,8 +54,12 @@ namespace Barotrauma private static readonly List brokenItems = new List(); private static float brokenItemsCheckTimer; + private static readonly List bossHealthBars = new List(); + private static readonly Dictionary cachedHudTexts = new Dictionary(); + private static GUILayoutGroup bossHealthContainer; + private static GUIFrame hudFrame; public static GUIFrame HUDFrame { @@ -34,6 +72,13 @@ namespace Barotrauma { CanBeFocused = false }; + bossHealthContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.15f, 0.5f), hudFrame.RectTransform, Anchor.CenterRight) + { + RelativeOffset = new Vector2(0.005f, 0.0f) + }) + { + AbsoluteSpacing = GUI.IntScale(10) + }; } return hudFrame; } @@ -71,7 +116,7 @@ namespace Barotrauma public static void AddToGUIUpdateList(Character character) { - if (GUI.DisableHUD) return; + if (GUI.DisableHUD) { return; } if (!character.IsIncapacitated && character.Stun <= 0.0f && !IsCampaignInterfaceOpen) { @@ -84,7 +129,7 @@ namespace Barotrauma foreach (ItemComponent ic in item.Components) { - if (ic.DrawHudWhenEquipped) ic.AddToGUIUpdateList(); + if (ic.DrawHudWhenEquipped) { ic.AddToGUIUpdateList(); } } } } @@ -100,13 +145,14 @@ namespace Barotrauma public static void Update(float deltaTime, Character character, Camera cam) { + UpdateBossHealthBars(deltaTime); + if (GUI.DisableHUD) { if (character.Inventory != null && !LockInventory(character)) { character.Inventory.UpdateSlotInput(); } - return; } @@ -489,6 +535,92 @@ namespace Barotrauma } } + public static void ShowBossHealthBar(Character character) + { + var existingBar = bossHealthBars.Find(b => b.Character == character); + if (existingBar != null) + { + existingBar.FadeTimer = BossHealthBarDuration; + return; + } + + if (bossHealthBars.Count > 5) + { + BossHealthBar oldestHealthBar = bossHealthBars.First(); + foreach (var bar in bossHealthBars) + { + if (bar.TopHealthBar.BarSize < oldestHealthBar.TopHealthBar.BarSize) + { + oldestHealthBar = bar; + } + } + oldestHealthBar.FadeTimer = Math.Min(oldestHealthBar.FadeTimer, 1.0f); + } + + bossHealthBars.Add(new BossHealthBar(character)); + } + + public static void UpdateBossHealthBars(float deltaTime) + { + for (int i = 0; i < bossHealthBars.Count; i++) + { + var bossHealthBar = bossHealthBars[i]; + + bool showTopBar = i == 0; + if (showTopBar != bossHealthBar.TopContainer.Visible) + { + bossHealthContainer.Recalculate(); + } + + bossHealthBar.TopContainer.Visible = showTopBar; + bossHealthBar.SideContainer.Visible = !bossHealthBar.TopContainer.Visible; + + float health = bossHealthBar.Character.Vitality / bossHealthBar.Character.MaxVitality; + + float alpha = Math.Min(bossHealthBar.FadeTimer, 1.0f); + foreach (var c in bossHealthBar.TopContainer.GetAllChildren()) + { + c.Color = new Color(c.Color, (byte)(alpha * 255)); + if (c is GUITextBlock textBlock) + { + textBlock.TextColor = new Color(textBlock.TextColor, (byte)(alpha * 255)); + } + } + + foreach (var c in bossHealthBar.SideContainer.GetAllChildren()) + { + c.Color = new Color(c.Color, (byte)(alpha * 255)); + if (c is GUITextBlock textBlock) + { + textBlock.TextColor = new Color(textBlock.TextColor, (byte)(alpha * 255)); + } + } + + bossHealthBar.TopHealthBar.BarSize = bossHealthBar.SideHealthBar.BarSize = health; + + bossHealthBar.TopHealthBar.Color = bossHealthBar.SideHealthBar.Color = + ToolBox.GradientLerp(health, GUI.Style.HealthBarColorLow, GUI.Style.HealthBarColorMedium, GUI.Style.HealthBarColorHigh) * alpha; + + if (bossHealthBar.Character.IsDead || bossHealthBar.Character.Removed) + { + bossHealthBar.FadeTimer = Math.Min(bossHealthBar.FadeTimer, 1.0f); + } + bossHealthBar.FadeTimer -= deltaTime; + } + + for (int i = bossHealthBars.Count - 1; i >= 0 ; i--) + { + var bossHealthBar = bossHealthBars[i]; + if (bossHealthBar.FadeTimer <= 0) + { + bossHealthBar.SideContainer.Parent?.RemoveChild(bossHealthBar.SideContainer); + bossHealthBar.TopContainer.Parent?.RemoveChild(bossHealthBar.TopContainer); + bossHealthBars.RemoveAt(i); + bossHealthContainer.Recalculate(); + } + } + } + private static bool LockInventory(Character character) { if (character?.Inventory == null || !character.AllowInput || character.LockHands || IsCampaignInterfaceOpen) { return true; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs index 7c97a7dc0..8bcb7e503 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs @@ -297,6 +297,7 @@ namespace Barotrauma barSize: 1.0f, color: GUI.Style.HealthBarColorHigh, style: horizontal ? "CharacterHealthBar" : "GUIProgressBarVertical") { HoverCursor = CursorState.Hand, + ToolTip = TextManager.GetWithVariable("hudbutton.healthinterface", "[key]", GameMain.Config.KeyBindText(InputType.Health)), Enabled = true, IsHorizontal = horizontal }; diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/ChatBox.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/ChatBox.cs index 09cb9afbb..647bee221 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/ChatBox.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/ChatBox.cs @@ -383,8 +383,20 @@ namespace Barotrauma color: ((chatBox.Content.CountChildren % 2) == 0) ? Color.Transparent : Color.Black * 0.1f, parseRichText: true) { UserData = message.SenderName, - CanBeFocused = true + CanBeFocused = false }; + msgText.CalculateHeightFromText(); + if (msgText.RichTextData != null) + { + foreach (var data in msgText.RichTextData) + { + msgText.ClickableAreas.Add(new GUITextBlock.ClickableArea() + { + Data = data, + OnClick = GameMain.NetLobbyScreen.SelectPlayer + }); + } + } if (message is OrderChatMessage orderChatMsg && Character.Controlled != null && diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs index 7be3d7ae9..140c0a62c 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs @@ -539,52 +539,42 @@ namespace Barotrauma } } + IEnumerable strings; if (MouseOn != null) { RectTransform mouseOnRect = MouseOn.RectTransform; bool isAbsoluteOffsetInUse = mouseOnRect.AbsoluteOffset != Point.Zero || mouseOnRect.RelativeOffset == Vector2.Zero; - string selectedString = $"Selected UI Element: {MouseOn.GetType().Name} ({ MouseOn.Style?.Element.Name.LocalName ?? "no style" }, {MouseOn.Rect}"; - string offsetString = $"Relative Offset: {mouseOnRect.RelativeOffset} | Absolute Offset: {(isAbsoluteOffsetInUse ? mouseOnRect.AbsoluteOffset : mouseOnRect.ParentRect.MultiplySize(mouseOnRect.RelativeOffset))}{(isAbsoluteOffsetInUse ? "" : " (Calculated from RelativeOffset)")}"; - string anchorPivotString = $"Anchor: {mouseOnRect.Anchor} | Pivot: {mouseOnRect.Pivot}"; - Vector2 selectedStringSize = SmallFont.MeasureString(selectedString); - Vector2 offsetStringSize = SmallFont.MeasureString(offsetString); - Vector2 anchorPivotStringSize = SmallFont.MeasureString(anchorPivotString); - - int padding = IntScale(10); - int yPos = padding; - - DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - (int)selectedStringSize.X - padding, yPos), selectedString, Color.LightGreen, Color.Black, 0, SmallFont); - yPos += (int)selectedStringSize.Y + padding / 2; - - DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - (int)offsetStringSize.X - padding, yPos), offsetString, Color.LightGreen, Color.Black, 0, SmallFont); - yPos += (int)offsetStringSize.Y + padding / 2; - - DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - (int)anchorPivotStringSize.X - padding, yPos), anchorPivotString, Color.LightGreen, Color.Black, 0, SmallFont); - yPos += (int)anchorPivotStringSize.Y + padding / 2; + strings = new string[] + { + $"Selected UI Element: {MouseOn.GetType().Name} ({ MouseOn.Style?.Element.Name.LocalName ?? "no style" }, {MouseOn.Rect}", + $"Relative Offset: {mouseOnRect.RelativeOffset} | Absolute Offset: {(isAbsoluteOffsetInUse ? mouseOnRect.AbsoluteOffset : mouseOnRect.ParentRect.MultiplySize(mouseOnRect.RelativeOffset))}{(isAbsoluteOffsetInUse ? "" : " (Calculated from RelativeOffset)")}", + $"Anchor: {mouseOnRect.Anchor} | Pivot: {mouseOnRect.Pivot}" + }; } else { - string[] strings = new string[] + strings = new string[] { $"GUI.Scale: {Scale}", $"GUI.xScale: {xScale}", $"GUI.yScale: {yScale}", $"RelativeHorizontalAspectRatio: {RelativeHorizontalAspectRatio}", $"RelativeVerticalAspectRatio: {RelativeVerticalAspectRatio}", - $"Cam.Zoom: {Screen.Selected.Cam?.Zoom ?? 0f}", }; + } - int padding = IntScale(10); - int yPos = padding; + strings = strings.Concat(new string[] { $"Cam.Zoom: {Screen.Selected.Cam?.Zoom ?? 0f}" }); - foreach (string str in strings) - { - Vector2 stringSize = SmallFont.MeasureString(str); + int padding = IntScale(10); + int yPos = padding; - DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - (int)stringSize.X - padding, yPos), str, Color.LightGreen, Color.Black, 0, SmallFont); - yPos += (int)stringSize.Y + padding / 2; - } + foreach (string str in strings) + { + Vector2 stringSize = SmallFont.MeasureString(str); + + DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - (int)stringSize.X - padding, yPos), str, Color.LightGreen, Color.Black, 0, SmallFont); + yPos += (int)stringSize.Y + padding / 2; } } @@ -1037,7 +1027,7 @@ namespace Barotrauma } } - if (parent != null) + if (parent != null && parent.CanBeFocused) { if (!parent.Rect.Equals(monitorRect)) { return parent.HoverCursor; } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUITextBlock.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUITextBlock.cs index 1e30def57..46941f61d 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUITextBlock.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUITextBlock.cs @@ -573,8 +573,9 @@ namespace Barotrauma { base.Update(deltaTime); - if (ClickableAreas.Any() && (GUI.MouseOn?.IsParentOf(this) ?? true) && Rect.Contains(PlayerInput.MousePosition)) + if (ClickableAreas.Any() && (GUI.MouseOn?.IsParentOf(this) ?? true)) { + if (!Rect.Contains(PlayerInput.MousePosition)) { return; } int index = GetCaretIndexFromScreenPos(PlayerInput.MousePosition); foreach (ClickableArea clickableArea in ClickableAreas) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/SubmarineSelection.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/SubmarineSelection.cs index 836c62458..838f4c534 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/SubmarineSelection.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/SubmarineSelection.cs @@ -60,6 +60,7 @@ namespace Barotrauma public GUITextBlock submarineFee; public GUIButton selectSubmarineButton; public GUITextBlock middleTextBlock; + public GUIButton previewButton; } public SubmarineSelection(bool transfer, Action closeAction, RectTransform parent) @@ -191,6 +192,12 @@ namespace Barotrauma submarineDisplayElement.submarineClass = new GUITextBlock(new RectTransform(new Vector2(1f, 0.1f), submarineDisplayElement.background.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { AbsoluteOffset = new Point(0, HUDLayoutSettings.Padding + (int)GUI.Font.MeasureString(submarineDisplayElement.submarineName.Text).Y) }, string.Empty, textAlignment: Alignment.Center); submarineDisplayElement.submarineFee = new GUITextBlock(new RectTransform(new Vector2(1f, 0.1f), submarineDisplayElement.background.RectTransform, Anchor.BottomCenter, Pivot.BottomCenter) { AbsoluteOffset = new Point(0, HUDLayoutSettings.Padding) }, string.Empty, textAlignment: Alignment.Center, font: GUI.SubHeadingFont); submarineDisplayElement.selectSubmarineButton = new GUIButton(new RectTransform(Vector2.One, submarineDisplayElement.background.RectTransform), style: null); + submarineDisplayElement.previewButton = new GUIButton(new RectTransform(Vector2.One * 0.12f, submarineDisplayElement.background.RectTransform, anchor: Anchor.BottomRight, pivot: Pivot.BottomRight, scaleBasis: ScaleBasis.BothHeight) { AbsoluteOffset = new Point((int)(0.03f * background.Rect.Height)) }, style: "ExpandButton") + { + Color = Color.White, + HoverColor = Color.White, + PressedColor = Color.White + }; submarineDisplays[i] = submarineDisplayElement; } @@ -299,6 +306,7 @@ namespace Barotrauma submarineDisplays[i].selectSubmarineButton.OnClicked = null; submarineDisplays[i].displayedSubmarine = null; submarineDisplays[i].middleTextBlock.AutoDraw = false; + submarineDisplays[i].previewButton.Visible = false; } else { @@ -369,6 +377,13 @@ namespace Barotrauma { SelectSubmarine(subToDisplay, submarineDisplays[i].background.Rect); } + + submarineDisplays[i].previewButton.Visible = true; + submarineDisplays[i].previewButton.OnClicked = (btn, obj) => + { + SubmarinePreview.Create(subToDisplay); + return false; + }; } submarineIndex++; diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs index a9a72df2e..3b0679933 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs @@ -192,7 +192,7 @@ namespace Barotrauma contentFrameSize = new Vector2(0.45f, 0.667f); break; } - contentFrame = new GUIFrame(new RectTransform(contentFrameSize, infoFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { RelativeOffset = new Vector2(0.025f, 0.12f) }); + contentFrame = new GUIFrame(new RectTransform(contentFrameSize, infoFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.12f) }); var horizontalLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.958f, 0.943f), contentFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { AbsoluteOffset = new Point(0, GUI.IntScale(25f)) }, isHorizontal: true) { @@ -234,8 +234,6 @@ namespace Barotrauma { var reputationButton = createTabButton(InfoFrameTab.Reputation, "reputation"); - var submarineButton = createTabButton(InfoFrameTab.Submarine, "submarine"); - var balanceFrame = new GUIFrame(new RectTransform(new Point(innerLayoutGroup.Rect.Width, innerLayoutGroup.Rect.Height - infoFrameHolderHeight), parent: innerLayoutGroup.RectTransform), style: "InnerFrame"); new GUITextBlock(new RectTransform(Vector2.One, balanceFrame.RectTransform), "", textAlignment: Alignment.Right, parseRichText: true) { @@ -251,6 +249,8 @@ namespace Barotrauma } } + var submarineButton = createTabButton(InfoFrameTab.Submarine, "submarine"); + if (GameMain.NetworkMember != null) { var myCharacterButton = createTabButton(InfoFrameTab.MyCharacter, "tabmenu.character"); @@ -722,7 +722,7 @@ namespace Barotrauma GUIComponent existingPreview = infoFrameHolder.FindChild("SelectedCharacter"); if (existingPreview != null) infoFrameHolder.RemoveChild(existingPreview); - GUIFrame background = new GUIFrame(new RectTransform(new Vector2(0.543f, 0.717f), infoFrameHolder.RectTransform, Anchor.TopLeft, Pivot.TopRight) { RelativeOffset = new Vector2(-0.061f, 0) }) + GUIFrame background = new GUIFrame(new RectTransform(new Vector2(0.543f, 0.717f), infoFrameHolder.RectTransform, Anchor.TopLeft, Pivot.TopRight) { RelativeOffset = new Vector2(-0.145f, 0) }) { UserData = "SelectedCharacter" }; @@ -1106,7 +1106,11 @@ namespace Barotrauma if (GameMain.GameSession?.GameMode is CampaignMode campaign) { - var upgradeRootLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.57f), paddedFrame.RectTransform, Anchor.BottomLeft, Pivot.BottomLeft), true); + GUILayoutGroup headerLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.09f), paddedFrame.RectTransform) { RelativeOffset = new Vector2(0f, 0.43f) }, isHorizontal: true) { Stretch = true }; + GUIImage headerIcon = new GUIImage(new RectTransform(Vector2.One, headerLayout.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "SubmarineIcon"); + new GUITextBlock(new RectTransform(Vector2.One, headerLayout.RectTransform), TextManager.Get("uicategory.upgrades"), font: GUI.LargeFont); + + var upgradeRootLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.48f), paddedFrame.RectTransform, Anchor.BottomLeft, Pivot.BottomLeft), isHorizontal: true); var upgradeCategoryPanel = UpgradeStore.CreateUpgradeCategoryList(new RectTransform(new Vector2(0.4f, 1f), upgradeRootLayout.RectTransform)); upgradeCategoryPanel.HideChildrenOutsideFrame = true; @@ -1129,6 +1133,11 @@ namespace Barotrauma return true; }; } + else + { + var specsListBox = new GUIListBox(new RectTransform(new Vector2(1f, 0.57f), paddedFrame.RectTransform, Anchor.BottomLeft, Pivot.BottomLeft)); + sub.Info.CreateSpecsWindow(specsListBox, GUI.Font, includeTitle: false, includeClass: false, includeDescription: true); + } } } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/CrewManager.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/CrewManager.cs index b3a5380c8..424596618 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/CrewManager.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/CrewManager.cs @@ -767,6 +767,10 @@ namespace Barotrauma else if (orderInfo.MatchesOrder(order, option)) { icon.UserData = new OrderInfo(order, option, priority); + if (icon is GUIImage image) + { + image.Sprite = GetOrderIconSprite(order, option); + } updatedExistingIcon = true; } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/CampaignMode.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/CampaignMode.cs index 11b414dd7..f4b410a6e 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/CampaignMode.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/CampaignMode.cs @@ -55,6 +55,10 @@ namespace Barotrauma { chatBox.ToggleOpen = wasChatBoxOpen; } + if (!value && CampaignUI?.SelectedTab == InteractionType.PurchaseSub) + { + SubmarinePreview.Close(); + } showCampaignUI = value; } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/SinglePlayerCampaign.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/SinglePlayerCampaign.cs index 847b21361..7bb8a4255 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/SinglePlayerCampaign.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/SinglePlayerCampaign.cs @@ -533,7 +533,7 @@ namespace Barotrauma base.Update(deltaTime); - Map?.Radiation.UpdateRadiation(deltaTime); + Map?.Radiation?.UpdateRadiation(deltaTime); if (PlayerInput.SecondaryMouseButtonClicked() || PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Escape)) diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/HintManager.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/HintManager.cs index 943608350..ba8a256a9 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/HintManager.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/HintManager.cs @@ -106,7 +106,7 @@ namespace Barotrauma CheckIsInteracting(); CheckIfDivingGearOutOfOxygen(); - CheckAdjacentHulls(); + CheckHulls(); CheckReminders(); } @@ -503,6 +503,19 @@ namespace Barotrauma DisplayHint("onrepairfailed"); } + public static void OnActiveOrderAdded(Order order) + { + if (!CanDisplayHints()) { return; } + if (order == null) { return; } + + if (order.Identifier == "reportballastflora" && + order.TargetEntity is Hull h && + h.Submarine?.TeamID == Character.Controlled.TeamID) + { + DisplayHint("onballastflorainfected"); + } + } + private static void CheckIfDivingGearOutOfOxygen() { if (!CanDisplayHints()) { return; } @@ -520,10 +533,14 @@ namespace Barotrauma }); } - private static void CheckAdjacentHulls() + private static void CheckHulls() { if (!CanDisplayHints()) { return; } if (Character.Controlled.CurrentHull == null) { return; } + if (HumanAIController.IsBallastFloraNoticeable(Character.Controlled, Character.Controlled.CurrentHull)) + { + if (DisplayHint("onballastflorainfected")) { return; } + } foreach (var gap in Character.Controlled.CurrentHull.ConnectedGaps) { if (gap.ConnectedDoor == null || gap.ConnectedDoor.Impassable) { continue; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Sonar.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Sonar.cs index f7bc9181b..9420c1e64 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Sonar.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Sonar.cs @@ -705,6 +705,7 @@ namespace Barotrauma.Items.Components if (c.Params.HideInSonar) { continue; } if (!c.IsUnconscious && c.Params.DistantSonarRange > 0.0f && + c.AIController is EnemyAIController enemyAI && enemyAI.IsTargetingPlayer && ((c.WorldPosition - transducerCenter) * displayScale).LengthSquared() > DisplayRadius * DisplayRadius) { float dist = Vector2.Distance(c.WorldPosition, transducerCenter); @@ -1099,6 +1100,7 @@ namespace Barotrauma.Items.Components if (Level.Loaded != null && dockingPort.Item.Submarine.WorldPosition.Y > Level.Loaded.Size.Y) { continue; } if (dockingPort.Item.Submarine == null) { continue; } if (dockingPort.Item.Submarine.Info.IsWreck) { continue; } + if (!dockingPort.Item.Submarine.ShowSonarMarker && !dockingPort.Item.Submarine.Info.IsOutpost) { continue; } //don't show the docking ports of the opposing team on the sonar if (item.Submarine != null) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Connection.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Connection.cs index 403e6d15b..963b5b9c7 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Connection.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Connection.cs @@ -238,7 +238,8 @@ namespace Barotrauma.Items.Components if (!PlayerInput.PrimaryMouseButtonHeld()) { - if (GameMain.NetworkMember != null || panel.CheckCharacterSuccess(Character.Controlled)) + if ((GameMain.NetworkMember != null || panel.CheckCharacterSuccess(Character.Controlled)) && + Wires.Count(w => w != null) < MaxPlayerConnectableWires) { //find an empty cell for the new connection int index = FindEmptyIndex(); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/CustomInterface.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/CustomInterface.cs index da095f186..365680a44 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/CustomInterface.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/CustomInterface.cs @@ -50,7 +50,8 @@ namespace Barotrauma.Items.Components var textBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), layoutGroup.RectTransform), ciElement.Signal, style: "GUITextBoxNoIcon") { OverflowClip = true, - UserData = ciElement + UserData = ciElement, + MaxTextLength = ciElement.MaxTextLength }; //reset size restrictions set by the Style to make sure the elements can fit the interface textBox.RectTransform.MinSize = textBox.Frame.RectTransform.MinSize = new Point(0, 0); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Turret.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Turret.cs index 991bb560a..e0873cd96 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Turret.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Turret.cs @@ -130,12 +130,15 @@ namespace Barotrauma.Items.Components } } - powerIndicator = new GUIProgressBar(new RectTransform(new Vector2(0.18f, 0.03f), GUI.Canvas, Anchor.TopCenter) + powerIndicator = new GUIProgressBar(new RectTransform(new Vector2(0.18f, 0.03f), GUI.Canvas, Anchor.BottomCenter) { - MinSize = new Point(100,20), + MinSize = new Point(100, 20), RelativeOffset = new Vector2(0.0f, 0.01f) - }, - barSize: 0.0f, style: "DeviceProgressBar"); + }, + barSize: 0.0f, style: "DeviceProgressBar") + { + CanBeFocused = false + }; } public override void Move(Vector2 amount) @@ -497,9 +500,15 @@ namespace Barotrauma.Items.Components foreach (MapEntity e in item.linkedTo) { if (!(e is Item linkedItem)) { continue; } - availableAmmo.AddRange(linkedItem.ContainedItems); - } - + var itemContainer = linkedItem.GetComponent(); + if (itemContainer == null) { continue; } + availableAmmo.AddRange(itemContainer.Inventory.AllItems); + for (int i = 0; i < itemContainer.Inventory.Capacity - itemContainer.Inventory.AllItems.Count(); i++) + { + availableAmmo.Add(null); + } + } + float chargeRate = powerConsumption <= 0.0f ? 1.0f : @@ -534,7 +543,7 @@ namespace Barotrauma.Items.Components int spacing = 5; int slotsPerRow = Math.Min(availableAmmo.Count, 6); int totalWidth = slotSize.X * slotsPerRow + spacing * (slotsPerRow - 1); - Point invSlotPos = new Point(GameMain.GraphicsWidth / 2 - totalWidth / 2, (int)(60 * GUI.Scale)); + Point invSlotPos = new Point(GameMain.GraphicsWidth / 2 - totalWidth / 2, powerIndicator.Rect.Y - (int)(75 * GUI.Scale)); for (int i = 0; i < availableAmmo.Count; i++) { // TODO: Optimize? Creates multiple new objects per frame? diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs index e538b8a63..58a858865 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs @@ -319,10 +319,10 @@ namespace Barotrauma { get { - return DraggingItems.Any() && - Character.Controlled != null && + return Character.Controlled != null && Character.Controlled.SelectedConstruction == null && - CharacterHealth.OpenHealthWindow == null; + CharacterHealth.OpenHealthWindow == null && + DraggingItems.Any(); } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightManager.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightManager.cs index c1161dfc3..150a4bfc4 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightManager.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightManager.cs @@ -496,8 +496,6 @@ namespace Barotrauma.Lights if ((!LosEnabled || LosMode == LosMode.None) && !ObstructVision) return; if (ViewTarget == null) return; - if (Character.Controlled == null) { DebugConsole.NewMessage("aaa", Color.Orange); } - graphics.SetRenderTarget(LosTexture); if (ObstructVision) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/Map/Map.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/Map/Map.cs index 38b1db50b..2fa61bc08 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/Map/Map.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/Map/Map.cs @@ -103,13 +103,6 @@ namespace Barotrauma }; } #endif - public Location CurrentDisplayLocation - { - get - { - return GameMain.GameSession.Campaign.CurrentDisplayLocation; - } - } partial void InitProjectSpecific() { @@ -263,24 +256,26 @@ namespace Barotrauma { Rectangle rect = mapContainer.Rect; - if (CurrentDisplayLocation != null) + var currentDisplayLocation = GameMain.GameSession?.Campaign?.GetCurrentDisplayLocation(); + + if (currentDisplayLocation != null) { - if (!CurrentDisplayLocation.Discovered) + if (!currentDisplayLocation.Discovered) { - RemoveFogOfWar(CurrentDisplayLocation); - CurrentDisplayLocation.Discovered = true; - if (CurrentDisplayLocation.MapPosition.X > furthestDiscoveredLocation.MapPosition.X) + RemoveFogOfWar(currentDisplayLocation); + currentDisplayLocation.Discovered = true; + if (currentDisplayLocation.MapPosition.X > furthestDiscoveredLocation.MapPosition.X) { - furthestDiscoveredLocation = CurrentDisplayLocation; + furthestDiscoveredLocation = currentDisplayLocation; } } } - Vector2 currentPosition = CurrentDisplayLocation.MapPosition; + Vector2 currentPosition = currentDisplayLocation.MapPosition; if (Level.Loaded?.Type == LevelData.LevelType.LocationConnection && Level.Loaded.StartLocation != null && Level.Loaded.EndLocation != null) { - Vector2 startPos = CurrentDisplayLocation == Level.Loaded.StartLocation ? Level.Loaded.StartLocation.MapPosition : Level.Loaded.EndLocation.MapPosition; - int moveDir = CurrentDisplayLocation == Level.Loaded.StartLocation ? 1 : -1; + Vector2 startPos = currentDisplayLocation == Level.Loaded.StartLocation ? Level.Loaded.StartLocation.MapPosition : Level.Loaded.EndLocation.MapPosition; + int moveDir = currentDisplayLocation == Level.Loaded.StartLocation ? 1 : -1; Vector2 diff = Level.Loaded.EndLocation.MapPosition - Level.Loaded.StartLocation.MapPosition; currentPosition = startPos + @@ -330,14 +325,14 @@ namespace Barotrauma for (int i = 0; i < Locations.Count; i++) { Location location = Locations[i]; - if (IsInFogOfWar(location) && !(CurrentDisplayLocation?.Connections.Any(c => c.Locations.Contains(location)) ?? false) && !GameMain.DebugDraw) { continue; } + if (IsInFogOfWar(location) && !(currentDisplayLocation?.Connections.Any(c => c.Locations.Contains(location)) ?? false) && !GameMain.DebugDraw) { continue; } Vector2 pos = rectCenter + (location.MapPosition + viewOffset) * zoom; if (!rect.Contains(pos)) { continue; } Sprite locationSprite = location.IsCriticallyRadiated() ? location.Type.RadiationSprite ?? location.Type.Sprite : location.Type.Sprite; float iconScale = generationParams.LocationIconSize / locationSprite.size.X; - if (location == CurrentDisplayLocation) { iconScale *= 1.2f; } + if (location == currentDisplayLocation) { iconScale *= 1.2f; } Rectangle drawRect = locationSprite.SourceRect; drawRect.Width = (int)(drawRect.Width * iconScale * zoom * 1.4f); @@ -383,9 +378,9 @@ namespace Barotrauma { foreach (LocationConnection connection in Connections) { - if (HighlightedLocation != CurrentDisplayLocation && + if (HighlightedLocation != currentDisplayLocation && connection.Locations.Contains(HighlightedLocation) && - connection.Locations.Contains(CurrentDisplayLocation)) + connection.Locations.Contains(currentDisplayLocation)) { if (PlayerInput.PrimaryMouseButtonClicked() && SelectedLocation != HighlightedLocation && HighlightedLocation != null) @@ -418,13 +413,13 @@ namespace Barotrauma { if (PlayerInput.DoubleClicked() && HighlightedLocation != null) { - var passedConnection = CurrentDisplayLocation.Connections.Find(c => c.OtherLocation(CurrentDisplayLocation) == HighlightedLocation); + var passedConnection = currentDisplayLocation.Connections.Find(c => c.OtherLocation(currentDisplayLocation) == HighlightedLocation); if (passedConnection != null) { passedConnection.Passed = true; } - Location prevLocation = CurrentDisplayLocation; + Location prevLocation = currentDisplayLocation; CurrentLocation = HighlightedLocation; Level.Loaded.DebugSetStartLocation(CurrentLocation); Level.Loaded.DebugSetEndLocation(null); @@ -436,7 +431,7 @@ namespace Barotrauma { CurrentLocation.CreateStore(); ProgressWorld(); - Radiation.OnStep(1); + Radiation?.OnStep(1); } else { @@ -461,6 +456,7 @@ namespace Barotrauma public void Draw(SpriteBatch spriteBatch, GUICustomComponent mapContainer) { tooltip = null; + var currentDisplayLocation = GameMain.GameSession?.Campaign?.GetCurrentDisplayLocation(); Rectangle rect = mapContainer.Rect; @@ -531,14 +527,14 @@ namespace Barotrauma float rawNoiseScale = 1.0f + PerlinNoise.GetPerlin((int)(Timing.TotalTime * 1 - 1), (int)(Timing.TotalTime * 1 - 1)); DrawNoise(spriteBatch, rect, rawNoiseScale); - Radiation.Draw(spriteBatch, rect, zoom); + Radiation?.Draw(spriteBatch, rect, zoom); if (generationParams.ShowLocations) { foreach (LocationConnection connection in Connections) { if (IsInFogOfWar(connection.Locations[0]) && IsInFogOfWar(connection.Locations[1])) { continue; } - DrawConnection(spriteBatch, connection, rect, viewOffset); + DrawConnection(spriteBatch, connection, rect, viewOffset, currentDisplayLocation); } for (int i = 0; i < Locations.Count; i++) @@ -557,12 +553,12 @@ namespace Barotrauma Color color = location.Type.SpriteColor; if (!location.Discovered) { color = Color.White; } - if (location.Connections.Find(c => c.Locations.Contains(CurrentDisplayLocation)) == null) + if (location.Connections.Find(c => c.Locations.Contains(currentDisplayLocation)) == null) { color *= 0.5f; } - float iconScale = location == CurrentDisplayLocation ? 1.2f : 1.0f; + float iconScale = location == currentDisplayLocation ? 1.2f : 1.0f; if (location == HighlightedLocation) { iconScale *= 1.2f; @@ -571,7 +567,7 @@ namespace Barotrauma locationSprite.Draw(spriteBatch, pos, color, scale: generationParams.LocationIconSize / locationSprite.size.X * iconScale * zoom); - if (location == CurrentDisplayLocation) + if (location == currentDisplayLocation) { if (SelectedLocation != null) { @@ -701,7 +697,7 @@ namespace Barotrauma if (drawRadiationTooltip) { - Radiation.DrawFront(spriteBatch); + Radiation?.DrawFront(spriteBatch); } spriteBatch.End(); @@ -736,7 +732,7 @@ namespace Barotrauma private static float GetPerlinNoise() => PerlinNoise.GetPerlin((int)(Timing.TotalTime * 1 - 1), (int)(Timing.TotalTime * 1 - 1)); - private void DrawConnection(SpriteBatch spriteBatch, LocationConnection connection, Rectangle viewArea, Vector2 viewOffset, Color? overrideColor = null) + private void DrawConnection(SpriteBatch spriteBatch, LocationConnection connection, Rectangle viewArea, Vector2 viewOffset, Location currentDisplayLocation, Color? overrideColor = null) { Color connectionColor; if (GameMain.DebugDraw) @@ -765,15 +761,15 @@ namespace Barotrauma width = (int)(width * 1.5f); } //selected connection - if (SelectedLocation != CurrentDisplayLocation && - connection.Locations.Contains(SelectedLocation) && connection.Locations.Contains(CurrentDisplayLocation)) + if (SelectedLocation != currentDisplayLocation && + connection.Locations.Contains(SelectedLocation) && connection.Locations.Contains(currentDisplayLocation)) { connectionColor = generationParams.HighlightedConnectionColor; width *= 2; } //highlighted connection - else if (HighlightedLocation != CurrentDisplayLocation && - connection.Locations.Contains(HighlightedLocation) && connection.Locations.Contains(CurrentDisplayLocation)) + else if (HighlightedLocation != currentDisplayLocation && + connection.Locations.Contains(HighlightedLocation) && connection.Locations.Contains(currentDisplayLocation)) { connectionColor = generationParams.HighlightedConnectionColor; width *= 2; @@ -834,7 +830,7 @@ namespace Barotrauma if (connection == SelectedConnection) { float t = (i - startIndex) / (float)(endIndex - startIndex - 1); - if (CurrentDisplayLocation == connection.Locations[1]) { t = 1.0f - t; } + if (currentDisplayLocation == connection.Locations[1]) { t = 1.0f - t; } if (t > connectionHighlightState) { segmentWidth /= 2; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/SubmarineInfo.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/SubmarineInfo.cs index 3ad06be3d..412dcad18 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/SubmarineInfo.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/SubmarineInfo.cs @@ -20,7 +20,7 @@ namespace Barotrauma { var texture = TextureLoader.FromStream(mem, path: FilePath, compress: false); if (texture == null) { throw new Exception("PreviewImage texture returned null"); } - PreviewImage = new Sprite(texture, null, null); + PreviewImage = new Sprite(texture, sourceRectangle: null, newOffset: null, path: FilePath); } } catch (Exception e) @@ -39,6 +39,7 @@ namespace Barotrauma var previewButton = new GUIButton(new RectTransform(new Vector2(1f, 0.5f), content.RectTransform), style: null) { + CanBeFocused = SubmarineElement != null, OnClicked = (btn, obj) => { SubmarinePreview.Create(this); return false; }, }; @@ -61,16 +62,19 @@ namespace Barotrauma new GUIFrame(new RectTransform(Vector2.One, submarinePreviewBackground.RectTransform), "InnerGlow", color: Color.Black) { CanBeFocused = false }; } - new GUIFrame(new RectTransform(Vector2.One * 0.12f, previewButton.RectTransform, anchor: Anchor.BottomRight, pivot: Pivot.BottomRight, scaleBasis: ScaleBasis.BothHeight) + if (SubmarineElement != null) { - AbsoluteOffset = new Point((int)(0.03f * previewButton.Rect.Height)) - }, - "ExpandButton", Color.White) - { - Color = Color.White, - HoverColor = Color.White, - PressedColor = Color.White - }; + new GUIFrame(new RectTransform(Vector2.One * 0.12f, previewButton.RectTransform, anchor: Anchor.BottomRight, pivot: Pivot.BottomRight, scaleBasis: ScaleBasis.BothHeight) + { + AbsoluteOffset = new Point((int)(0.03f * previewButton.Rect.Height)) + }, + "ExpandButton", Color.White) + { + Color = Color.White, + HoverColor = Color.White, + PressedColor = Color.White + }; + } var descriptionBox = new GUIListBox(new RectTransform(new Vector2(1, 0.5f), content.RectTransform, Anchor.BottomCenter)) { @@ -81,10 +85,10 @@ namespace Barotrauma ScalableFont font = parent.Rect.Width < 350 ? GUI.SmallFont : GUI.Font; - CreateSpecsWindow(descriptionBox, font, includesDescription: true); + CreateSpecsWindow(descriptionBox, font, includeDescription: true); } - public void CreateSpecsWindow(GUIListBox parent, ScalableFont font, bool includeTitle = true, bool includesDescription = false) + public void CreateSpecsWindow(GUIListBox parent, ScalableFont font, bool includeTitle = true, bool includeClass = true, bool includeDescription = false) { float leftPanelWidth = 0.6f; float rightPanelWidth = 0.4f; @@ -94,15 +98,18 @@ namespace Barotrauma int leftPanelWidthInt = (int)(parent.Rect.Width * leftPanelWidth); GUITextBlock submarineNameText = null; + GUITextBlock submarineClassText = null; if (includeTitle) { int nameHeight = (int)GUI.LargeFont.MeasureString(DisplayName, true).Y; submarineNameText = new GUITextBlock(new RectTransform(new Point(leftPanelWidthInt, nameHeight + HUDLayoutSettings.Padding / 2), parent.Content.RectTransform), DisplayName, textAlignment: Alignment.CenterLeft, font: GUI.LargeFont) { CanBeFocused = false }; submarineNameText.RectTransform.MinSize = new Point(0, (int)submarineNameText.TextSize.Y); } - var submarineClassText = new GUITextBlock(new RectTransform(new Point(leftPanelWidthInt, classHeight), parent.Content.RectTransform), className, textAlignment: Alignment.CenterLeft, font: GUI.SubHeadingFont) { CanBeFocused = false }; - submarineClassText.RectTransform.MinSize = new Point(0, (int)submarineClassText.TextSize.Y); - + if (includeClass) + { + submarineClassText = new GUITextBlock(new RectTransform(new Point(leftPanelWidthInt, classHeight), parent.Content.RectTransform), className, textAlignment: Alignment.CenterLeft, font: GUI.SubHeadingFont) { CanBeFocused = false }; + submarineClassText.RectTransform.MinSize = new Point(0, (int)submarineClassText.TextSize.Y); + } Vector2 realWorldDimensions = Dimensions * Physics.DisplayToRealWorldRatio; if (realWorldDimensions != Vector2.Zero) { @@ -169,7 +176,7 @@ namespace Barotrauma } GUITextBlock descBlock = null; - if (includesDescription) + if (includeDescription) { //space new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), parent.Content.RectTransform), style: null); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/SubmarinePreview.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/SubmarinePreview.cs index 044b4f444..630a44622 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/SubmarinePreview.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/SubmarinePreview.cs @@ -60,10 +60,15 @@ namespace Barotrauma public static void Create(SubmarineInfo submarineInfo) { - instance?.Dispose(); + Close(); instance = new SubmarinePreview(submarineInfo); } + public static void Close() + { + instance?.Dispose(); + } + private SubmarinePreview(SubmarineInfo subInfo) { camera = new Camera(); @@ -102,7 +107,7 @@ namespace Barotrauma }, (deltaTime, component) => { bool isMouseOnComponent = GUI.MouseOn == component; - camera.MoveCamera(deltaTime, allowZoom: isMouseOnComponent); + camera.MoveCamera(deltaTime, allowZoom: isMouseOnComponent, followSub: false); if (isMouseOnComponent && (PlayerInput.MidButtonHeld() || PlayerInput.LeftButtonHeld())) { @@ -136,7 +141,7 @@ namespace Barotrauma ScrollBarVisible = false, Spacing = 5 }; - subInfo.CreateSpecsWindow(specsContainer, GUI.Font, includeTitle: false, includesDescription: true); + subInfo.CreateSpecsWindow(specsContainer, GUI.Font, includeTitle: false, includeDescription: true); int width = specsContainer.Rect.Width; void recalculateSpecsContainerHeight() { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/ChatMessage.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/ChatMessage.cs index 157ed497a..3a94e246e 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/ChatMessage.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/ChatMessage.cs @@ -29,6 +29,14 @@ namespace Barotrauma.Networking string senderName = msg.ReadString(); Character senderCharacter = null; + Client senderClient = null; + bool hasSenderClient = msg.ReadBoolean(); + if (hasSenderClient) + { + UInt64 clientId = msg.ReadUInt64(); + senderClient = GameMain.Client.ConnectedClients.Find(c => c.SteamID == clientId || c.ID == clientId); + if (senderClient != null) { senderName = senderClient.Name; } + } bool hasSenderCharacter = msg.ReadBoolean(); if (hasSenderCharacter) { @@ -38,6 +46,7 @@ namespace Barotrauma.Networking senderName = senderCharacter.Name; } } + msg.ReadPadBits(); switch (type) { @@ -197,7 +206,7 @@ namespace Barotrauma.Networking GameMain.Client.ServerSettings.ServerLog?.WriteLine(txt, messageType); break; default: - GameMain.Client.AddChatMessage(txt, type, senderName, senderCharacter, changeType); + GameMain.Client.AddChatMessage(txt, type, senderName, senderClient, senderCharacter, changeType); break; } LastID = id; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs index 39be674c2..23927eb64 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs @@ -1805,8 +1805,10 @@ namespace Barotrauma.Networking var matchingSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash); if (matchingSub == null) { - matchingSub = new SubmarineInfo(Path.Combine(SubmarineInfo.SavePath, subName) + ".sub", subHash, tryLoad: false); - matchingSub.SubmarineClass = (SubmarineClass)subClass; + matchingSub = new SubmarineInfo(Path.Combine(SubmarineInfo.SavePath, subName) + ".sub", subHash, tryLoad: false) + { + SubmarineClass = (SubmarineClass)subClass + }; } matchingSub.RequiredContentPackagesInstalled = requiredContentPackagesInstalled; ServerSubmarines.Add(matchingSub); @@ -3578,6 +3580,10 @@ namespace Barotrauma.Networking { errorLines.Add("Submarine: " + GameMain.GameSession.Submarine.Info.Name); } + if (GameMain.NetworkMember?.RespawnManager?.RespawnShuttle != null) + { + errorLines.Add("Respawn shuttle: " + GameMain.NetworkMember.RespawnManager.RespawnShuttle.Info.Name); + } if (Level.Loaded != null) { errorLines.Add("Level: " + Level.Loaded.Seed + ", " + string.Join(", ", Level.Loaded.EqualityCheckValues.Select(cv => cv.ToString("X")))); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/ServerSettings.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/ServerSettings.cs index fd51cf3fc..b78876069 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/ServerSettings.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/ServerSettings.cs @@ -648,7 +648,14 @@ namespace Barotrauma.Networking foreach (ItemPrefab ip in ItemPrefab.Prefabs) { - if (!ip.CanBeBought && !ip.Tags.Contains("smallitem")) continue; + if (ip.AllowAsExtraCargo.HasValue) + { + if (!ip.AllowAsExtraCargo.Value) { continue; } + } + else + { + if (!ip.CanBeBought) { continue; } + } var itemFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.15f), cargoFrame.Content.RectTransform) { MinSize = new Point(0, 30) }, isHorizontal: true) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/Voting.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/Voting.cs index ceec59032..31dc44d22 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/Voting.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/Voting.cs @@ -112,14 +112,17 @@ namespace Barotrauma switch (voteType) { - case VoteType.Sub: - SubmarineInfo sub = data as SubmarineInfo; - if (sub == null) { return; } + case VoteType.Sub: + if (!(data is SubmarineInfo sub)) { return; } msg.Write(sub.EqualityCheckVal); + if (sub.EqualityCheckVal == 0) + { + //sub doesn't exist client-side, use hash to let the server know which one we voted for + msg.Write(sub.MD5Hash.Hash); + } break; case VoteType.Mode: - GameModePreset gameMode = data as GameModePreset; - if (gameMode == null) { return; } + if (!(data is GameModePreset gameMode)) { return; } msg.Write(gameMode.Identifier); break; case VoteType.EndRound: @@ -127,8 +130,7 @@ namespace Barotrauma msg.Write((bool)data); break; case VoteType.Kick: - Client votedClient = data as Client; - if (votedClient == null) return; + if (!(data is Client votedClient)) { return; } msg.Write(votedClient.ID); break; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignSetupUI.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignSetupUI.cs index 8a154cf79..19d9c2348 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignSetupUI.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignSetupUI.cs @@ -173,7 +173,15 @@ namespace Barotrauma string savePath = SaveUtil.CreateSavePath(isMultiplayer ? SaveUtil.SaveType.Multiplayer : SaveUtil.SaveType.Singleplayer, saveNameBox.Text); bool hasRequiredContentPackages = selectedSub.RequiredContentPackagesInstalled; - CampaignSettings settings = new CampaignSettings { RadiationEnabled = EnableRadiationToggle?.Selected ?? GameMain.NetLobbyScreen.IsRadiationEnabled() }; + CampaignSettings settings = new CampaignSettings(); + if (isMultiplayer) + { + settings.RadiationEnabled = GameMain.NetLobbyScreen.IsRadiationEnabled(); + } + else + { + settings.RadiationEnabled = EnableRadiationToggle?.Selected ?? false; + } if (selectedSub.HasTag(SubmarineTag.Shuttle) || !hasRequiredContentPackages) { @@ -257,11 +265,14 @@ namespace Barotrauma if (!isMultiplayer) { - EnableRadiationToggle = new GUITickBox(new RectTransform(new Vector2(0.3f, 1f), buttonContainer.RectTransform), TextManager.Get("CampaignOption.EnableRadiation"), font: GUI.Style.Font) + if (MapGenerationParams.Instance.RadiationParams != null) { - Selected = true, - ToolTip = TextManager.Get("campaignoption.enableradiation.tooltip") - }; + EnableRadiationToggle = new GUITickBox(new RectTransform(new Vector2(0.3f, 1f), buttonContainer.RectTransform), TextManager.Get("CampaignOption.EnableRadiation"), font: GUI.Style.Font) + { + Selected = true, + ToolTip = TextManager.Get("campaignoption.enableradiation.tooltip") + }; + } var disclaimerBtn = new GUIButton(new RectTransform(new Vector2(1.0f, 0.8f), rightColumn.RectTransform, Anchor.TopRight) { AbsoluteOffset = new Point(5) }, style: "GUINotificationButton") { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignUI.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignUI.cs index 2210f080d..d57aaba8f 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignUI.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignUI.cs @@ -306,7 +306,7 @@ namespace Barotrauma { var map = GameMain.GameSession?.Map; if (map == null) { return; } - if (selectedLocation != null && selectedLocation == map.CurrentDisplayLocation) + if (selectedLocation != null && selectedLocation == GameMain.GameSession.Campaign.GetCurrentDisplayLocation()) { map.SelectLocation(-1); } @@ -438,7 +438,7 @@ namespace Barotrauma }; SelectedLevel = connection?.LevelData; - Location currentDisplayLocation = Campaign.CurrentDisplayLocation; + Location currentDisplayLocation = Campaign.GetCurrentDisplayLocation(); if (connection != null && connection.Locations.Contains(currentDisplayLocation)) { List availableMissions = currentDisplayLocation.GetMissionsInConnection(connection).ToList(); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs index 49d1430fe..6041af895 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs @@ -711,7 +711,7 @@ namespace Barotrauma.CharacterEditor } } // Camera - Cam.MoveCamera((float)deltaTime, allowMove: false); + Cam.MoveCamera((float)deltaTime, allowMove: false, allowZoom: GUI.MouseOn == null); Vector2 targetPos = character.WorldPosition; if (PlayerInput.MidButtonHeld()) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/EventEditor/EventEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/EventEditor/EventEditorScreen.cs index a475dafb4..1a891e878 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/EventEditor/EventEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/EventEditor/EventEditorScreen.cs @@ -953,7 +953,7 @@ namespace Barotrauma CreateGUI(); } - Cam.MoveCamera((float) deltaTime, true, true); + Cam.MoveCamera((float) deltaTime, allowMove: true, allowZoom: GUI.MouseOn == null); Vector2 mousePos = Cam.ScreenToWorld(PlayerInput.MousePosition); mousePos.Y = -mousePos.Y; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs index 0f22636f4..62fcc7ba7 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs @@ -843,7 +843,7 @@ namespace Barotrauma pointerLightSource.Position = cam.ScreenToWorld(PlayerInput.MousePosition); pointerLightSource.Enabled = cursorLightEnabled.Selected; pointerLightSource.IsBackground = true; - cam.MoveCamera((float)deltaTime); + cam.MoveCamera((float)deltaTime, allowZoom: GUI.MouseOn == null); cam.UpdateTransform(); Level.Loaded?.Update((float)deltaTime, cam); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen.cs index b7745a745..0a990cf75 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen.cs @@ -1173,7 +1173,10 @@ namespace Barotrauma (int)(campaignSetupUI.StartButton.TextBlock.TextSize.X * 1.5f), campaignSetupUI.StartButton.RectTransform.MinSize.Y); startButtonContainer.RectTransform.MinSize = new Point(0, campaignSetupUI.StartButton.RectTransform.MinSize.Y); - campaignSetupUI.EnableRadiationToggle.RectTransform.Parent = startButtonContainer.RectTransform; + if (campaignSetupUI.EnableRadiationToggle != null) + { + campaignSetupUI.EnableRadiationToggle.RectTransform.Parent = startButtonContainer.RectTransform; + } campaignSetupUI.InitialMoneyText.RectTransform.Parent = startButtonContainer.RectTransform; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs index c8e7ca975..6b3c45a76 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs @@ -485,6 +485,7 @@ namespace Barotrauma if (socialHolder != null) { socialHolder.Visible = false; } if (!(serverLogHolder?.Visible ?? true)) { + if (GameMain.Client?.ServerSettings?.ServerLog == null) { return false; } serverLogHolder.Visible = true; GameMain.Client.ServerSettings.ServerLog.AssignLogFrame(serverLogReverseButton, serverLogBox, serverLogFilterTicks.Content, serverLogFilter); } @@ -1134,15 +1135,19 @@ namespace Barotrauma } }; - radiationEnabledTickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.1f), settingsContent.RectTransform), TextManager.Get("CampaignOption.EnableRadiation"), font: GUI.Style.Font) + if (MapGenerationParams.Instance.RadiationParams != null) { - Selected = true, - OnSelected = box => + radiationEnabledTickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.1f), settingsContent.RectTransform), TextManager.Get("CampaignOption.EnableRadiation"), font: GUI.Style.Font) { - GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, radiationEnabled: box.Selected); - return true; - } - }; + Selected = true, + OnSelected = box => + { + GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, radiationEnabled: box.Selected); + return true; + } + }; + } + List settingsElements = settingsContent.Children.ToList(); for (int i = 0; i < settingsElements.Count; i++) @@ -1292,7 +1297,10 @@ namespace Barotrauma } SeedBox.Enabled = !CampaignFrame.Visible && !CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings); levelDifficultyScrollBar.Enabled = !CampaignFrame.Visible && !CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings); - radiationEnabledTickBox.Enabled = CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings); + if (radiationEnabledTickBox != null) + { + radiationEnabledTickBox.Enabled = CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings); + } traitorProbabilityButtons[0].Enabled = traitorProbabilityButtons[1].Enabled = traitorProbabilityText.Enabled = !CampaignFrame.Visible && !CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings); botCountButtons[0].Enabled = botCountButtons[1].Enabled = GameMain.Client.HasPermission(ClientPermissions.ManageSettings); @@ -2611,6 +2619,18 @@ namespace Barotrauma UserData = message, CanBeFocused = false }; + msg.CalculateHeightFromText(); + if (msg.RichTextData != null) + { + foreach (var data in msg.RichTextData) + { + msg.ClickableAreas.Add(new GUITextBlock.ClickableArea() + { + Data = data, + OnClick = GameMain.NetLobbyScreen.SelectPlayer + }); + } + } msg.RectTransform.SizeChanged += Recalculate; void Recalculate() { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/ParticleEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/ParticleEditorScreen.cs index 80e3a1c02..9924096cf 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/ParticleEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/ParticleEditorScreen.cs @@ -311,7 +311,7 @@ namespace Barotrauma public override void Update(double deltaTime) { - cam.MoveCamera((float)deltaTime, true); + cam.MoveCamera((float)deltaTime, allowMove: true, allowZoom: GUI.MouseOn == null); if (selectedPrefab != null) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs index b1d8f054f..cf0d71c47 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs @@ -4291,7 +4291,7 @@ namespace Barotrauma if (PlayerInput.IsCtrlDown() && MapEntity.StartMovingPos == Vector2.Zero) { - cam.MoveCamera((float) deltaTime, allowMove: false); + cam.MoveCamera((float) deltaTime, allowMove: false, allowZoom: GUI.MouseOn == null); // Save menu if (PlayerInput.KeyHit(Keys.S)) { @@ -4330,12 +4330,12 @@ namespace Barotrauma } else { - cam.MoveCamera((float) deltaTime, allowMove: true); + cam.MoveCamera((float) deltaTime, allowMove: true, allowZoom: GUI.MouseOn == null); } } else { - cam.MoveCamera((float) deltaTime, allowMove: false); + cam.MoveCamera((float) deltaTime, allowMove: false, allowZoom: GUI.MouseOn == null); } if (PlayerInput.MidButtonHeld()) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Sounds/OggSound.cs b/Barotrauma/BarotraumaClient/ClientSource/Sounds/OggSound.cs index 8f1f89246..7249c9972 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Sounds/OggSound.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Sounds/OggSound.cs @@ -105,7 +105,7 @@ namespace Barotrauma.Sounds int alError = Al.GetError(); if (alError != Al.NoError) { - throw new Exception("Failed to set buffer data for non-streamed audio! " + Al.GetErrorString(alError)); + throw new Exception("Failed to set regular buffer data for non-streamed audio! " + Al.GetErrorString(alError)); } MuffleBuffer(floatBuffer, SampleRate, reader.Channels); @@ -118,7 +118,7 @@ namespace Barotrauma.Sounds alError = Al.GetError(); if (alError != Al.NoError) { - throw new Exception("Failed to set buffer data for non-streamed audio! " + Al.GetErrorString(alError)); + throw new Exception("Failed to set muffled buffer data for non-streamed audio! " + Al.GetErrorString(alError)); } reader.Dispose(); reader = null; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Sounds/SoundBuffer.cs b/Barotrauma/BarotraumaClient/ClientSource/Sounds/SoundBuffer.cs index e02c58015..8cbcc5b37 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Sounds/SoundBuffer.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Sounds/SoundBuffer.cs @@ -34,6 +34,7 @@ namespace Barotrauma.Sounds { bufferPool.ForEach(b => Al.DeleteBuffer(b)); bufferPool.Clear(); + BuffersGenerated = 0; } public bool RequestAlBuffers() @@ -81,10 +82,37 @@ namespace Barotrauma.Sounds if (otherSound.IsPlaying()) { continue; } if (otherSound.Buffers == null) { continue; } if (otherSound.Buffers.AlBuffer == 0) { continue; } + + // Dispose all channels that are holding + // a reference to these buffers, otherwise + // an INVALID_OPERATION error will be thrown + // when attempting to set the buffer data later. + // Having the sources not play is not enough, + // as OpenAL assumes that you may want to call + // alSourcePlay without reassigning the buffer. + otherSound.Owner.KillChannels(otherSound); + AlBuffer = otherSound.Buffers.AlBuffer; AlMuffledBuffer = otherSound.Buffers.AlMuffledBuffer; otherSound.Buffers.AlBuffer = 0; otherSound.Buffers.AlMuffledBuffer = 0; + + // For performance reasons, sift the current sound to + // the end of the loadedSounds list, that way it'll + // be less likely to have its buffers stolen, which + // means less reuploads for frequently played sounds. + sound.Owner.MoveSoundToPosition(sound, sound.Owner.LoadedSoundCount-1); + + if (!Al.IsBuffer(AlBuffer)) + { + throw new Exception(sound.Filename + " has an invalid buffer!"); + } + if (!Al.IsBuffer(AlMuffledBuffer)) + { + throw new Exception(sound.Filename + " has an invalid muffled buffer!"); + } + + return true; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Sounds/SoundChannel.cs b/Barotrauma/BarotraumaClient/ClientSource/Sounds/SoundChannel.cs index 0a530b6d5..45a3e50bf 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Sounds/SoundChannel.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Sounds/SoundChannel.cs @@ -491,8 +491,10 @@ namespace Barotrauma.Sounds mutex = new object(); } +#if !DEBUG try { +#endif if (mutex != null) { Monitor.Enter(mutex); } if (sound.Owner.CountPlayingInstances(sound) < sound.MaxSimultaneousInstances) { @@ -515,15 +517,6 @@ namespace Barotrauma.Sounds Sound.FillBuffers(); } - if (!Al.IsBuffer(sound.Buffers.AlBuffer)) - { - throw new Exception(sound.Filename + " has an invalid buffer!"); - } - if (!Al.IsBuffer(sound.Buffers.AlMuffledBuffer)) - { - throw new Exception(sound.Filename + " has an invalid muffled buffer!"); - } - uint alBuffer = sound.Owner.GetCategoryMuffle(category) || muffled ? Sound.Buffers.AlMuffledBuffer : Sound.Buffers.AlBuffer; Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, (int)alBuffer); alError = Al.GetError(); @@ -587,6 +580,7 @@ namespace Barotrauma.Sounds this.Near = near; this.Far = far; this.Category = category; +#if !DEBUG } catch { @@ -594,8 +588,11 @@ namespace Barotrauma.Sounds } finally { +#endif if (mutex != null) { Monitor.Exit(mutex); } +#if !DEBUG } +#endif Sound.Owner.Update(); } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Sounds/SoundManager.cs b/Barotrauma/BarotraumaClient/ClientSource/Sounds/SoundManager.cs index 50056145f..d5defd0dd 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Sounds/SoundManager.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Sounds/SoundManager.cs @@ -514,6 +514,18 @@ namespace Barotrauma.Sounds } } + public void MoveSoundToPosition(Sound sound, int pos) + { + lock (loadedSounds) + { + int index = loadedSounds.IndexOf(sound); + if (index >= 0) + { + loadedSounds.SiftElement(index, pos); + } + } + } + public void SetCategoryGainMultiplier(string category, float gain, int index=0) { if (Disabled) { return; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Sprite/Sprite.cs b/Barotrauma/BarotraumaClient/ClientSource/Sprite/Sprite.cs index c4e17d9b7..2a86615d1 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Sprite/Sprite.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Sprite/Sprite.cs @@ -29,7 +29,16 @@ namespace Barotrauma get { return texture != null && !cannotBeLoaded; } } - public Sprite(Texture2D texture, Rectangle? sourceRectangle, Vector2? newOffset, float newRotation = 0.0f) + public Sprite(Sprite other) : this(other.texture, other.sourceRect, other.offset, other.rotation) + { + FilePath = other.FilePath; + FullPath = other.FullPath; + Compress = other.Compress; + size = other.size; + effects = other.effects; + } + + public Sprite(Texture2D texture, Rectangle? sourceRectangle, Vector2? newOffset, float newRotation = 0.0f, string path = null) { this.texture = texture; @@ -45,6 +54,8 @@ namespace Barotrauma rotation = newRotation; + FilePath = path; + AddToList(this); } diff --git a/Barotrauma/BarotraumaClient/LinuxClient.csproj b/Barotrauma/BarotraumaClient/LinuxClient.csproj index 55ef308e9..f05e71c00 100644 --- a/Barotrauma/BarotraumaClient/LinuxClient.csproj +++ b/Barotrauma/BarotraumaClient/LinuxClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.1300.0.3 + 0.1300.0.4 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/MacClient.csproj b/Barotrauma/BarotraumaClient/MacClient.csproj index b10d5ec10..d3951a6d7 100644 --- a/Barotrauma/BarotraumaClient/MacClient.csproj +++ b/Barotrauma/BarotraumaClient/MacClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.1300.0.3 + 0.1300.0.4 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/WindowsClient.csproj b/Barotrauma/BarotraumaClient/WindowsClient.csproj index 4f28bac29..e47974854 100644 --- a/Barotrauma/BarotraumaClient/WindowsClient.csproj +++ b/Barotrauma/BarotraumaClient/WindowsClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.1300.0.3 + 0.1300.0.4 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaServer/LinuxServer.csproj b/Barotrauma/BarotraumaServer/LinuxServer.csproj index 1d613f26e..a58ad1fe3 100644 --- a/Barotrauma/BarotraumaServer/LinuxServer.csproj +++ b/Barotrauma/BarotraumaServer/LinuxServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.1300.0.3 + 0.1300.0.4 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/MacServer.csproj b/Barotrauma/BarotraumaServer/MacServer.csproj index b8e7c5a84..0a8de3273 100644 --- a/Barotrauma/BarotraumaServer/MacServer.csproj +++ b/Barotrauma/BarotraumaServer/MacServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.1300.0.3 + 0.1300.0.4 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs b/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs index 7bd0c9b6e..a4ee8f123 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs @@ -367,7 +367,7 @@ namespace Barotrauma { if (CoroutineManager.IsCoroutineRunning("LevelTransition")) { return; } - Map?.Radiation.UpdateRadiation(deltaTime); + Map?.Radiation?.UpdateRadiation(deltaTime); base.Update(deltaTime); if (Level.Loaded != null) diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/ChatMessage.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/ChatMessage.cs index f23528e1d..c5757b5df 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/ChatMessage.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/ChatMessage.cs @@ -230,12 +230,16 @@ namespace Barotrauma.Networking 2 + //(UInt16)NetStateID 1 + //(byte)Type Encoding.UTF8.GetBytes(Text).Length + 2; - + + if (SenderClient != null) + { + length += 8; //SteamID or local ID (ulong) + } if (Sender != null && c.InGame) { length += 2; //sender ID (UInt16) } - else if (SenderName != null) + if (SenderName != null) { length += Encoding.UTF8.GetBytes(SenderName).Length + 2; } @@ -252,11 +256,16 @@ namespace Barotrauma.Networking msg.Write(Text); msg.Write(SenderName); + msg.Write(SenderClient != null); + msg.Write(SenderClient != null ? + ((SenderClient.SteamID != 0) ? SenderClient.SteamID : SenderClient.ID) : + 0); msg.Write(Sender != null && c.InGame); if (Sender != null && c.InGame) { msg.Write(Sender.ID); } + msg.WritePadBits(); if (Type == ChatMessageType.ServerMessageBoxInGame) { msg.Write(IconStyle); diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs index c0cef8f02..47ef711ac 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs @@ -938,6 +938,10 @@ namespace Barotrauma.Networking { errorLines.Add("Submarine: " + GameMain.GameSession.Submarine.Info.Name); } + if (GameMain.NetworkMember?.RespawnManager?.RespawnShuttle != null) + { + errorLines.Add("Respawn shuttle: " + GameMain.NetworkMember.RespawnManager.RespawnShuttle.Info.Name); + } if (Level.Loaded != null) { errorLines.Add("Level: " + Level.Loaded.Seed + ", " + string.Join(", ", Level.Loaded.EqualityCheckValues.Select(cv => cv.ToString("X")))); @@ -3111,7 +3115,7 @@ namespace Barotrauma.Networking string myReceivedMessage = type == ChatMessageType.Server || type == ChatMessageType.Error ? TextManager.GetServerMessage(message) : message; if (!string.IsNullOrWhiteSpace(myReceivedMessage)) { - AddChatMessage(myReceivedMessage, (ChatMessageType)type, senderName, senderCharacter); + AddChatMessage(myReceivedMessage, (ChatMessageType)type, senderName, senderClient, senderCharacter); } } } @@ -3778,18 +3782,6 @@ namespace Barotrauma.Networking } } - public static string ClientLogName(Client client, string name = null) - { - if (client == null) { return name; } - string retVal = "‖"; - if (client.Karma < 40.0f) - { - retVal += "color:#ff9900;"; - } - retVal += "metadata:" + (client.SteamID != 0 ? client.SteamID.ToString() : client.ID.ToString()) + "‖" + (name ?? client.Name).Replace("‖","") + "‖end‖"; - return retVal; - } - public static string CharacterLogName(Character character) { if (character == null) { return "[NULL]"; } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/OrderChatMessage.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/OrderChatMessage.cs index bdffaf263..061c05438 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/OrderChatMessage.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/OrderChatMessage.cs @@ -8,11 +8,16 @@ msg.Write(NetStateID); msg.Write((byte)ChatMessageType.Order); msg.Write(SenderName); + msg.Write(SenderClient != null); + msg.Write(SenderClient != null ? + ((SenderClient.SteamID != 0) ? SenderClient.SteamID : SenderClient.ID) : + 0); msg.Write(Sender != null && c.InGame); if (Sender != null && c.InGame) { msg.Write(Sender.ID); } + msg.WritePadBits(); WriteOrder(msg); } } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/Primitives/Peers/Server/ServerPeer.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/Primitives/Peers/Server/ServerPeer.cs index a392f34fe..c72467622 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/Primitives/Peers/Server/ServerPeer.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/Primitives/Peers/Server/ServerPeer.cs @@ -212,7 +212,7 @@ namespace Barotrauma.Networking return; } - if (connectedClients.Count >= serverSettings.MaxPlayers - 1) + if (connectedClients.Count >= serverSettings.MaxPlayers) { RemovePendingClient(pendingClient, DisconnectReason.ServerFull, ""); } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/Voting.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/Voting.cs index f00dec7dd..acb320756 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/Voting.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/Voting.cs @@ -65,7 +65,7 @@ namespace Barotrauma public void ServerRead(IReadMessage inc, Client sender) { - if (GameMain.Server == null || sender == null) return; + if (GameMain.Server == null || sender == null) { return; } byte voteTypeByte = inc.ReadByte(); VoteType voteType = VoteType.Unknown; @@ -83,7 +83,10 @@ namespace Barotrauma { case VoteType.Sub: int equalityCheckVal = inc.ReadInt32(); - SubmarineInfo sub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.EqualityCheckVal == equalityCheckVal); + string hash = equalityCheckVal > 0 ? string.Empty : inc.ReadString(); + SubmarineInfo sub = equalityCheckVal > 0 ? + SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Type == SubmarineType.Player && s.EqualityCheckVal == equalityCheckVal) : + SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Type == SubmarineType.Player && s.MD5Hash.Hash == hash); sender.SetVote(voteType, sub); break; case VoteType.Mode: diff --git a/Barotrauma/BarotraumaServer/WindowsServer.csproj b/Barotrauma/BarotraumaServer/WindowsServer.csproj index ca4eeec0d..2bd87c45a 100644 --- a/Barotrauma/BarotraumaServer/WindowsServer.csproj +++ b/Barotrauma/BarotraumaServer/WindowsServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.1300.0.3 + 0.1300.0.4 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs index bb8e6a12f..4b6234ea5 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs @@ -265,16 +265,22 @@ namespace Barotrauma } } - public void UnequipEmptyItems(Item item, bool avoidDroppingInSea = true) => UnequipEmptyItems(Character, item, avoidDroppingInSea); + public void UnequipEmptyItems(Item parentItem, bool avoidDroppingInSea = true) => UnequipEmptyItems(Character, parentItem, avoidDroppingInSea); - public static void UnequipEmptyItems(Character character, Item item, bool avoidDroppingInSea = true) + public void UnequipContainedItems(Item parentItem, Func predicate, bool avoidDroppingInSea = true) => UnequipContainedItems(Character, parentItem, predicate, avoidDroppingInSea); + + public static void UnequipEmptyItems(Character character, Item parentItem, bool avoidDroppingInSea = true) => UnequipContainedItems(character, parentItem, it => it.Condition <= 0, avoidDroppingInSea); + + public static void UnequipContainedItems(Character character, Item parentItem, Func predicate, bool avoidDroppingInSea = true) { - if (item.OwnInventory.AllItems.Any(it => it.Condition <= 0.0f)) + var inventory = parentItem.OwnInventory; + if (inventory == null) { return; } + if (inventory.AllItems.Any(predicate)) { - foreach (Item containedItem in item.OwnInventory.AllItemsMod) + foreach (Item containedItem in inventory.AllItemsMod) { if (containedItem == null) { continue; } - if (containedItem.Condition <= 0.0f) + if (predicate(containedItem)) { if (character.Submarine == null && avoidDroppingInSea) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs index 7119b258b..dcc521f3a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs @@ -181,6 +181,7 @@ namespace Barotrauma private set; } = new HashSet(); + public bool IsTargetingPlayer => SelectedAiTarget?.Entity?.Submarine != null && SelectedAiTarget.Entity.Submarine.Info.IsPlayer || SelectedAiTarget?.Entity is Character targetCharacter && targetCharacter.IsPlayer; public bool IsBeingChasedBy(Character c) => c.AIController is EnemyAIController enemyAI && enemyAI.SelectedAiTarget?.Entity is Character && (enemyAI.State == AIState.Aggressive || enemyAI.State == AIState.Attack); private bool IsBeingChased => SelectedAiTarget?.Entity is Character targetCharacter && IsBeingChasedBy(targetCharacter); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/HumanAIController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/HumanAIController.cs index eea5366db..cbcf87483 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/HumanAIController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/HumanAIController.cs @@ -771,17 +771,11 @@ namespace Barotrauma targetHull = hull; } } - foreach (var ballastFlora in MapCreatures.Behavior.BallastFloraBehavior.EntityList) + if (IsBallastFloraNoticeable(Character, hull)) { - if (ballastFlora.Parent?.Submarine != Character.Submarine) { continue; } - if (!ballastFlora.HasBrokenThrough) { continue; } - // Don't react to the first two branches, because they are usually in the very edges of the room. - if (ballastFlora.Branches.Count(b => !b.Removed && b.Health > 0 && b.CurrentHull == hull) > 2) - { - var orderPrefab = Order.GetPrefab("reportballastflora"); - newOrder = new Order(orderPrefab, hull, null, orderGiver: Character); - targetHull = hull; - } + var orderPrefab = Order.GetPrefab("reportballastflora"); + newOrder = new Order(orderPrefab, hull, null, orderGiver: Character); + targetHull = hull; } if (!isFighting) { @@ -848,6 +842,21 @@ namespace Barotrauma } } + public static bool IsBallastFloraNoticeable(Character character, Hull hull) + { + foreach (var ballastFlora in MapCreatures.Behavior.BallastFloraBehavior.EntityList) + { + if (ballastFlora.Parent?.Submarine != character.Submarine) { continue; } + if (!ballastFlora.HasBrokenThrough) { continue; } + // Don't react to the first two branches, because they are usually in the very edges of the room. + if (ballastFlora.Branches.Count(b => !b.Removed && b.Health > 0 && b.CurrentHull == hull) > 2) + { + return true; + } + } + return false; + } + public static void ReportProblem(Character reporter, Order order) { if (reporter == null || order == null) { return; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFindDivingGear.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFindDivingGear.cs index 4c11ccbcc..3cecff6d8 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFindDivingGear.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFindDivingGear.cs @@ -58,16 +58,10 @@ namespace Barotrauma } else { - if (!EjectEmptyTanks(character, targetItem, out var containedItems)) - { -#if DEBUG - DebugConsole.ThrowError($"{character.Name}: AIObjectiveFindDivingGear failed - the item \"" + targetItem + "\" has no proper inventory"); -#endif - Abandon = true; - return; - } + HumanAIController.UnequipContainedItems(targetItem, it => !it.HasTag("oxygensource")); + HumanAIController.UnequipEmptyItems(targetItem); float min = character.Submarine == null ? 0.01f : MIN_OXYGEN; - if (containedItems.None(it => it != null && it.HasTag(OXYGEN_SOURCE) && it.Condition > min)) + if (targetItem.OwnInventory != null && targetItem.OwnInventory.AllItems.None(it => it != null && it.HasTag(OXYGEN_SOURCE) && it.Condition > min)) { // No valid oxygen source loaded. // Seek oxygen that has at least 10% condition left. diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFixLeak.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFixLeak.cs index f3ede74d6..3b6b38a69 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFixLeak.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFixLeak.cs @@ -86,10 +86,9 @@ namespace Barotrauma Abandon = true; return; } - // Drop empty tanks + HumanAIController.UnequipContainedItems(weldingTool, it => !it.HasTag("weldingfuel")); HumanAIController.UnequipEmptyItems(weldingTool); - - if (weldingTool.OwnInventory.AllItems.None(i => i.HasTag("weldingfuel") && i.Condition > 0.0f)) + if (weldingTool.OwnInventory != null && weldingTool.OwnInventory.AllItems.None(i => i.HasTag("weldingfuel") && i.Condition > 0.0f)) { TryAddSubObjective(ref refuelObjective, () => new AIObjectiveContainItem(character, "weldingfuel", weldingTool.GetComponent(), objectiveManager, spawnItemIfNotFound: character.TeamID == CharacterTeamType.FriendlyNPC), onAbandon: () => diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs index ab3574641..6e4046bb5 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs @@ -122,7 +122,7 @@ namespace Barotrauma Abandon = true; return; } - // Eject empty tanks + HumanAIController.UnequipContainedItems(repairTool.Item, it => !it.HasTag("weldingfuel")); HumanAIController.UnequipEmptyItems(repairTool.Item); RelatedItem item = null; Item fuel = null; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItems.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItems.cs index 01fcadd83..1c020742f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItems.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItems.cs @@ -153,6 +153,8 @@ namespace Barotrauma if (item.IsFullCondition) { return false; } if (item.CurrentHull == null) { return false; } if (item.Submarine == null || character.Submarine == null) { return false; } + //player crew ignores items in outposts + if (character.IsOnPlayerTeam && item.Submarine.Info.IsOutpost) { return false; } if (!character.Submarine.IsEntityFoundOnThisSub(item, includingConnectedSubs: true)) { return false; } if (item.Repairables.None()) { return false; } return true; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescue.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescue.cs index a433d8b52..3c0fdd972 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescue.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescue.cs @@ -78,14 +78,14 @@ namespace Barotrauma // Check if the character needs more oxygen if (!ignoreOxygen && character.SelectedCharacter == targetCharacter || character.CanInteractWith(targetCharacter)) { - // Replace empty oxygen tank - // First remove empty tanks + // Replace empty oxygen and welding fuel. if (HumanAIController.HasItem(targetCharacter, AIObjectiveFindDivingGear.HEAVY_DIVING_GEAR, out IEnumerable suits, requireEquipped: true)) { Item suit = suits.FirstOrDefault(); if (suit != null) { - AIObjectiveFindDivingGear.EjectEmptyTanks(character, suit, out _); + AIController.UnequipEmptyItems(character, suit); + AIController.UnequipContainedItems(character, suit, it => it.HasTag("weldingfuel")); } } else if (HumanAIController.HasItem(targetCharacter, AIObjectiveFindDivingGear.LIGHT_DIVING_GEAR, out IEnumerable masks, requireEquipped: true)) @@ -93,7 +93,8 @@ namespace Barotrauma Item mask = masks.FirstOrDefault(); if (mask != null) { - AIObjectiveFindDivingGear.EjectEmptyTanks(character, mask, out _); + AIController.UnequipEmptyItems(character, mask); + AIController.UnequipContainedItems(character, mask, it => it.HasTag("weldingfuel")); } } bool ShouldRemoveDivingSuit() => targetCharacter.OxygenAvailable < CharacterHealth.InsufficientOxygenThreshold && targetCharacter.CurrentHull?.LethalPressure <= 0; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PathFinder.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PathFinder.cs index 92de10a84..08ed530f3 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PathFinder.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PathFinder.cs @@ -35,7 +35,7 @@ namespace Barotrauma WayPointID = Waypoint.ID; } - public static List GenerateNodes(List wayPoints) + public static List GenerateNodes(List wayPoints, bool removeOrphans) { var nodes = new Dictionary(); foreach (WayPoint wayPoint in wayPoints) @@ -63,7 +63,10 @@ namespace Barotrauma } var nodeList = nodes.Values.ToList(); - nodeList.RemoveAll(n => n.connections.Count == 0); + if (removeOrphans) + { + nodeList.RemoveAll(n => n.connections.Count == 0); + } foreach (PathNode node in nodeList) { node.distances = new List(); @@ -90,7 +93,7 @@ namespace Barotrauma public PathFinder(List wayPoints, bool indoorsSteering = false) { - nodes = PathNode.GenerateNodes(wayPoints.FindAll(w => w.Submarine != null == indoorsSteering)); + nodes = PathNode.GenerateNodes(wayPoints.FindAll(w => w.Submarine != null == indoorsSteering), removeOrphans: true); foreach (WayPoint wp in wayPoints) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs index 188707322..469f96125 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs @@ -69,8 +69,8 @@ namespace Barotrauma /// public bool IsRemotelyControlled { - get - { + get + { if (GameMain.NetworkMember == null) { return false; @@ -145,14 +145,8 @@ namespace Barotrauma } private readonly List lastAttackers = new List(); - public IEnumerable LastAttackers - { - get { return lastAttackers; } - } - public Character LastAttacker - { - get { return lastAttackers.Count > 0 ? lastAttackers[lastAttackers.Count - 1].Character : null; } - } + public IEnumerable LastAttackers => lastAttackers; + public Character LastAttacker => lastAttackers.LastOrDefault()?.Character; public Entity LastDamageSource; @@ -203,7 +197,7 @@ namespace Barotrauma public bool IsTraitor { - get; + get; set; } @@ -442,7 +436,7 @@ namespace Barotrauma /// public IEnumerable HeldItems { - get + get { var item1 = Inventory?.GetItemInLimbSlot(InvSlotType.RightHand); var item2 = Inventory?.GetItemInLimbSlot(InvSlotType.LeftHand); @@ -527,7 +521,7 @@ namespace Barotrauma } public bool UseHullOxygen { get; set; } = true; - + public float Stun { get { return IsRagdolled ? 1.0f : CharacterHealth.Stun; } @@ -601,7 +595,7 @@ namespace Barotrauma { get; set; - } + } /// /// Current speed of the character's collider. Can be used by status effects to check if the character is moving. @@ -655,11 +649,11 @@ namespace Barotrauma } private bool isDead; - public bool IsDead - { + public bool IsDead + { get { return isDead; } - set - { + set + { if (isDead == value) { return; } if (value) { @@ -822,7 +816,7 @@ namespace Barotrauma speciesName = Path.GetFileNameWithoutExtension(speciesName).ToLowerInvariant(); } - var prefab = CharacterPrefab.FindBySpeciesName(speciesName); + var prefab = CharacterPrefab.FindBySpeciesName(speciesName); if (prefab == null) { DebugConsole.ThrowError($"Failed to create character \"{speciesName}\". Matching prefab not found.\n" + Environment.StackTrace); @@ -2191,8 +2185,7 @@ namespace Barotrauma #if CLIENT if (isLocalPlayer) { - if (GUI.MouseOn == null && - (!CharacterInventory.IsMouseOnInventory() || CharacterInventory.DraggingItemToWorld)) + if (!IsMouseOnUI) { if (findFocusedTimer <= 0.0f || Screen.Selected == GameMain.SubEditorScreen) { @@ -2910,7 +2903,7 @@ namespace Barotrauma } } - // Prevent adding duplicate orders (same identifier and same option) + // Prevent adding duplicate orders RemoveDuplicateOrders(order, orderOption); OrderInfo newOrderInfo = new OrderInfo(order, orderOption, priority); @@ -2971,7 +2964,7 @@ namespace Barotrauma for (int i = CurrentOrders.Count - 1; i >= 0; i--) { var orderInfo = CurrentOrders[i]; - if (orderInfo.MatchesOrder(order, option)) + if (order?.Identifier == orderInfo.Order?.Identifier) { priorityOfRemoved = orderInfo.ManualPriority; CurrentOrders.RemoveAt(i); @@ -3316,6 +3309,13 @@ namespace Barotrauma if (attacker.TeamID == TeamID) { return new AttackResult(); } } +#if CLIENT + if (attacker == Controlled && Controlled != null && Params.UseBossHealthBar) + { + CharacterHUD.ShowBossHealthBar(this); + } +#endif + Vector2 dir = hitLimb.WorldPosition - worldPosition; if (Math.Abs(attackImpulse) > 0.0f) { @@ -3351,14 +3351,14 @@ namespace Barotrauma if (attackResult.Damage > 0) { LastDamage = attackResult; - ApplyStatusEffects(ActionType.OnDamaged, 1.0f); - hitLimb.ApplyStatusEffects(ActionType.OnDamaged, 1.0f); if (attacker != null) { AddAttacker(attacker, attackResult.Damage); AddEncounter(attacker); attacker.AddEncounter(this); } + ApplyStatusEffects(ActionType.OnDamaged, 1.0f); + hitLimb.ApplyStatusEffects(ActionType.OnDamaged, 1.0f); } return attackResult; } @@ -3418,6 +3418,16 @@ namespace Barotrauma foreach (StatusEffect statusEffect in statusEffects) { if (statusEffect.type != actionType) { continue; } + if (statusEffect.type == ActionType.OnDamaged) + { + if (statusEffect.OnlyPlayerTriggered) + { + if (LastAttacker == null || !LastAttacker.IsPlayer) + { + continue; + } + } + } if (statusEffect.HasTargetType(StatusEffect.TargetType.NearbyItems) || statusEffect.HasTargetType(StatusEffect.TargetType.NearbyCharacters)) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionHusk.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionHusk.cs index 2bc993c17..70de29313 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionHusk.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionHusk.cs @@ -148,10 +148,9 @@ namespace Barotrauma } } - public void Remove() + public void UnsubscribeFromDeathEvent() { - if (character == null) { return; } - DeactivateHusk(); + if (character == null || !subscribedToDeathEvent) { return; } character.OnDeath -= CharacterDead; subscribedToDeathEvent = false; } @@ -159,7 +158,11 @@ namespace Barotrauma private void CharacterDead(Character character, CauseOfDeath causeOfDeath) { if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; } - if (Strength < ActiveThreshold || character.Removed) { return; } + if (Strength < ActiveThreshold || character.Removed) + { + UnsubscribeFromDeathEvent(); + return; + } //don't turn the character into a husk if any of its limbs are severed if (character.AnimController?.LimbJoints != null) @@ -185,6 +188,7 @@ namespace Barotrauma character.Enabled = false; Entity.Spawner.AddToRemoveQueue(character); + UnsubscribeFromDeathEvent(); string huskedSpeciesName = GetHuskedSpeciesName(character.SpeciesName, Prefab as AfflictionPrefabHusk); CharacterPrefab prefab = CharacterPrefab.FindBySpeciesName(huskedSpeciesName); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionPrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionPrefab.cs index 4076e1c6d..645fefcea 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionPrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionPrefab.cs @@ -613,9 +613,6 @@ namespace Barotrauma case "icon": Icon = new Sprite(subElement); break; - case "periodiceffect": - periodicEffects.Add(new PeriodicEffect(subElement, Name)); - break; } } @@ -649,6 +646,9 @@ namespace Barotrauma case "effect": effects.Add(new Effect(subElement, Name)); break; + case "periodiceffect": + periodicEffects.Add(new PeriodicEffect(subElement, Name)); + break; } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Limb.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Limb.cs index e08596e97..7f3a83ed3 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Limb.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Limb.cs @@ -1125,6 +1125,16 @@ namespace Barotrauma foreach (StatusEffect statusEffect in statusEffects) { if (statusEffect.type != actionType) { continue; } + if (statusEffect.type == ActionType.OnDamaged) + { + if (statusEffect.OnlyPlayerTriggered) + { + if (character.LastAttacker == null || !character.LastAttacker.IsPlayer) + { + continue; + } + } + } if (statusEffect.HasTargetType(StatusEffect.TargetType.NearbyItems) || statusEffect.HasTargetType(StatusEffect.TargetType.NearbyCharacters)) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs index 988de5809..d8aa2419a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs @@ -49,6 +49,9 @@ namespace Barotrauma [Serialize(false, false), Editable] public bool CanSpeak { get; set; } + [Serialize(false, true), Editable] + public bool UseBossHealthBar { get; private set; } + [Serialize(100f, true, description: "How much noise the character makes when moving?"), Editable(minValue: 0f, maxValue: 100000f)] public float Noise { get; set; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Decals/DecalManager.cs b/Barotrauma/BarotraumaShared/SharedSource/Decals/DecalManager.cs index b107eac25..277efee1c 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Decals/DecalManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Decals/DecalManager.cs @@ -110,13 +110,14 @@ namespace Barotrauma public Decal CreateDecal(string decalName, float scale, Vector2 worldPosition, Hull hull, int? spriteIndex = null) { - if (!Prefabs.ContainsKey(decalName.ToLowerInvariant())) + string lowerCaseDecalName = decalName.ToLowerInvariant(); + if (!Prefabs.ContainsKey(lowerCaseDecalName)) { DebugConsole.ThrowError("Decal prefab " + decalName + " not found!"); return null; } - DecalPrefab prefab = Prefabs[decalName]; + DecalPrefab prefab = Prefabs[lowerCaseDecalName]; return new Decal(prefab, scale, worldPosition, hull, spriteIndex); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/EventPrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/EventPrefab.cs index 3cdcf4b37..d605651cc 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/EventPrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/EventPrefab.cs @@ -66,5 +66,10 @@ namespace Barotrauma return (Event)instance; } + + public override string ToString() + { + return $"EventPrefab ({Identifier})"; + } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/MonsterEvent.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/MonsterEvent.cs index 80ac6f8ac..032daf700 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/MonsterEvent.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/MonsterEvent.cs @@ -299,6 +299,13 @@ namespace Barotrauma System.Diagnostics.Debug.Assert(spawnPoint.ParentRuin == chosenPosition.Ruin); spawnPos = spawnPoint.WorldPosition; } + else + { + //no suitable position found, disable the event + spawnPos = null; + Finished(); + return; + } } else if ((chosenPosition.PositionType == Level.PositionType.MainPath || chosenPosition.PositionType == Level.PositionType.SidePath) && offset > 0) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/ScriptedEvent.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/ScriptedEvent.cs index 50fe57605..779136e9c 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/ScriptedEvent.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/ScriptedEvent.cs @@ -22,7 +22,7 @@ namespace Barotrauma public override string ToString() { - return "ScriptedEvent (" + prefab.EventType.ToString() +")"; + return $"ScriptedEvent ({prefab.Identifier})"; } public ScriptedEvent(EventPrefab prefab) : base(prefab) diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/CrewManager.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/CrewManager.cs index 5167bce56..0c9cf2706 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/CrewManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/CrewManager.cs @@ -71,10 +71,13 @@ namespace Barotrauma else if (!isUnignoreOrder) { ActiveOrders.Add(new Pair(order, fadeOutTime)); +#if CLIENT + HintManager.OnActiveOrderAdded(order); +#endif return true; } - bool MatchesTarget(Entity existingTarget, Entity newTarget) + static bool MatchesTarget(Entity existingTarget, Entity newTarget) { if (existingTarget == newTarget) { return true; } if (existingTarget is Hull existingHullTarget && newTarget is Hull newHullTarget) diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs index daaa46986..6e96753f0 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs @@ -148,28 +148,26 @@ namespace Barotrauma /// The location that's displayed as the "current one" in the map screen. Normally the current outpost or the location at the start of the level, /// but when selecting the next destination at the end of the level at an uninhabited location we use the location at the end /// - public Location CurrentDisplayLocation + public Location GetCurrentDisplayLocation() { - get + if (Level.Loaded?.EndLocation != null && !Level.Loaded.Generating && + Level.Loaded.Type == LevelData.LevelType.LocationConnection && + GetAvailableTransition(out _, out _) == TransitionType.ProgressToNextEmptyLocation) { - if (Level.Loaded?.EndLocation != null && !Level.Loaded.Generating && - Level.Loaded.Type == LevelData.LevelType.LocationConnection && - GetAvailableTransition(out _, out _) == TransitionType.ProgressToNextEmptyLocation) - { - return Level.Loaded.EndLocation; - } - return Level.Loaded?.StartLocation ?? Map.CurrentLocation; + return Level.Loaded.EndLocation; } + return Level.Loaded?.StartLocation ?? Map.CurrentLocation; } public List GetSubsToLeaveBehind(Submarine leavingSub) { //leave subs behind if they're not docked to the leaving sub and not at the same exit - return Submarine.Loaded.FindAll(s => - s != leavingSub && - !leavingSub.DockedTo.Contains(s) && - s.Info.Type == SubmarineType.Player && - (s.AtEndExit != leavingSub.AtEndExit || s.AtStartExit != leavingSub.AtStartExit)); + return Submarine.Loaded.FindAll(sub => + sub != leavingSub && + !leavingSub.DockedTo.Contains(sub) && + sub.Info.Type == SubmarineType.Player && + sub != GameMain.NetworkMember?.RespawnManager?.RespawnShuttle && + (sub.AtEndExit != leavingSub.AtEndExit || sub.AtStartExit != leavingSub.AtStartExit)); } public override void Start() @@ -476,7 +474,7 @@ namespace Barotrauma { if (Level.Loaded.StartOutpost == null) { - Submarine closestSub = Submarine.FindClosest(Level.Loaded.StartExitPosition, ignoreOutposts: true); + Submarine closestSub = Submarine.FindClosest(Level.Loaded.StartExitPosition, ignoreOutposts: true, ignoreRespawnShuttle: true); return closestSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : closestSub; } else @@ -490,7 +488,7 @@ namespace Barotrauma //nothing docked, check if there's a sub close enough to the outpost and someone inside the outpost if (Level.Loaded.Type == LevelData.LevelType.LocationConnection && !leavingPlayers.Any(s => s.Submarine == Level.Loaded.StartOutpost)) { return null; } - Submarine closestSub = Submarine.FindClosest(Level.Loaded.StartOutpost.WorldPosition, ignoreOutposts: true); + Submarine closestSub = Submarine.FindClosest(Level.Loaded.StartOutpost.WorldPosition, ignoreOutposts: true, ignoreRespawnShuttle: true); if (closestSub == null || !closestSub.AtStartExit) { return null; } return closestSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : closestSub; } @@ -503,7 +501,7 @@ namespace Barotrauma if (Level.Loaded.EndOutpost == null) { - Submarine closestSub = Submarine.FindClosest(Level.Loaded.EndPosition, ignoreOutposts: true); + Submarine closestSub = Submarine.FindClosest(Level.Loaded.EndPosition, ignoreOutposts: true, ignoreRespawnShuttle: true); return closestSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : closestSub; } else @@ -517,7 +515,7 @@ namespace Barotrauma //nothing docked, check if there's a sub close enough to the outpost and someone inside the outpost if (Level.Loaded.Type == LevelData.LevelType.LocationConnection && !leavingPlayers.Any(s => s.Submarine == Level.Loaded.EndOutpost)) { return null; } - Submarine closestSub = Submarine.FindClosest(Level.Loaded.EndOutpost.WorldPosition, ignoreOutposts: true); + Submarine closestSub = Submarine.FindClosest(Level.Loaded.EndOutpost.WorldPosition, ignoreOutposts: true, ignoreRespawnShuttle: true); if (closestSub == null || !closestSub.AtEndExit) { return null; } return closestSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : closestSub; } @@ -625,7 +623,10 @@ namespace Barotrauma } Map.SetLocation(Map.Locations.IndexOf(Map.StartLocation)); Map.SelectLocation(-1); - Map.Radiation.Amount = Map.Radiation.Params.StartingRadiation; + if (Map.Radiation != null) + { + Map.Radiation.Amount = Map.Radiation.Params.StartingRadiation; + } foreach (Location location in Map.Locations) { location.TurnsInRadiation = 0; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/DockingPort.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/DockingPort.cs index 91a87c839..dabd8d959 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/DockingPort.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/DockingPort.cs @@ -875,6 +875,7 @@ namespace Barotrauma.Items.Components Item.Submarine.EnableObstructedWaypoints(DockingTarget.Item.Submarine); obstructedWayPointsDisabled = false; + Item.Submarine.RefreshOutdoorNodes(); DockingTarget.Undock(); DockingTarget = null; @@ -1000,6 +1001,7 @@ namespace Barotrauma.Items.Components if (!obstructedWayPointsDisabled && dockingState >= 0.99f) { Item.Submarine.DisableObstructedWayPoints(DockingTarget?.Item.Submarine); + Item.Submarine.RefreshOutdoorNodes(); obstructedWayPointsDisabled = true; } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/AndComponent.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/AndComponent.cs index 68baf4a5a..2c5b8ba0e 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/AndComponent.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/AndComponent.cs @@ -31,7 +31,7 @@ namespace Barotrauma.Items.Components { if (value == null) { return; } output = value; - if (output.Length > MaxOutputLength) + if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading)) { output = output.Substring(0, MaxOutputLength); } @@ -46,7 +46,7 @@ namespace Barotrauma.Items.Components { if (value == null) { return; } falseOutput = value; - if (falseOutput.Length > MaxOutputLength) + if (falseOutput.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading)) { falseOutput = falseOutput.Substring(0, MaxOutputLength); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/Connection.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/Connection.cs index b825e42b5..7f3d24709 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/Connection.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/Connection.cs @@ -1,5 +1,4 @@ -using Microsoft.Xna.Framework; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Xml.Linq; @@ -11,7 +10,10 @@ namespace Barotrauma.Items.Components //how many wires can be linked to connectors by default private const int DefaultMaxWires = 5; - //how many wires can be linked to this connection + //how many wires a player can link to this connection + public readonly int MaxPlayerConnectableWires = 5; + + //how many wires can be linked to this connection in total public readonly int MaxWires = 5; public readonly string Name; @@ -81,6 +83,7 @@ namespace Barotrauma.Items.Components item = connectionPanel.Item; MaxWires = element.GetAttributeInt("maxwires", DefaultMaxWires); + MaxPlayerConnectableWires = element.GetAttributeInt("maxplayerconnectablewires", MaxWires); wires = new Wire[MaxWires]; IsOutput = element.Name.ToString() == "output"; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/CustomInterface.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/CustomInterface.cs index d88cc06a6..a97527ea6 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/CustomInterface.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/CustomInterface.cs @@ -16,13 +16,18 @@ namespace Barotrauma.Items.Components [Serialize("", false, translationTextTag: "Label.", description: "The text displayed on this button/tickbox."), Editable] public string Label { get; set; } + [Serialize("1", false, description: "The signal sent out when this button is pressed or this tickbox checked."), Editable] public string Signal { get; set; } public string PropertyName { get; } public bool TargetOnlyParentProperty { get; } + public int NumberInputMin { get; } public int NumberInputMax { get; } + + public int MaxTextLength { get; } + public const int DefaultNumberInputMin = 0, DefaultNumberInputMax = 99; public bool IsIntegerInput { get; } public bool HasPropertyName { get; } @@ -46,7 +51,7 @@ namespace Barotrauma.Items.Components TargetOnlyParentProperty = element.GetAttributeBool("targetonlyparentproperty", false); NumberInputMin = element.GetAttributeInt("min", DefaultNumberInputMin); NumberInputMax = element.GetAttributeInt("max", DefaultNumberInputMax); - + MaxTextLength = element.GetAttributeInt("maxtextlength", int.MaxValue); HasPropertyName = !string.IsNullOrEmpty(PropertyName); IsIntegerInput = HasPropertyName && element.Name.ToString().ToLowerInvariant() == "integerinput"; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/EqualsComponent.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/EqualsComponent.cs index 0d4206765..48296b87b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/EqualsComponent.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/EqualsComponent.cs @@ -23,7 +23,7 @@ namespace Barotrauma.Items.Components { if (value == null) { return; } output = value; - if (output.Length > MaxOutputLength) + if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading)) { output = output.Substring(0, MaxOutputLength); } @@ -38,7 +38,7 @@ namespace Barotrauma.Items.Components { if (value == null) { return; } falseOutput = value; - if (falseOutput.Length > MaxOutputLength) + if (falseOutput.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading)) { falseOutput = falseOutput.Substring(0, MaxOutputLength); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/MotionSensor.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/MotionSensor.cs index f92e62f4d..3f2a1a3a2 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/MotionSensor.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/MotionSensor.cs @@ -83,7 +83,7 @@ namespace Barotrauma.Items.Components { if (value == null) { return; } output = value; - if (output.Length > MaxOutputLength) + if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading)) { output = output.Substring(0, MaxOutputLength); } @@ -99,7 +99,7 @@ namespace Barotrauma.Items.Components { if (value == null) { return; } falseOutput = value; - if (falseOutput.Length > MaxOutputLength) + if (falseOutput.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading)) { falseOutput = falseOutput.Substring(0, MaxOutputLength); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/RegExFindComponent.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/RegExFindComponent.cs index 4f7344c44..cf86b139c 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/RegExFindComponent.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/RegExFindComponent.cs @@ -28,7 +28,7 @@ namespace Barotrauma.Items.Components { if (value == null) { return; } output = value; - if (output.Length > MaxOutputLength) + if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading)) { output = output.Substring(0, MaxOutputLength); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/SignalCheckComponent.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/SignalCheckComponent.cs index bd35f1731..3a0ce8ba1 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/SignalCheckComponent.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/SignalCheckComponent.cs @@ -14,7 +14,7 @@ namespace Barotrauma.Items.Components { if (value == null) { return; } output = value; - if (output.Length > MaxOutputLength) + if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading)) { output = output.Substring(0, MaxOutputLength); } @@ -30,7 +30,7 @@ namespace Barotrauma.Items.Components { if (value == null) { return; } falseOutput = value; - if (falseOutput.Length > MaxOutputLength) + if (falseOutput.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading)) { falseOutput = falseOutput.Substring(0, MaxOutputLength); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/SmokeDetector.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/SmokeDetector.cs index 122c056bc..e0d4a3a38 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/SmokeDetector.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/SmokeDetector.cs @@ -19,7 +19,7 @@ namespace Barotrauma.Items.Components { if (value == null) { return; } output = value; - if (output.Length > MaxOutputLength) + if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading)) { output = output.Substring(0, MaxOutputLength); } @@ -35,7 +35,7 @@ namespace Barotrauma.Items.Components { if (value == null) { return; } falseOutput = value; - if (falseOutput.Length > MaxOutputLength) + if (falseOutput.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading)) { falseOutput = falseOutput.Substring(0, MaxOutputLength); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/WaterDetector.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/WaterDetector.cs index 306458b79..97ee74d54 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/WaterDetector.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/WaterDetector.cs @@ -21,7 +21,7 @@ namespace Barotrauma.Items.Components { if (value == null) { return; } output = value; - if (output.Length > MaxOutputLength) + if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading)) { output = output.Substring(0, MaxOutputLength); } @@ -37,7 +37,7 @@ namespace Barotrauma.Items.Components { if (value == null) { return; } falseOutput = value; - if (falseOutput.Length > MaxOutputLength) + if (falseOutput.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading)) { falseOutput = falseOutput.Substring(0, MaxOutputLength); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs index a9623d15d..61612c0af 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs @@ -348,7 +348,7 @@ namespace Barotrauma { if (AiTarget != null) { - AiTarget.SonarLabel = value; + AiTarget.SonarLabel = !string.IsNullOrEmpty(value) && value.Length > 200 ? value.Substring(200) : value; } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/ItemInventory.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/ItemInventory.cs index e2e783677..83e469f31 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/ItemInventory.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/ItemInventory.cs @@ -111,7 +111,7 @@ namespace Barotrauma public override bool TryPutItem(Item item, int i, bool allowSwapping, bool allowCombine, Character user, bool createNetworkEvent = true) { bool wasPut = base.TryPutItem(item, i, allowSwapping, allowCombine, user, createNetworkEvent); - if (wasPut) + if (wasPut && item.ParentInventory == this) { foreach (Character c in Character.CharacterList) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs index 51bab9e1c..dca0ec85d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs @@ -524,6 +524,11 @@ namespace Barotrauma public bool CanBeBought => (DefaultPrice != null && DefaultPrice.CanBeBought) || (locationPrices != null && locationPrices.Any(p => p.Value.CanBeBought)); + /// + /// Can the item be chosen as extra cargo in multiplayer. If not set, the item is available if it can be bought from outposts in the campaign. + /// + public bool? AllowAsExtraCargo; + /// /// Any item with a Price element in the definition can be sold everywhere. /// @@ -719,6 +724,11 @@ namespace Barotrauma FabricationRecipes = new List(); DeconstructTime = 1.0f; + if (element.Attribute("allowasextracargo") != null) + { + AllowAsExtraCargo = element.GetAttributeBool("allowasextracargo", false); + } + Tags = new HashSet(element.GetAttributeStringArray("tags", new string[0], convertToLowerInvariant: true)); if (!Tags.Any()) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Explosion.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Explosion.cs index 4f0fa15ea..b68a548e7 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Explosion.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Explosion.cs @@ -142,7 +142,7 @@ namespace Barotrauma if (displayRange < 0.1f) { return; } - if (Attack.GetStructureDamage(1.0f) > 0.0f) + if (Attack.GetStructureDamage(1.0f) > 0.0f || Attack.GetLevelWallDamage(1.0f) > 0.0f) { RangedStructureDamage(worldPosition, displayRange, Attack.GetStructureDamage(1.0f), Attack.GetLevelWallDamage(1.0f), attacker); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs index 162900bde..5a1bc2896 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs @@ -3603,31 +3603,36 @@ namespace Barotrauma } //remove wires - foreach (Item item in beaconItems.Where(it => it.GetComponent() != null).ToList()) + float removeWireMinDifficulty = 20.0f; + float removeWireProbability = MathUtils.InverseLerp(removeWireMinDifficulty, 100.0f, LevelData.Difficulty) * 0.5f; + if (removeWireProbability > 0.0f) { - if (item.NonInteractable) { continue; } - Wire wire = item.GetComponent(); - if (wire.Locked) { continue; } - if (wire.Connections[0] != null && (wire.Connections[0].Item.NonInteractable || wire.Connections[0].Item.GetComponent().Locked)) + foreach (Item item in beaconItems.Where(it => it.GetComponent() != null).ToList()) { - continue; - } - if (wire.Connections[1] != null && (wire.Connections[1].Item.NonInteractable || wire.Connections[1].Item.GetComponent().Locked)) - { - continue; - } - if (Rand.Range(0f, 1f, Rand.RandSync.Unsynced) < 0.25f) - { - foreach (Connection connection in wire.Connections) + if (item.NonInteractable) { continue; } + Wire wire = item.GetComponent(); + if (wire.Locked) { continue; } + if (wire.Connections[0] != null && (wire.Connections[0].Item.NonInteractable || wire.Connections[0].Item.GetComponent().Locked)) { - if (connection != null) + continue; + } + if (wire.Connections[1] != null && (wire.Connections[1].Item.NonInteractable || wire.Connections[1].Item.GetComponent().Locked)) + { + continue; + } + if (Rand.Range(0f, 1.0f, Rand.RandSync.Unsynced) < removeWireProbability) + { + foreach (Connection connection in wire.Connections) { - connection.ConnectionPanel.DisconnectedWires.Add(wire); - wire.RemoveConnection(connection.Item); + if (connection != null) + { + connection.ConnectionPanel.DisconnectedWires.Add(wire); + wire.RemoveConnection(connection.Item); #if SERVER connection.ConnectionPanel.Item.CreateServerEvent(connection.ConnectionPanel); wire.CreateNetworkEvent(); #endif + } } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelData.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelData.cs index 8123a7409..2cf68b72c 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelData.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelData.cs @@ -117,8 +117,7 @@ namespace Barotrauma EventHistory.AddRange(EventSet.PrefabList.Where(p => prefabNames.Any(n => p.Identifier.Equals(n, StringComparison.InvariantCultureIgnoreCase)))); string[] nonRepeatablePrefabNames = element.GetAttributeStringArray("nonrepeatableevents", new string[] { }); - NonRepeatableEvents.AddRange(EventSet.PrefabList.Where(p => prefabNames.Any(n => p.Identifier.Equals(n, StringComparison.InvariantCultureIgnoreCase)))); - + NonRepeatableEvents.AddRange(EventSet.PrefabList.Where(p => nonRepeatablePrefabNames.Any(n => p.Identifier.Equals(n, StringComparison.InvariantCultureIgnoreCase)))); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/LinkedSubmarine.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/LinkedSubmarine.cs index 9b94eb231..1e5a07512 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/LinkedSubmarine.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/LinkedSubmarine.cs @@ -183,10 +183,10 @@ namespace Barotrauma else { string levelSeed = element.GetAttributeString("location", ""); - LevelData levelData = GameMain.GameSession.Campaign?.NextLevel ?? GameMain.GameSession.LevelData; + LevelData levelData = GameMain.GameSession?.Campaign?.NextLevel ?? GameMain.GameSession?.LevelData; linkedSub = new LinkedSubmarine(submarine, idRemap.AssignMaxId()) { - purchasedLostShuttles = GameMain.GameSession.GameMode is CampaignMode campaign && campaign.PurchasedLostShuttles, + purchasedLostShuttles = GameMain.GameSession?.GameMode is CampaignMode campaign && campaign.PurchasedLostShuttles, saveElement = element }; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Location.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Location.cs index c17029a9e..7b13309c4 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Location.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Location.cs @@ -591,9 +591,9 @@ namespace Barotrauma public bool IsCriticallyRadiated() { - if (GameMain.GameSession is { Campaign: { Map: { } map } }) + if (GameMain.GameSession?.Map?.Radiation != null) { - return TurnsInRadiation > map.Radiation.Params.CriticalRadiationThreshold; + return TurnsInRadiation > GameMain.GameSession.Map.Radiation.Params.CriticalRadiationThreshold; } return false; @@ -708,7 +708,7 @@ namespace Barotrauma } } - public bool IsRadiated() => GameMain.GameSession is { Campaign: { Map: { Radiation: { Enabled: true } radiation } } } && radiation.Contains(this); + public bool IsRadiated() => GameMain.GameSession?.Map?.Radiation != null && GameMain.GameSession.Map.Radiation.Enabled && GameMain.GameSession.Map.Radiation.Contains(this); private List CreateStoreStock() { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Map.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Map.cs index efe2c9318..c6ada18cf 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Map.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Map.cs @@ -16,8 +16,8 @@ namespace Barotrauma private Location furthestDiscoveredLocation; - public int Width => generationParams.Width; - public int Height => generationParams.Height; + public int Width { get; private set; } + public int Height { get; private set; } public Action OnLocationSelected; /// @@ -62,12 +62,17 @@ namespace Barotrauma public Map(CampaignSettings settings) { generationParams = MapGenerationParams.Instance; + Width = generationParams.Width; + Height = generationParams.Height; Locations = new List(); Connections = new List(); - Radiation = new Radiation(this, generationParams.RadiationParams) + if (generationParams.RadiationParams != null) { - Enabled = settings.RadiationEnabled - }; + Radiation = new Radiation(this, generationParams.RadiationParams) + { + Enabled = settings.RadiationEnabled + }; + } } /// @@ -78,6 +83,9 @@ namespace Barotrauma Seed = element.GetAttributeString("seed", "a"); Rand.SetSyncedSeed(ToolBox.StringToInt(Seed)); + Width = element.GetAttributeInt("width", Width); + Height = element.GetAttributeInt("height", Height); + bool lairsFound = false; foreach (XElement subElement in element.Elements()) @@ -180,6 +188,12 @@ namespace Barotrauma } } + //backwards compatibility: if locations go out of bounds (map saved with different generation parameters before width/height were included in the xml) + float maxX = Locations.Select(l => l.MapPosition.X).Max(); + if (maxX > Width) { Width = (int)(maxX + 10); } + float maxY = Locations.Select(l => l.MapPosition.Y).Max(); + if (maxY > Height) { Height = (int)(maxY + 10); } + InitProjectSpecific(); } @@ -405,6 +419,7 @@ namespace Barotrauma int zone1 = GetZoneIndex(Connections[i].Locations[0].MapPosition.X); int zone2 = GetZoneIndex(Connections[i].Locations[1].MapPosition.X); if (zone1 == zone2) { continue; } + if (zone2 == generationParams.DifficultyZones) { continue; } if (!connectionsBetweenZones.Contains(Connections[i])) { @@ -416,9 +431,9 @@ namespace Barotrauma Connections[i].Locations[0].MapPosition.X < Connections[i].Locations[1].MapPosition.X ? Connections[i].Locations[0] : Connections[i].Locations[1]; - if (!leftMostLocation.Type.HasOutpost) + if (!leftMostLocation.Type.HasOutpost || leftMostLocation.Type.Identifier.Equals("abandoned", StringComparison.OrdinalIgnoreCase)) { - leftMostLocation.ChangeType(LocationType.List.First(lt => lt.HasOutpost)); + leftMostLocation.ChangeType(LocationType.List.First(lt => lt.HasOutpost && !lt.Identifier.Equals("abandoned", StringComparison.OrdinalIgnoreCase))); } leftMostLocation.IsGateBetweenBiomes = true; Connections[i].Locked = true; @@ -708,8 +723,9 @@ namespace Barotrauma } SelectedLocation = Locations[index]; + var currentDisplayLocation = GameMain.GameSession?.Campaign?.GetCurrentDisplayLocation(); SelectedConnection = - Connections.Find(c => c.Locations.Contains(GameMain.GameSession?.Campaign?.CurrentDisplayLocation) && c.Locations.Contains(SelectedLocation)) ?? + Connections.Find(c => c.Locations.Contains(currentDisplayLocation) && c.Locations.Contains(SelectedLocation)) ?? Connections.Find(c => c.Locations.Contains(CurrentLocation) && c.Locations.Contains(SelectedLocation)); if (SelectedConnection?.Locked ?? false) { @@ -796,7 +812,7 @@ namespace Barotrauma ProgressWorld(); } - Radiation.OnStep(steps); + Radiation?.OnStep(steps); } private void ProgressWorld() @@ -1092,6 +1108,8 @@ namespace Barotrauma mapElement.Add(new XAttribute("currentlocationconnection", Connections.IndexOf(Connections.Find(c => c.LevelData == Level.Loaded.LevelData)))); } } + mapElement.Add(new XAttribute("width", Width)); + mapElement.Add(new XAttribute("height", Height)); mapElement.Add(new XAttribute("selectedlocation", SelectedLocationIndex)); mapElement.Add(new XAttribute("startlocation", Locations.IndexOf(StartLocation))); mapElement.Add(new XAttribute("endlocation", Locations.IndexOf(EndLocation))); @@ -1118,7 +1136,10 @@ namespace Barotrauma mapElement.Add(connectionElement); } - mapElement.Add(Radiation.Save()); + if (Radiation != null) + { + mapElement.Add(Radiation.Save()); + } element.Add(mapElement); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Submarine.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Submarine.cs index 93077aefb..0305c2315 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Submarine.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Submarine.cs @@ -133,7 +133,7 @@ namespace Barotrauma public Rectangle Borders { - get + get { return subBody == null ? Rectangle.Empty : subBody.Borders; } @@ -155,7 +155,7 @@ namespace Barotrauma private float? realWorldCrushDepth; public float RealWorldCrushDepth { - get + get { if (!realWorldCrushDepth.HasValue) { @@ -172,6 +172,7 @@ namespace Barotrauma } return realWorldCrushDepth.Value; } + set { realWorldCrushDepth = value; } } /// @@ -179,7 +180,7 @@ namespace Barotrauma /// public float RealWorldDepth { - get + get { if (Level.Loaded?.GenerationParams == null) { @@ -191,7 +192,7 @@ namespace Barotrauma public bool AtEndExit { - get + get { if (Level.Loaded == null) { return false; } if (Level.Loaded.EndOutpost != null && DockedTo.Contains(Level.Loaded.EndOutpost)) @@ -247,7 +248,7 @@ namespace Barotrauma public bool AtDamageDepth { - get + get { if (Level.Loaded == null || subBody == null) { return false; } return RealWorldDepth > Level.Loaded.RealWorldCrushDepth && RealWorldDepth > RealWorldCrushDepth; @@ -330,7 +331,7 @@ namespace Barotrauma foreach (Item item in Item.ItemList) { if (item.Submarine != this) { continue; } - if (item.prefab.Identifier == "idcardwreck" || item.prefab.Identifier == "idcard") + if (item.prefab.Identifier == "idcardwreck" || item.prefab.Identifier == "idcard") { foreach (string tag in item.GetTags().ToList()) { @@ -338,7 +339,7 @@ namespace Barotrauma string newTag = Level.Loaded.GetWreckIDTag(tag, this); item.ReplaceTag(tag, newTag); ReplaceIDCardTagRequirements(tag, newTag); - } + } } } @@ -452,7 +453,7 @@ namespace Barotrauma public Vector2 FindSpawnPos(Vector2 spawnPos, Point? submarineSize = null, float subDockingPortOffset = 0.0f, int verticalMoveDir = 0) { Rectangle dockedBorders = GetDockedBorders(); - Vector2 diffFromDockedBorders = + Vector2 diffFromDockedBorders = new Vector2(dockedBorders.Center.X, dockedBorders.Y - dockedBorders.Height / 2) - new Vector2(Borders.Center.X, Borders.Y - Borders.Height / 2); @@ -503,7 +504,7 @@ namespace Barotrauma (e.Point1.Y > refPos.Y + minHeight * 0.5f && e.Point2.Y > refPos.Y + minHeight * 0.5f)) { continue; - } + } if (cell.Site.Coord.X < refPos.X) { @@ -550,7 +551,7 @@ namespace Barotrauma //walls found at both sides, use their midpoint spawnPos.X = (limits.X + limits.Y) / 2 + subDockingPortOffset; } - + spawnPos.Y = MathHelper.Clamp(spawnPos.Y, dockedBorders.Height / 2 + 10, Level.Loaded.Size.Y - dockedBorders.Height / 2 - padding * 2); return spawnPos - diffFromDockedBorders; } @@ -617,7 +618,7 @@ namespace Barotrauma return new Rectangle((int)minX, (int)minY, (int)(maxX - minX), (int)(maxY - minY)); } - + public static Rectangle AbsRect(Vector2 pos, Vector2 size) { if (size.X < 0.0f) @@ -630,7 +631,7 @@ namespace Barotrauma pos.Y -= size.Y; size.Y = -size.Y; } - + return new Rectangle((int)pos.X, (int)pos.Y, (int)size.X, (int)size.Y); } @@ -684,7 +685,7 @@ namespace Barotrauma closestFraction = 0.0f; closestNormal = Vector2.Normalize(rayEnd - rayStart); - if (fixture.Body != null) closestBody = fixture.Body; + if (fixture.Body != null) closestBody = fixture.Body; return false; }, ref aabb); if (closestFraction <= 0.0f) @@ -695,7 +696,7 @@ namespace Barotrauma return closestBody; } } - + GameMain.World.RayCast((fixture, point, normal, fraction) => { if (!CheckFixtureCollision(fixture, ignoredBodies, collisionCategory, ignoreSensors, customPredicate)) { return -1; } @@ -712,7 +713,7 @@ namespace Barotrauma lastPickedPosition = rayStart + (rayEnd - rayStart) * closestFraction; lastPickedFraction = closestFraction; lastPickedNormal = closestNormal; - + return closestBody; } @@ -837,13 +838,13 @@ namespace Barotrauma lastPickedPosition = rayEnd; return null; } - + GameMain.World.RayCast((fixture, point, normal, fraction) => { if (fixture == null) { return -1; } if (ignoreSensors && fixture.IsSensor) { return -1; } if (ignoreLevel && fixture.CollisionCategories.HasFlag(Physics.CollisionLevel)) { return -1; } - if (!fixture.CollisionCategories.HasFlag(Physics.CollisionLevel) + if (!fixture.CollisionCategories.HasFlag(Physics.CollisionLevel) && !fixture.CollisionCategories.HasFlag(Physics.CollisionWall) && !fixture.CollisionCategories.HasFlag(Physics.CollisionRepair)) { return -1; } if (ignoreSubs && fixture.Body.UserData is Submarine) { return -1; } @@ -890,7 +891,7 @@ namespace Barotrauma parents.Add(this); flippedX = !flippedX; - + Item.UpdateHulls(); List bodyItems = Item.ItemList.FindAll(it => it.Submarine == this && it.body != null); @@ -1174,7 +1175,7 @@ namespace Barotrauma subBody.SetPosition(subBody.Position + amount); } - public static Submarine FindClosest(Vector2 worldPosition, bool ignoreOutposts = false, bool ignoreOutsideLevel = true) + public static Submarine FindClosest(Vector2 worldPosition, bool ignoreOutposts = false, bool ignoreOutsideLevel = true, bool ignoreRespawnShuttle = false) { Submarine closest = null; float closestDist = 0.0f; @@ -1182,6 +1183,10 @@ namespace Barotrauma { if (ignoreOutposts && sub.Info.IsOutpost) { continue; } if (ignoreOutsideLevel && Level.Loaded != null && sub.WorldPosition.Y > Level.Loaded.Size.Y) { continue; } + if (ignoreRespawnShuttle) + { + if (sub == GameMain.NetworkMember?.RespawnManager?.RespawnShuttle) { continue; } + } float dist = Vector2.DistanceSquared(worldPosition, sub.WorldPosition); if (closest == null || dist < closestDist) { @@ -1344,9 +1349,9 @@ namespace Barotrauma PhysicsBody.FarseerBody.BodyType = BodyType.Static; TeamID = CharacterTeamType.FriendlyNPC; - bool indestructible = - GameMain.NetworkMember != null && - !GameMain.NetworkMember.ServerSettings.DestructibleOutposts && + bool indestructible = + GameMain.NetworkMember != null && + !GameMain.NetworkMember.ServerSettings.DestructibleOutposts && !(info.OutpostGenerationParams?.AlwaysDestructible ?? false); foreach (MapEntity me in MapEntity.mapEntityList) @@ -1432,7 +1437,7 @@ namespace Barotrauma //halve the brightness of the lights to make them look (almost) right on the new lighting formula if (showWarningMessages && !string.IsNullOrEmpty(Info.FilePath) && - Screen.Selected != GameMain.SubEditorScreen && + Screen.Selected != GameMain.SubEditorScreen && (Info.GameVersion == null || Info.GameVersion < new Version("0.8.9.0"))) { DebugConsole.ThrowError("The submarine \"" + Info.Name + "\" was made using an older version of the Barotrauma that used a different formula to calculate the lighting. " @@ -1445,6 +1450,7 @@ namespace Barotrauma if (lightComponent != null) lightComponent.LightColor = new Color(lightComponent.LightColor, lightComponent.LightColor.A / 255.0f * 0.5f); } } + GenerateOutdoorNodes(); } protected override ushort DetermineID(ushort id, Submarine submarine) @@ -1500,7 +1506,7 @@ namespace Barotrauma element.Add(new XAttribute("recommendedcrewsizemax", Info.RecommendedCrewSizeMax)); element.Add(new XAttribute("recommendedcrewexperience", Info.RecommendedCrewExperience ?? "")); element.Add(new XAttribute("requiredcontentpackages", string.Join(", ", Info.RequiredContentPackages))); - + if (Info.Type == SubmarineType.OutpostModule) { Info.OutpostModuleInfo?.Save(element); @@ -1606,7 +1612,7 @@ namespace Barotrauma PhysicsBody.RemoveAll(); - GameMain.World.Clear(); + GameMain.World.Clear(); Unloading = false; } @@ -1651,12 +1657,18 @@ namespace Barotrauma { if (outdoorNodes == null) { - outdoorNodes = PathNode.GenerateNodes(WayPoint.WayPointList.FindAll(wp => wp.SpawnType == SpawnType.Path && wp.Submarine == this && wp.CurrentHull == null)); + GenerateOutdoorNodes(); } return outdoorNodes; } } + private void GenerateOutdoorNodes() + { + var waypoints = WayPoint.WayPointList.FindAll(wp => wp.SpawnType == SpawnType.Path && wp.Submarine == this && wp.CurrentHull == null); + outdoorNodes = PathNode.GenerateNodes(waypoints, removeOrphans: false); + } + private readonly Dictionary> obstructedNodes = new Dictionary>(); /// @@ -1724,7 +1736,6 @@ namespace Barotrauma } } } - node.Waypoint.FindHull(); } } @@ -1739,7 +1750,8 @@ namespace Barotrauma nodes.Clear(); obstructedNodes.Remove(otherSub); } - OutdoorNodes.ForEach(n => n.Waypoint.FindHull()); } + + public void RefreshOutdoorNodes() => OutdoorNodes.ForEach(n => n?.Waypoint?.FindHull()); } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineBody.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineBody.cs index cb4cb0e85..4db2d7f8e 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineBody.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineBody.cs @@ -453,7 +453,7 @@ namespace Barotrauma //camera shake and sounds start playing 500 meters before crush depth float depthEffectThreshold = 500.0f; - if (Submarine.RealWorldDepth < Level.Loaded.RealWorldCrushDepth - depthEffectThreshold && Submarine.RealWorldDepth < Submarine.RealWorldCrushDepth - depthEffectThreshold) + if (Submarine.RealWorldDepth < Level.Loaded.RealWorldCrushDepth - depthEffectThreshold || Submarine.RealWorldDepth < Submarine.RealWorldCrushDepth - depthEffectThreshold) { return; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineInfo.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineInfo.cs index 77d858015..0d3b84d90 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineInfo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineInfo.cs @@ -275,7 +275,7 @@ namespace Barotrauma OutpostModuleInfo = new OutpostModuleInfo(original.OutpostModuleInfo); } #if CLIENT - PreviewImage = original.PreviewImage != null ? new Sprite(original.PreviewImage.Texture, null, null) : null; + PreviewImage = original.PreviewImage != null ? new Sprite(original.PreviewImage) : null; #endif } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/WayPoint.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/WayPoint.cs index 1f6f0a56e..9fc32beb5 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/WayPoint.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/WayPoint.cs @@ -144,7 +144,7 @@ namespace Barotrauma DebugConsole.Log("Created waypoint (" + ID + ")"); - CurrentHull = Hull.FindHull(WorldPosition); + FindHull(); } public override MapEntity Clone() @@ -791,7 +791,7 @@ namespace Barotrauma public override void OnMapLoaded() { InitializeLinks(); - CurrentHull = Hull.FindHull(WorldPosition, CurrentHull); + FindHull(); FindStairs(); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Networking/ChatMessage.cs b/Barotrauma/BarotraumaShared/SharedSource/Networking/ChatMessage.cs index d4c48430a..1226deb40 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Networking/ChatMessage.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Networking/ChatMessage.cs @@ -82,7 +82,7 @@ namespace Barotrauma.Networking { get { - return string.IsNullOrWhiteSpace(SenderName) ? TranslatedText : SenderName + ": " + TranslatedText; + return string.IsNullOrWhiteSpace(SenderName) ? TranslatedText : NetworkMember.ClientLogName(SenderClient, SenderName) + ": " + TranslatedText; } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Networking/NetworkMember.cs b/Barotrauma/BarotraumaShared/SharedSource/Networking/NetworkMember.cs index 327c43e7f..69ff7477f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Networking/NetworkMember.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Networking/NetworkMember.cs @@ -237,9 +237,9 @@ namespace Barotrauma.Networking return radioComponent.HasRequiredContainedItems(sender, addMessage: false); } - public void AddChatMessage(string message, ChatMessageType type, string senderName = "", Character senderCharacter = null, PlayerConnectionChangeType changeType = PlayerConnectionChangeType.None) + public void AddChatMessage(string message, ChatMessageType type, string senderName = "", Client senderClient = null, Character senderCharacter = null, PlayerConnectionChangeType changeType = PlayerConnectionChangeType.None) { - AddChatMessage(ChatMessage.Create(senderName, message, type, senderCharacter, changeType: changeType)); + AddChatMessage(ChatMessage.Create(senderName, message, type, senderCharacter, senderClient, changeType: changeType)); } public virtual void AddChatMessage(ChatMessage message) @@ -252,6 +252,18 @@ namespace Barotrauma.Networking } } + public static string ClientLogName(Client client, string name = null) + { + if (client == null) { return name; } + string retVal = "‖"; + if (client.Karma < 40.0f) + { + retVal += "color:#ff9900;"; + } + retVal += "metadata:" + (client.SteamID != 0 ? client.SteamID.ToString() : client.ID.ToString()) + "‖" + (name ?? client.Name).Replace("‖", "") + "‖end‖"; + return retVal; + } + public virtual void KickPlayer(string kickedName, string reason) { } public virtual void BanPlayer(string kickedName, string reason, bool range = false, TimeSpan? duration = null) { } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Networking/RespawnManager.cs b/Barotrauma/BarotraumaShared/SharedSource/Networking/RespawnManager.cs index c3a1ab7a1..9d2c63518 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Networking/RespawnManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Networking/RespawnManager.cs @@ -70,6 +70,8 @@ namespace Barotrauma.Networking { RespawnShuttle = new Submarine(shuttleInfo, true); RespawnShuttle.PhysicsBody.FarseerBody.OnCollision += OnShuttleCollision; + //set crush depth slightly deeper than the main sub's + RespawnShuttle.RealWorldCrushDepth = Math.Max(RespawnShuttle.RealWorldCrushDepth, Submarine.MainSub.RealWorldCrushDepth * 1.2f); //prevent wifi components from communicating between the respawn shuttle and other subs List wifiComponents = new List(); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Screens/GameScreen.cs b/Barotrauma/BarotraumaShared/SharedSource/Screens/GameScreen.cs index f4f431033..ea6aa2f24 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Screens/GameScreen.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Screens/GameScreen.cs @@ -244,7 +244,7 @@ namespace Barotrauma cam.TargetPos = targetPos; } - cam.MoveCamera((float)deltaTime); + cam.MoveCamera((float)deltaTime, allowZoom: GUI.MouseOn == null); #endif foreach (Submarine sub in Submarine.Loaded) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaShared/SharedSource/Screens/NetLobbyScreen.cs index 8f10e2d5b..e7c3e5da5 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Screens/NetLobbyScreen.cs @@ -40,6 +40,7 @@ namespace Barotrauma public void SetRadiationEnabled(bool enabled) { #if CLIENT + if (radiationEnabledTickBox == null) { return; } radiationEnabledTickBox.Selected = enabled; #endif } @@ -47,7 +48,7 @@ namespace Barotrauma public bool IsRadiationEnabled() { #if CLIENT - return radiationEnabledTickBox.Selected; + return radiationEnabledTickBox != null && radiationEnabledTickBox.Selected; #elif SERVER return GameMain.Server.ServerSettings.RadiationEnabled; #endif diff --git a/Barotrauma/BarotraumaShared/SharedSource/Screens/Screen.cs b/Barotrauma/BarotraumaShared/SharedSource/Screens/Screen.cs index bac118d97..c316d87da 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Screens/Screen.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Screens/Screen.cs @@ -32,6 +32,7 @@ GUI.KeyboardDispatcher.Subscriber = null; GUI.ScreenChanged = true; } + SubmarinePreview.Close(); #endif } selected = this; diff --git a/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs b/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs index 174be3390..931bf9748 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs @@ -281,6 +281,8 @@ namespace Barotrauma public readonly bool OnlyInside; public readonly bool OnlyOutside; + // Currently only used for OnDamaged. TODO: is there a better, more generic way to do this? + public readonly bool OnlyPlayerTriggered; public HashSet TargetIdentifiers { @@ -351,6 +353,7 @@ namespace Barotrauma tags = new HashSet(element.GetAttributeString("tags", "").Split(',')); OnlyInside = element.GetAttributeBool("onlyinside", false); OnlyOutside = element.GetAttributeBool("onlyoutside", false); + OnlyPlayerTriggered = element.GetAttributeBool("onlyplayertriggered", false); Range = element.GetAttributeFloat("range", 0.0f); Offset = element.GetAttributeVector2("offset", Vector2.Zero); @@ -1088,7 +1091,7 @@ namespace Barotrauma foreach (Pair reduceAffliction in ReduceAffliction) { - float reduceAmount = disableDeltaTime ? reduceAffliction.Second : reduceAffliction.Second * deltaTime; + float reduceAmount = disableDeltaTime || setValue ? reduceAffliction.Second : reduceAffliction.Second * deltaTime; Limb targetLimb = null; Character targetCharacter = null; if (target is Character character) diff --git a/Barotrauma/BarotraumaShared/Submarines/Humpback.sub b/Barotrauma/BarotraumaShared/Submarines/Humpback.sub index 65e1861f5..c1640d13f 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 dac49f4f7..5e14feb89 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 6a61c4af4..a59bad499 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Orca.sub and b/Barotrauma/BarotraumaShared/Submarines/Orca.sub differ diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index 7b67a9531..64e6ac372 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,3 +1,53 @@ +--------------------------------------------------------------------------------------------------------- +v0.1300.0.4 (unstable) +--------------------------------------------------------------------------------------------------------- + +Changes: +- Adjustments on Moloch. Improve the feedback. +- Certain large monsters' (endworm, charybdis, boss variants of molochs and hammerheads) health bars become visible at the top of the screen when you damage them. +- Readjusted abyss and combat diving suits. They are now essentially better versions of the normal diving suit (as opposed to just alternatives with their own pros and cons), making normal suits obsolete later in the campaign. Both suits now have a high resistance to pressure, although an abyss suit may still be required at the very end of the campaign. +- Replaced legacy small pumps with the new ones in Orca. +- Adjusted stun gun's effect. It basically works like incremental stun, but inversed: the strength increases rapidly to the max, after which we remove progressive stun and add full incremental stun that will wear off with time. +- Restrict the length of the text that can be entered as a sonar beacon's sonar label. +- The probability of disconnected wires in beacon stations is relative to the level's difficulty, and no wires are removed if the difficulty is less than 20. +- Added a hint for encountering ballast flora. +- Added submarine preview to campaign outpost submarine selection. +- Allow fabricating fresh fuel rods, welding fuel and coilgun ammunition using depleted ones. +- Abyss monsters only emit distant sonar "waves" while chasing the player, not always. + +Fixes: +- Fixed players being able to take the respawn shuttle with them from the levels in the multiplayer campaign, which would lead to "entity not found" errors during the next round. +- Fixed respawn shuttle always having the default crush depth of 3500 meters, making it unusable at later stages of the campaign. +- Fixed creaking hull sounds triggering when 500 meters above a non-upgraded sub's crush depth, even if the current sub can withstand more. +- Fixed Kastrull's drone airlock not flooding correctly. +- Don't restrict signal components' output length when the sub is being loaded. Fixes all outputs being restricted to 200 characters in subs from previous versions and output getting cut off when saving and loading the sub. +- Fixed crashing if you try to press the server log button in the lobby when connection to the server has been lost. +- Fixed item disappearing from the character's hand when you combine it with an item in a container in a way that doesn't fully deplete/remove it. +- Fixed gaps in the "backwall pipes" sprite. +- Fixed dedicated servers restricting player count to 1 less than the MaxPlayer setting. +- Fixed crashing when you try to preview a sub you don't have in the server lobby. +- Fixed "gate outpost" sometimes generating as abandoned outposts. +- Fixed clients being unable to vote for subs they don't have. +- Fixed a bunch of non-suitable items (such as devices that can't be deattached) being displayed in the "extra cargo" menu in the server lobby. +- Fixed Operate Weapons icon not updating when assigned again while targeting a weapon of different type. +- Fixed being able to assign the same order to a character multiple times with different options. +- Fixed highlighted client names in chat messages not opening the player info dialog when clicked. + +Bots: +- Fixed bots not knowing how to swap out welding fuel from diving gear and oxygen tanks from welding tools (#4380). +- Fixed bots sometimes yelling that they can't enter an airlock when the sub is docked. + +Modding: +- Fixed level editor crashing when it tries to place a wreck that contains linked subs in the level. +- Added "onlyplayertriggered" condition for status effects. Currently only implemented for OnDamaged. +- Monster events don't spawn monsters in wrecks that don't contain enemy spawnpoints. +- Fixed crashing if you try to create a decal with incorrect casing. +- Fixed affliction's periodic effects being unable to reference afflictions defined later in the affliction xml. +- Fixed crashes if radiation parameters aren't defined in the map generation xml. +- Fixed crashing if you save a campaign with a large map and try to load it with map generation parameters where the map is smaller. +- Fixed explosions not damaging level walls if their structure damage is set to 0. +- Fixed reduce affliction status effects using delta time even when "setvalue" is true. + --------------------------------------------------------------------------------------------------------- v0.1300.0.3 (unstable) --------------------------------------------------------------------------------------------------------- diff --git a/Barotrauma/BarotraumaShared/hintmanager.xml b/Barotrauma/BarotraumaShared/hintmanager.xml index 422212c3e..ed6c346cc 100644 --- a/Barotrauma/BarotraumaShared/hintmanager.xml +++ b/Barotrauma/BarotraumaShared/hintmanager.xml @@ -12,6 +12,7 @@ + diff --git a/test.xml b/test.xml deleted file mode 100644 index 744d86d15..000000000 --- a/test.xml +++ /dev/null @@ -1 +0,0 @@ -0.1300.0.2