diff --git a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs index 9e091e34c..2b59d689b 100644 --- a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs +++ b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.8.9.2")] -[assembly: AssemblyFileVersion("0.8.9.2")] +[assembly: AssemblyVersion("0.8.9.3")] +[assembly: AssemblyFileVersion("0.8.9.3")] diff --git a/Barotrauma/BarotraumaClient/Source/Characters/AI/AITarget.cs b/Barotrauma/BarotraumaClient/Source/Characters/AI/AITarget.cs index 3e2f5e46b..6a7d9ec27 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/AI/AITarget.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/AI/AITarget.cs @@ -10,31 +10,16 @@ namespace Barotrauma public void Draw(SpriteBatch spriteBatch) { if (!ShowAITargets) return; - - var rangeSprite = GUI.SubmarineIcon; - + var pos = new Vector2(WorldPosition.X, -WorldPosition.Y); if (soundRange > 0.0f) { - rangeSprite.Draw(spriteBatch, - new Vector2(WorldPosition.X, -WorldPosition.Y), - Color.Cyan * 0.1f, rangeSprite.Origin, - 0.0f, soundRange / rangeSprite.size.X); - rangeSprite.Draw(spriteBatch, - new Vector2(WorldPosition.X, -WorldPosition.Y), - Color.Cyan, rangeSprite.Origin, - 0.0f, 1.0f); + Color color = Entity is Character ? Color.Yellow : Color.Orange; + ShapeExtensions.DrawCircle(spriteBatch, pos, SoundRange, 100, color, thickness: 1 / Screen.Selected.Cam.Zoom); } - if (sightRange > 0.0f) { - rangeSprite.Draw(spriteBatch, - new Vector2(WorldPosition.X, -WorldPosition.Y), - Color.Orange * 0.1f, rangeSprite.Origin, - 0.0f, sightRange / rangeSprite.size.X); - rangeSprite.Draw(spriteBatch, - new Vector2(WorldPosition.X, -WorldPosition.Y), - Color.Orange, rangeSprite.Origin, - 0.0f, 1.0f); + Color color = Entity is Character ? Color.CornflowerBlue : Color.CadetBlue; + ShapeExtensions.DrawCircle(spriteBatch, pos, SightRange, 100, color, thickness: 1 / Screen.Selected.Cam.Zoom); } } } diff --git a/Barotrauma/BarotraumaClient/Source/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaClient/Source/Characters/AI/EnemyAIController.cs index 7fad3d0a8..2f25f0131 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/AI/EnemyAIController.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/AI/EnemyAIController.cs @@ -27,7 +27,7 @@ namespace Barotrauma GUI.DrawLine(spriteBatch, pos, wallTargetPos, Color.Orange * 0.5f, 0, 5); } - GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 20.0f, Color.Red); + GUI.Font.DrawString(spriteBatch, $"{selectedAiTarget.Entity.ToString()} ({targetValue.ToString()})", pos - Vector2.UnitY * 20.0f, Color.Red); } /*GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 80.0f, Color.Red); diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterHealth.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterHealth.cs index 2b07cfe39..4a7da5645 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterHealth.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterHealth.cs @@ -54,7 +54,7 @@ namespace Barotrauma private GUIListBox recommendedTreatmentContainer; private float bloodParticleTimer; - + private GUIFrame healthWindow; private GUIComponent deadIndicator; @@ -73,7 +73,7 @@ namespace Barotrauma private GUIComponent draggingMed; private int highlightedLimbIndex = -1; - private int selectedLimbIndex = 0; + private int selectedLimbIndex = -1; private float distortTimer; @@ -96,7 +96,7 @@ namespace Barotrauma if (value != null && !value.UseHealthWindow) return; if (value == null && - Character.Controlled?.SelectedCharacter?.CharacterHealth == openHealthWindow && + Character.Controlled?.SelectedCharacter?.CharacterHealth == openHealthWindow && !Character.Controlled.SelectedCharacter.CanInventoryBeAccessed) { Character.Controlled.DeselectCharacter(); @@ -114,7 +114,7 @@ namespace Barotrauma } static CharacterHealth() - { + { damageOverlay = new Sprite("Content/UI/damageOverlay.png", Vector2.Zero); } @@ -144,14 +144,14 @@ namespace Barotrauma IsHorizontal = horizontal }; healthShadowSize = 1.0f; - + afflictionInfoFrame = new GUIFrame(new RectTransform(new Point(HUDLayoutSettings.HealthWindowAreaLeft.Width / 2, 200), GUI.Canvas)); var paddedInfoFrame = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.9f), afflictionInfoFrame.RectTransform, Anchor.Center), style: null); new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.08f), paddedInfoFrame.RectTransform), "", font: GUI.LargeFont) { UserData = "selectedlimbname" }; - + afflictionInfoContainer = new GUIListBox(new RectTransform(new Vector2(0.7f, 0.85f), paddedInfoFrame.RectTransform, Anchor.BottomLeft)); new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.08f), paddedInfoFrame.RectTransform), TextManager.Get("SuitableTreatments"), textAlignment: Alignment.TopRight); @@ -191,7 +191,7 @@ namespace Barotrauma { CanBeFocused = false }; - + healthWindow = new GUIFrame(new RectTransform(new Point(100, 200), GUI.Canvas)); var paddedHealthWindow = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), healthWindow.RectTransform, Anchor.Center)) { @@ -303,7 +303,7 @@ namespace Barotrauma } } } - + private void OnAttacked(Character attacker, AttackResult attackResult) { if (Math.Abs(attackResult.Damage) < 0.01f && attackResult.Afflictions.Count == 0) return; @@ -328,13 +328,13 @@ namespace Barotrauma { healthBar.RectTransform.SetPosition(Anchor.BottomLeft); healthBarShadow.RectTransform.SetPosition(Anchor.BottomLeft); - healthBar.RectTransform.AbsoluteOffset = healthBarShadow.RectTransform.AbsoluteOffset = + healthBar.RectTransform.AbsoluteOffset = healthBarShadow.RectTransform.AbsoluteOffset = new Point(HUDLayoutSettings.HealthBarAreaLeft.X, GameMain.GraphicsHeight - HUDLayoutSettings.HealthBarAreaLeft.Bottom); healthBar.RectTransform.NonScaledSize = healthBarShadow.RectTransform.NonScaledSize = HUDLayoutSettings.HealthBarAreaLeft.Size; healthWindow.RectTransform.AbsoluteOffset = HUDLayoutSettings.HealthWindowAreaLeft.Location + new Point(healthWindowHealthBarWidth, 0); healthWindow.RectTransform.NonScaledSize = new Point( - HUDLayoutSettings.HealthWindowAreaLeft.Width / 3 - healthWindowHealthBarWidth, + HUDLayoutSettings.HealthWindowAreaLeft.Width / 3 - healthWindowHealthBarWidth, HUDLayoutSettings.HealthWindowAreaLeft.Height); afflictionInfoFrame.RectTransform.AbsoluteOffset = new Point( @@ -346,7 +346,7 @@ namespace Barotrauma healthWindowHealthBar.RectTransform.NonScaledSize = healthWindowHealthBarShadow.RectTransform.NonScaledSize = new Point(healthWindowHealthBarWidth, healthWindow.Rect.Height); - healthWindowHealthBar.RectTransform.AbsoluteOffset = healthWindowHealthBarShadow.RectTransform.AbsoluteOffset = + healthWindowHealthBar.RectTransform.AbsoluteOffset = healthWindowHealthBarShadow.RectTransform.AbsoluteOffset = HUDLayoutSettings.HealthWindowAreaLeft.Location; int cprButtonSize = (int)(100 * GUI.Scale); @@ -365,7 +365,7 @@ namespace Barotrauma HUDLayoutSettings.HealthWindowAreaRight.X + HUDLayoutSettings.HealthWindowAreaRight.Width / 3 * 2, HUDLayoutSettings.HealthWindowAreaRight.Y); healthWindow.RectTransform.NonScaledSize = new Point( - HUDLayoutSettings.HealthWindowAreaRight.Width / 3 - healthWindowHealthBarWidth, + HUDLayoutSettings.HealthWindowAreaRight.Width / 3 - healthWindowHealthBarWidth, HUDLayoutSettings.HealthWindowAreaRight.Height); afflictionInfoFrame.RectTransform.AbsoluteOffset = new Point( @@ -384,7 +384,7 @@ namespace Barotrauma cprButton.RectTransform.AbsoluteOffset = new Point(HUDLayoutSettings.HealthWindowAreaRight.X - cprButtonSize, dropItemArea.Rect.Center.Y - cprButtonSize / 2); cprButton.RectTransform.NonScaledSize = new Point(cprButtonSize); } - + dropItemArea.RectTransform.NonScaledSize = new Point(dropItemArea.Rect.Width); screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight); @@ -456,13 +456,13 @@ namespace Barotrauma } dropItemArea.Visible = !Character.IsDead; - + float blurStrength = 0.0f; float distortStrength = 0.0f; float distortSpeed = 0.0f; float radialDistortStrength = 0.0f; float chromaticAberrationStrength = 0.0f; - + if (Character.IsUnconscious) { blurStrength = 1.0f; @@ -509,7 +509,7 @@ namespace Barotrauma distortTimer = 0.0f; } - if (PlayerInput.KeyHit(InputType.Health) && GUI.KeyboardDispatcher.Subscriber == null && + if (PlayerInput.KeyHit(InputType.Health) && GUI.KeyboardDispatcher.Subscriber == null && Character.AllowInput && Character.FocusedCharacter == null && !toggledThisFrame) { if (openHealthWindow != null) @@ -529,8 +529,8 @@ namespace Barotrauma } } toggledThisFrame = false; - - + + if (Character.IsDead) { healthBar.Color = healthWindowHealthBar.Color = Color.Black; @@ -538,7 +538,7 @@ namespace Barotrauma } else { - healthBar.Color = healthWindowHealthBar.Color = ToolBox.GradientLerp(Vitality / MaxVitality, Color.Red, Color.Orange, Color.Green ); + healthBar.Color = healthWindowHealthBar.Color = ToolBox.GradientLerp(Vitality / MaxVitality, Color.Red, Color.Orange, Color.Green); healthBar.HoverColor = healthWindowHealthBar.HoverColor = healthBar.Color * 2.0f; healthBar.BarSize = healthWindowHealthBar.BarSize = (Vitality > 0.0f) ? Vitality / MaxVitality : 1.0f - Vitality / MinVitality; @@ -556,7 +556,7 @@ namespace Barotrauma healthBar.RectTransform.LocalScale = Vector2.One; } } - + if (OpenHealthWindow == this) { if (Character == Character.Controlled && !Character.AllowInput) @@ -600,8 +600,21 @@ namespace Barotrauma } Rectangle limbArea = healthWindow.Children.First().Rect; - UpdateAfflictionContainer( - selectedLimbIndex < 0 ? (highlightedLimbIndex < 0 ? null : limbHealths[highlightedLimbIndex]) : limbHealths[selectedLimbIndex]); + + var highlightedLimb = highlightedLimbIndex < 0 ? null : limbHealths[highlightedLimbIndex]; + if (highlightedLimb == null && selectedLimbIndex < 0) + { + // If no limb is selected or highlighted, select the one with the most critical afflictions. + var affliction = GetAllAfflictions(a => a.Prefab.IndicatorLimb != LimbType.None) + .OrderByDescending(a => a.DamagePerSecond) + .ThenByDescending(a => a.Strength).FirstOrDefault(); + var limbHealth = GetMathingLimbHealth(affliction); + if (limbHealth != null) + { + selectedLimbIndex = limbHealths.IndexOf(limbHealth); + } + } + UpdateAfflictionContainer(selectedLimbIndex < 0 ? highlightedLimb : limbHealths[selectedLimbIndex]); if (Inventory.draggingItem != null) { @@ -691,7 +704,7 @@ namespace Barotrauma public void DrawHUD(SpriteBatch spriteBatch) { if (GUI.DisableHUD) return; - if (GameMain.GraphicsWidth != screenResolution.X || + if (GameMain.GraphicsWidth != screenResolution.X || GameMain.GraphicsHeight != screenResolution.Y || Math.Abs(inventoryScale - Inventory.UIScale) > 0.01f || Math.Abs(uiScale - GUI.Scale) > 0.01f) @@ -755,12 +768,12 @@ namespace Barotrauma Pair highlightedIcon = null; Vector2 highlightedIconPos = Vector2.Zero; - Rectangle afflictionArea = alignment == Alignment.Left ? HUDLayoutSettings.AfflictionAreaLeft : HUDLayoutSettings.AfflictionAreaRight; + Rectangle afflictionArea = alignment == Alignment.Left ? HUDLayoutSettings.AfflictionAreaLeft : HUDLayoutSettings.AfflictionAreaRight; Point pos = afflictionArea.Location + healthBar.RectTransform.ScreenSpaceOffset; bool horizontal = afflictionArea.Width > afflictionArea.Height; int iconSize = horizontal ? afflictionArea.Height : afflictionArea.Width; - + foreach (Pair statusIcon in statusIcons) { Rectangle afflictionIconRect = new Rectangle(pos, new Point(iconSize)); @@ -805,7 +818,7 @@ namespace Barotrauma highlightedIcon.Second, Color.White * 0.8f, Color.Black * 0.5f); } - + if (Vitality > 0.0f) { float currHealth = healthBar.BarSize; @@ -849,12 +862,7 @@ namespace Barotrauma afflictionInfoContainer.Content.ClearChildren(); return; } - - var currentAfflictions = selectedLimb.Afflictions.Where(a => a.Strength >= a.Prefab.ShowIconThreshold).ToList(); - currentAfflictions.AddRange(afflictions.Where(a => a.Strength >= - a.Prefab.ShowIconThreshold && - limbHealths[Character.AnimController.GetLimb(a.Prefab.IndicatorLimb).HealthIndex] == selectedLimb)); - + var currentAfflictions = GetMatchingAfflictions(selectedLimb, a => a.Strength >= a.Prefab.ShowIconThreshold); var displayedAfflictions = afflictionInfoContainer.Content.Children.Select(c => c.UserData as Affliction); if (currentAfflictions.Any(a => !displayedAfflictions.Contains(a)) || displayedAfflictions.Any(a => !currentAfflictions.Contains(a))) @@ -984,10 +992,18 @@ namespace Barotrauma itemSlot.ToolTip = item.Name + "\n" + item.Description; } - afflictionInfoContainer.Content.RectTransform.SortChildren((r1,r2) => + afflictionInfoContainer.Content.RectTransform.SortChildren((r1, r2) => { - return Math.Sign(((Affliction)r2.GUIComponent.UserData).GetVitalityDecrease(this) - ((Affliction)r1.GUIComponent.UserData).GetVitalityDecrease(this)); + var first = r1.GUIComponent.UserData as Affliction; + var second = r2.GUIComponent.UserData as Affliction; + int dmgPerSecond = Math.Sign(second.DamagePerSecond - first.DamagePerSecond); + return dmgPerSecond != 0 ? dmgPerSecond : Math.Sign(second.Strength - first.Strength); }); + + //afflictionInfoContainer.Content.RectTransform.SortChildren((r1, r2) => + //{ + // return Math.Sign(((Affliction)r2.GUIComponent.UserData).GetVitalityDecrease(this) - ((Affliction)r1.GUIComponent.UserData).GetVitalityDecrease(this)); + //}); } private void UpdateAfflictionInfos(IEnumerable afflictions) diff --git a/Barotrauma/BarotraumaClient/Source/GUI/SpriteSheetPlayer.cs b/Barotrauma/BarotraumaClient/Source/GUI/SpriteSheetPlayer.cs index 1bf8afa85..f533b7a1e 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/SpriteSheetPlayer.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/SpriteSheetPlayer.cs @@ -25,6 +25,7 @@ namespace Barotrauma private int currentFrameIndex = 0; private Color backgroundColor = new Color(0f, 0f, 0f, 1f); + private Action callbackOnStop; private bool isPlaying; public bool IsPlaying @@ -117,17 +118,24 @@ namespace Barotrauma isPlaying = false; } + private bool OKButtonClicked(GUIButton button, object userData) + { + Stop(); + callbackOnStop?.Invoke(); + return true; + } + public void AddToGUIUpdateList() { if (!isPlaying) return; background.AddToGUIUpdateList(); } - public void LoadContent(string contentPath, XElement videoElement, string contentId, bool startPlayback) + public void LoadContent(string contentPath, XElement videoElement, string contentId, bool startPlayback, bool hasButton, Action callback = null) { totalElapsed = loopTimer = 0.0f; animationSpeed = videoElement.GetAttributeFloat("animationspeed", 0.1f); - loopDelay = videoElement.GetAttributeFloat("loopdelay", 0.0f); ; + loopDelay = videoElement.GetAttributeFloat("loopdelay", 0.0f); if (playingSheets != null) { @@ -155,6 +163,17 @@ namespace Barotrauma title.Text = TextManager.Get(contentId); title.RectTransform.NonScaledSize = new Point(resolution.X, 30); + callbackOnStop = callback; + + if (hasButton) + { + var okButton = new GUIButton(new RectTransform(new Point(160, 50), videoFrame.RectTransform, Anchor.BottomCenter, Pivot.TopCenter) { AbsoluteOffset = new Point(0, -10) }, + TextManager.Get("OK")) + { + OnClicked = OKButtonClicked + }; + } + if (startPlayback) Play(); } diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs b/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs index 74185da13..870f6f909 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs @@ -669,7 +669,7 @@ namespace Barotrauma if (IsSinglePlayer) { orderGiver?.Speak( - order.GetChatMessage(character.Name, orderGiver.CurrentHull?.RoomName, option), ChatMessageType.Order); + order.GetChatMessage(character.Name, orderGiver.CurrentHull?.RoomName, option), null); } else if (orderGiver != null) { @@ -987,21 +987,25 @@ namespace Barotrauma chatBox.Update(deltaTime); chatBox.InputBox.Visible = Character.Controlled != null; - if ((PlayerInput.KeyHit(InputType.Chat) || PlayerInput.KeyHit(InputType.RadioChat)) && - !DebugConsole.IsOpen && chatBox.InputBox.Visible) + if (!DebugConsole.IsOpen && chatBox.InputBox.Visible) { - if (chatBox.InputBox.Selected) + if (PlayerInput.KeyHit(InputType.Chat)) { - chatBox.InputBox.Text = ""; - chatBox.InputBox.Deselect(); + if (chatBox.InputBox.Selected) + { + chatBox.InputBox.Text = ""; + chatBox.InputBox.Deselect(); + } + else + { + chatBox.InputBox.Select(); + } } - else + + if (PlayerInput.KeyHit(InputType.RadioChat) && !chatBox.InputBox.Selected) { chatBox.InputBox.Select(); - if (PlayerInput.KeyHit(InputType.RadioChat)) - { - chatBox.InputBox.Text = "r; "; - } + chatBox.InputBox.Text = "r; "; } } } diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/ContextualTutorial.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/ContextualTutorial.cs index 202caa6d1..860f24e2a 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/ContextualTutorial.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/ContextualTutorial.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Xml.Linq; using System; -using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework; using Barotrauma.Items.Components; using System.Linq; @@ -30,9 +29,7 @@ namespace Barotrauma.Tutorials private bool started = false; private string playableContentPath; - - private float inputGracePeriodTimer; - private const float inputGracePeriod = .5f; + private float tutorialTimer; private float degrading2ActivationCountdown; @@ -161,7 +158,6 @@ namespace Barotrauma.Tutorials activeSegment = null; tutorialTimer = 0.0f; - inputGracePeriodTimer = 0.0f; degrading2ActivationCountdown = -1; subStartingPosition = Vector2.Zero; characterTimeOnSonar.Clear(); @@ -228,36 +224,10 @@ namespace Barotrauma.Tutorials public override void Update(float deltaTime) { - if (!started) return; + if (!started || ContentRunning) return; + deltaTime *= 0.5f; - if (ContentRunning) // Content is running, wait until dismissed - { - if (inputGracePeriodTimer < inputGracePeriod) - { - inputGracePeriodTimer += deltaTime; - } - else if (Keyboard.GetState().GetPressedKeys().Length > 0 || Mouse.GetState().LeftButton == ButtonState.Pressed || Mouse.GetState().RightButton == ButtonState.Pressed) - { - switch (activeSegment.ContentType) - { - case ContentTypes.None: - break; - case ContentTypes.Video: - spriteSheetPlayer.Stop(); - break; - case ContentTypes.Text: - infoBox = null; - break; - } - - activeSegment = null; - ContentRunning = false; - inputGracePeriodTimer = 0.0f; - } - return; - } - for (int i = 0; i < segments.Count; i++) { if (segments[i].IsTriggered) continue; @@ -268,6 +238,12 @@ namespace Barotrauma.Tutorials } } + private void CurrentSegmentStopCallback() + { + activeSegment = null; + ContentRunning = false; + } + private bool CheckContextualTutorials(int index, float deltaTime) { switch (index) @@ -485,13 +461,13 @@ namespace Barotrauma.Tutorials case ContentTypes.None: break; case ContentTypes.Video: - spriteSheetPlayer.LoadContent(playableContentPath, activeSegment.Content, activeSegment.Name, true); + spriteSheetPlayer.LoadContent(playableContentPath, activeSegment.Content, activeSegment.Name, true, true, CurrentSegmentStopCallback); break; case ContentTypes.Text: infoBox = CreateInfoFrame(TextManager.Get(activeSegment.Name), TextManager.Get(activeSegment.Content.GetAttributeString("tag", ""), false, args), activeSegment.Content.GetAttributeInt("width", 300), activeSegment.Content.GetAttributeInt("height", 80), - activeSegment.Content.GetAttributeString("anchor", "Center"), false); + activeSegment.Content.GetAttributeString("anchor", "Center"), true, CurrentSegmentStopCallback); break; } diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/Tutorial.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/Tutorial.cs index c98b0ac73..1707a518e 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/Tutorial.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/Tutorial.cs @@ -11,6 +11,7 @@ namespace Barotrauma.Tutorials public static List Tutorials; protected GUIComponent infoBox; + private Action infoBoxClosedCallback; protected XElement configElement; private enum TutorialType { None, Scenario, Contextual }; @@ -136,10 +137,11 @@ namespace Barotrauma.Tutorials protected bool CloseInfoFrame(GUIButton button, object userData) { infoBox = null; + infoBoxClosedCallback?.Invoke(); return true; } - protected GUIComponent CreateInfoFrame(string text, bool hasButton = false) + protected GUIComponent CreateInfoFrame(string text, bool hasButton = false, Action callback = null) { int width = 300; int height = hasButton ? 110 : 80; @@ -154,9 +156,11 @@ namespace Barotrauma.Tutorials var textBlock = new GUITextBlock(new RectTransform(new Vector2(0.9f, 0.7f), infoBlock.RectTransform, Anchor.Center), text, wrap: true); + infoBoxClosedCallback = callback; + if (hasButton) { - var okButton = new GUIButton(new RectTransform(new Point(80, 25), infoBlock.RectTransform, Anchor.BottomCenter) { AbsoluteOffset = new Point(0, 5) }, + var okButton = new GUIButton(new RectTransform(new Point(160, 50), infoBlock.RectTransform, Anchor.BottomCenter, Pivot.TopCenter) { AbsoluteOffset = new Point(0, -10) }, TextManager.Get("OK")) { OnClicked = CloseInfoFrame @@ -168,7 +172,7 @@ namespace Barotrauma.Tutorials return infoBlock; } - protected GUIComponent CreateInfoFrame(string title, string text, int width, int height, string anchorStr, bool hasButton = false) + protected GUIComponent CreateInfoFrame(string title, string text, int width, int height, string anchorStr, bool hasButton = false, Action callback = null) { if (hasButton) height += 30; @@ -196,9 +200,11 @@ namespace Barotrauma.Tutorials var textBlock = new GUITextBlock(new RectTransform(new Vector2(0.9f, 1f), infoBlock.RectTransform, Anchor.BottomCenter), text, wrap: true); + infoBoxClosedCallback = callback; + if (hasButton) { - var okButton = new GUIButton(new RectTransform(new Point(80, 25), infoBlock.RectTransform, Anchor.BottomCenter) { AbsoluteOffset = new Point(0, 5) }, + var okButton = new GUIButton(new RectTransform(new Point(160, 50), infoBlock.RectTransform, Anchor.BottomCenter, Pivot.TopCenter) { AbsoluteOffset = new Point(0, -10) }, TextManager.Get("OK")) { OnClicked = CloseInfoFrame diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Fabricator.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Fabricator.cs index 5cbdb527a..68982c692 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Fabricator.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Fabricator.cs @@ -306,6 +306,13 @@ namespace Barotrauma.Items.Components new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform), text, textColor: inadequateSkills.Any() ? Color.Red : Color.LightGreen, font: GUI.SmallFont); } + } + + private bool SelectItem(Character user, FabricableItem selectedItem) + { + selectedItemFrame.ClearChildren(); + + var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), selectedItemFrame.RectTransform, Anchor.Center)) { RelativeSpacing = 0.03f, Stretch = true }; float degreeOfSuccess = user == null ? 0.0f : DegreeOfSuccess(user, selectedItem.RequiredSkills); if (degreeOfSuccess > 0.5f) { degreeOfSuccess = 1.0f; } @@ -321,6 +328,12 @@ namespace Barotrauma.Items.Components private bool StartButtonClicked(GUIButton button, object obj) { if (selectedItem == null) { return false; } + if (!outputContainer.Inventory.IsEmpty()) + { + outputInventoryHolder.Flash(Color.Red); + return false; + } + if (fabricatedItem == null) { StartFabricating(selectedItem, Character.Controlled); diff --git a/Barotrauma/BarotraumaClient/Source/Map/Lights/ConvexHull.cs b/Barotrauma/BarotraumaClient/Source/Map/Lights/ConvexHull.cs index 8fbe30db7..7ac9f226a 100644 --- a/Barotrauma/BarotraumaClient/Source/Map/Lights/ConvexHull.cs +++ b/Barotrauma/BarotraumaClient/Source/Map/Lights/ConvexHull.cs @@ -3,6 +3,7 @@ using Microsoft.Xna.Framework.Graphics; using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; namespace Barotrauma.Lights { @@ -112,11 +113,11 @@ namespace Barotrauma.Lights public int shadowVertexCount; - private Entity parentEntity; + private MapEntity parentEntity; private Rectangle boundingBox; - public Entity ParentEntity + public MapEntity ParentEntity { get { return parentEntity; } @@ -151,7 +152,7 @@ namespace Barotrauma.Lights get { return boundingBox; } } - public ConvexHull(Vector2[] points, Color color, Entity parent) + public ConvexHull(Vector2[] points, Color color, MapEntity parent) { if (shadowEffect == null) { @@ -567,8 +568,18 @@ namespace Barotrauma.Lights else { //light is inside, convexhull outside - if (chList.Submarine == null) continue; - + if (chList.Submarine == null) + { + lightPos += (ParentSub.WorldPosition - ParentSub.HiddenSubPosition); + HashSet visibleRuins = new HashSet(); + foreach (RuinGeneration.Ruin ruin in Level.Loaded.Ruins) + { + if (!MathUtils.CircleIntersectsRectangle(lightPos, range, ruin.Area)) { continue; } + visibleRuins.Add(ruin); + } + list.AddRange(chList.List.FindAll(ch => ch.ParentEntity?.ParentRuin != null && visibleRuins.Contains(ch.ParentEntity.ParentRuin))); + continue; + } //light and convexhull are both inside the same sub if (chList.Submarine == ParentSub) { diff --git a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs index 1e8762123..250d31cd6 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs @@ -1182,6 +1182,15 @@ namespace Barotrauma.Networking ConnectedClients.RemoveAt(i); } } + //remove clients that aren't present anymore + for (int i = ConnectedClients.Count - 1; i >= 0; i--) + { + if (!currentClients.Contains(ConnectedClients[i])) + { + GameMain.NetLobbyScreen.RemovePlayer(ConnectedClients[i].Name); + ConnectedClients.RemoveAt(i); + } + } Voting.AllowSubVoting = allowSubVoting; Voting.AllowModeVoting = allowModeVoting; diff --git a/Barotrauma/BarotraumaClient/Source/Networking/NetworkMember.cs b/Barotrauma/BarotraumaClient/Source/Networking/NetworkMember.cs index 328331b73..cbb0eb865 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/NetworkMember.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/NetworkMember.cs @@ -160,23 +160,32 @@ namespace Barotrauma.Networking //tab doesn't autoselect the chatbox when debug console is open, //because tab is used for autocompleting console commands - if ((PlayerInput.KeyHit(InputType.Chat) || PlayerInput.KeyHit(InputType.RadioChat)) && - !DebugConsole.IsOpen && (Screen.Selected != GameMain.GameScreen || msgBox.Visible)) + + if (!DebugConsole.IsOpen && (Screen.Selected != GameMain.GameScreen || msgBox.Visible)) { - if (msgBox.Selected) + if (PlayerInput.KeyHit(InputType.Chat)) { - msgBox.Text = ""; - msgBox.Deselect(); - } - else - { - msgBox.Select(); - if (Screen.Selected == GameMain.GameScreen && PlayerInput.KeyHit(InputType.RadioChat)) + if (msgBox.Selected) { - msgBox.Text = "r; "; + msgBox.Text = ""; + msgBox.Deselect(); + } + else + { + msgBox.Select(); + if ( PlayerInput.KeyHit(InputType.RadioChat)) + { + msgBox.Text = "r; "; + } } } + if (Screen.Selected == GameMain.GameScreen && PlayerInput.KeyHit(InputType.RadioChat) && !msgBox.Selected) + { + msgBox.Select(); + msgBox.Text = "r; "; + } } + if (ServerLog.LogFrame != null) ServerLog.LogFrame.AddToGUIUpdateList(); } diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CharacterEditorScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/CharacterEditorScreen.cs index 2731c054c..e1c15f6fb 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/CharacterEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/CharacterEditorScreen.cs @@ -1559,6 +1559,7 @@ namespace Barotrauma }; void UpdateJointScale(float value) { + freezeToggle.Selected = false; TryUpdateRagdollParam("jointscale", value); jointScaleText.Text = $"Joint Scale: {RagdollParams.JointScale.FormatDoubleDecimal()}"; character.AnimController.ResetJoints(); @@ -4301,11 +4302,15 @@ namespace Barotrauma }; break; case 1: - new GUITextBlock(leftElement, "Is Humanoid?"); + new GUITextBlock(leftElement, "Is Humanoid?") + { + TextColor = Color.White * 0.3f + }; new GUITickBox(rightElement, string.Empty) { Selected = IsHumanoid, - OnSelected = (tB) => IsHumanoid = tB.Selected + OnSelected = (tB) => IsHumanoid = tB.Selected, + Enabled = false }; break; case 2: diff --git a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs index 8a359fc07..f251a588c 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs @@ -692,6 +692,7 @@ namespace Barotrauma { if (GameMain.Client == null) return; spectateButton.Visible = true; + spectateButton.Enabled = true; } public void SetCampaignCharacterInfo(CharacterInfo characterInfo) @@ -1510,14 +1511,16 @@ namespace Barotrauma if ((prevSize == 1.0f && chatBox.BarScroll == 0.0f) || (prevSize < 1.0f && chatBox.BarScroll == 1.0f)) chatBox.BarScroll = 1.0f; } + // TODO: remember the previous head(s), check that the next is unique private bool ToggleHead(GUIButton button, object userData) { if (GameMain.NetworkMember.CharacterInfo == null) return true; - int dir = (int)userData; - GameMain.NetworkMember.CharacterInfo.HeadSpriteId += dir; - GameMain.NetworkMember.CharacterInfo.LoadHeadAttachments(); - GameMain.NetworkMember.CharacterInfo.LoadHeadSprite(); + var info = GameMain.NetworkMember.CharacterInfo; + info.SetRandomRace(); + info.SetRandomHead(); + info.LoadHeadAttachments(); + info.LoadHeadSprite(); StoreHead(); GameMain.Config.Save(); return true; @@ -1526,26 +1529,27 @@ namespace Barotrauma private bool SwitchGender(GUIButton button, object obj) { Gender gender = (Gender)obj; - GameMain.NetworkMember.CharacterInfo.Gender = gender; - GameMain.NetworkMember.CharacterInfo.SetRandomHead(); - GameMain.NetworkMember.CharacterInfo.LoadHeadAttachments(); - GameMain.NetworkMember.CharacterInfo.LoadHeadSprite(); + var info = GameMain.NetworkMember.CharacterInfo; + info.Gender = gender; + info.SetRandomHead(); + info.LoadHeadAttachments(); + info.LoadHeadSprite(); StoreHead(); GameMain.Config.Save(); return true; } - // TODO: switch race - private void StoreHead() { - GameMain.Config.CharacterRace = GameMain.NetworkMember.CharacterInfo.Race; - GameMain.Config.CharacterGender = GameMain.NetworkMember.CharacterInfo.Gender; - GameMain.Config.CharacterHeadIndex = GameMain.NetworkMember.CharacterInfo.HeadSpriteId; - GameMain.Config.CharacterHairIndex = GameMain.NetworkMember.CharacterInfo.HairIndex; - GameMain.Config.CharacterBeardIndex = GameMain.NetworkMember.CharacterInfo.BeardIndex; - GameMain.Config.CharacterMoustacheIndex = GameMain.NetworkMember.CharacterInfo.MoustacheIndex; - GameMain.Config.CharacterFaceAttachmentIndex = GameMain.NetworkMember.CharacterInfo.FaceAttachmentIndex; + var info = GameMain.NetworkMember.CharacterInfo; + var config = GameMain.Config; + config.CharacterRace = info.Race; + config.CharacterGender = info.Gender; + config.CharacterHeadIndex = info.HeadSpriteId; + config.CharacterHairIndex = info.HairIndex; + config.CharacterBeardIndex = info.BeardIndex; + config.CharacterMoustacheIndex = info.MoustacheIndex; + config.CharacterFaceAttachmentIndex = info.FaceAttachmentIndex; } public void SelectMode(int modeIndex) diff --git a/Barotrauma/BarotraumaClient/Source/Screens/SpriteEditorScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/SpriteEditorScreen.cs index 651f838b8..56adb609f 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/SpriteEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/SpriteEditorScreen.cs @@ -333,6 +333,8 @@ namespace Barotrauma element.Elements("BrokenSprite").ForEach(s => CreateSprite(s)); element.Elements("containedsprite").ForEach(s => CreateSprite(s)); element.Elements("ContainedSprite").ForEach(s => CreateSprite(s)); + element.Elements("inventoryicon").ForEach(s => CreateSprite(s)); + element.Elements("InventoryIcon").ForEach(s => CreateSprite(s)); //decorativesprites don't necessarily have textures (can be used to hide/disable other sprites) element.Elements("decorativesprite").ForEach(s => { if (s.Attribute("texture") != null) CreateSprite(s); }); element.Elements("DecorativeSprite").ForEach(s => { if (s.Attribute("texture") != null) CreateSprite(s); }); diff --git a/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs index b7178263c..71953769d 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs @@ -613,7 +613,7 @@ namespace Barotrauma new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), modificationDate.RectTransform, Anchor.TopRight), item.Modified.ToString(), textAlignment: Alignment.TopRight); var fileSize = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.0f), content.RectTransform), TextManager.Get("WorkshopItemFileSize") + ": "); - new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), fileSize.RectTransform, Anchor.TopRight), MathUtils.GetBytesReadable((long)item.Size), textAlignment: Alignment.TopRight); + new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), fileSize.RectTransform, Anchor.TopRight), MathUtils.GetBytesReadable(item.Installed ? (long)item.Size : item.DownloadSize), textAlignment: Alignment.TopRight); new GUIButton(new RectTransform(new Vector2(0.2f, 0.05f), content.RectTransform), TextManager.Get("WorkshopShowItemInSteam")) { diff --git a/Barotrauma/BarotraumaClient/Source/Sounds/SoundChannel.cs b/Barotrauma/BarotraumaClient/Source/Sounds/SoundChannel.cs index 34215feae..2f1073d83 100644 --- a/Barotrauma/BarotraumaClient/Source/Sounds/SoundChannel.cs +++ b/Barotrauma/BarotraumaClient/Source/Sounds/SoundChannel.cs @@ -457,7 +457,11 @@ namespace Barotrauma.Sounds { startedPlaying = false; buffersToUnqueue = 4; - unqueuedBuffers = (int[])streamBuffers.Clone(); + unqueuedBuffers = new int[4]; + for (int i = 0; i < 4; i++) + { + unqueuedBuffers[i] = (int)streamBuffers[i]; + } } for (int i = 0; i < buffersToUnqueue; i++) diff --git a/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs index 347b45346..4c0eac159 100644 --- a/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs +++ b/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.8.9.2")] -[assembly: AssemblyFileVersion("0.8.9.2")] +[assembly: AssemblyVersion("0.8.9.3")] +[assembly: AssemblyFileVersion("0.8.9.3")] diff --git a/Barotrauma/BarotraumaShared/BarotraumaShared.projitems b/Barotrauma/BarotraumaShared/BarotraumaShared.projitems index 30e1573b2..df8e3c7ea 100644 --- a/Barotrauma/BarotraumaShared/BarotraumaShared.projitems +++ b/Barotrauma/BarotraumaShared/BarotraumaShared.projitems @@ -246,6 +246,21 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/Barotrauma/BarotraumaShared/Data/ContentPackages/Vanilla 0.9.xml b/Barotrauma/BarotraumaShared/Data/ContentPackages/Vanilla 0.9.xml index 241faa7b0..1a16b7f60 100644 --- a/Barotrauma/BarotraumaShared/Data/ContentPackages/Vanilla 0.9.xml +++ b/Barotrauma/BarotraumaShared/Data/ContentPackages/Vanilla 0.9.xml @@ -60,6 +60,7 @@ + diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/AITarget.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/AITarget.cs index 029c586f6..9542150e9 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/AITarget.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/AITarget.cs @@ -21,13 +21,13 @@ namespace Barotrauma public float SoundRange { get { return soundRange; } - set { soundRange = Math.Max(value, MinSoundRange); } + set { soundRange = MathHelper.Clamp(value, MinSoundRange, MaxSoundRange); } } public float SightRange { get { return sightRange; } - set { sightRange = Math.Max(value, MinSightRange); } + set { sightRange = MathHelper.Clamp(value, MinSightRange, MaxSoundRange); } } private float sectorRad = MathHelper.TwoPi; @@ -58,7 +58,8 @@ namespace Barotrauma public bool Enabled = true; - public float MinSoundRange, MinSightRange; + public readonly float MinSoundRange, MinSightRange; + public readonly float MaxSoundRange = float.MaxValue, MaxSightRange = float.MaxValue; public Vector2 WorldPosition { @@ -102,6 +103,17 @@ namespace Barotrauma { SightRange = MinSightRange = element.GetAttributeFloat("sightrange", 0.0f); SoundRange = MinSoundRange = element.GetAttributeFloat("soundrange", 0.0f); + // Use the min and max definitions if found. + if (element.Attribute("minsightrange") != null) + { + MinSightRange = element.GetAttributeFloat("minsightrange", MinSightRange); + } + if (element.Attribute("minsoundrange") != null) + { + MinSoundRange = element.GetAttributeFloat("minsoundrange", MinSoundRange); + } + MaxSightRange = element.GetAttributeFloat("maxsightrange", MaxSightRange); + MaxSoundRange = element.GetAttributeFloat("maxsoundrange", MaxSoundRange); SonarLabel = element.GetAttributeString("sonarlabel", ""); } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs index 38eb433ec..569a01ea2 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs @@ -432,6 +432,20 @@ namespace Barotrauma attackSimPosition = ConvertUnits.ToSimUnits(selectedAiTarget.WorldPosition - Character.Submarine.Position); } + if (selectedAiTarget.Entity is Item item) + { + // If the item is held by a character, attack the character instead. + var pickable = item.components.Select(c => c as Pickable).FirstOrDefault(); + if (pickable != null) + { + var target = pickable.Picker?.AiTarget; + if (target != null) + { + selectedAiTarget = target; + } + } + } + if (wallTarget != null) { attackSimPosition = ConvertUnits.ToSimUnits(wallTarget.Position); diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescue.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescue.cs index 9e68af109..72913faf6 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescue.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescue.cs @@ -21,8 +21,13 @@ namespace Barotrauma { get { - if (targetCharacter.Removed) return false; - if (goToObjective != null && !goToObjective.CanBeCompleted) return false; + if (targetCharacter.Removed || + targetCharacter.IsDead || + targetCharacter.Vitality / targetCharacter.MaxVitality > AIObjectiveRescueAll.VitalityThreshold) + { + return false; + } + if (goToObjective != null && !goToObjective.CanBeCompleted) { return false; } return true; } @@ -208,7 +213,8 @@ namespace Barotrauma public override bool IsCompleted() { - bool isCompleted = !targetCharacter.IsUnconscious || targetCharacter.IsDead; + bool isCompleted = + targetCharacter.Vitality / targetCharacter.MaxVitality > AIObjectiveRescueAll.VitalityThreshold; if (isCompleted) { @@ -216,14 +222,19 @@ namespace Barotrauma null, 1.0f, "targethealed" + targetCharacter.Name, 60.0f); } - return isCompleted; + return isCompleted || targetCharacter.IsDead; } public override float GetPriority(AIObjectiveManager objectiveManager) { - if (targetCharacter.AnimController.CurrentHull == null) return 0.0f; - float distance = Vector2.DistanceSquared(character.WorldPosition, targetCharacter.WorldPosition); - return targetCharacter.IsDead ? 1000.0f / distance : 10000.0f / distance; + if (targetCharacter.AnimController.CurrentHull == null || targetCharacter.IsDead) { return 0.0f; } + + Vector2 diff = targetCharacter.WorldPosition - character.WorldPosition; + float distance = Math.Abs(diff.X) + Math.Abs(diff.Y); + + float vitalityFactor = (targetCharacter.MaxVitality - targetCharacter.Vitality) / targetCharacter.MaxVitality; + + return 1000.0f * vitalityFactor / distance; } } } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescueAll.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescueAll.cs index 3a6db490f..e7fc7efcc 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescueAll.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescueAll.cs @@ -5,6 +5,9 @@ namespace Barotrauma { class AIObjectiveRescueAll : AIObjective { + //only treat characters whose vitality is below this (0.8 = 80% of max vitality) + public const float VitalityThreshold = 0.8f; + private List rescueTargets; public AIObjectiveRescueAll(Character character) @@ -38,7 +41,8 @@ namespace Barotrauma rescueTargets = Character.CharacterList.FindAll(c => c.AIController is HumanAIController && c != character && - c.IsUnconscious); + !c.IsDead && + c.Vitality / c.MaxVitality < VitalityThreshold); } protected override void Act(float deltaTime) @@ -52,7 +56,6 @@ namespace Barotrauma public override bool IsCompleted() { return false; - } - + } } } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Animation/FishAnimController.cs b/Barotrauma/BarotraumaShared/Source/Characters/Animation/FishAnimController.cs index c396415e2..fba5a3812 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Animation/FishAnimController.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Animation/FishAnimController.cs @@ -349,7 +349,7 @@ namespace Barotrauma if (movement.LengthSquared() < 0.00001f) { WalkPos = MathHelper.SmoothStep(WalkPos, MathHelper.PiOver2, deltaTime * 5); - MainLimb.PullJointWorldAnchorB = Vector2.Lerp(MainLimb.PullJointWorldAnchorB, Collider.SimPosition, 0.5f); + MainLimb.PullJointWorldAnchorB = Collider.SimPosition; return; } @@ -459,14 +459,21 @@ namespace Barotrauma Limbs[i].body.ApplyForce(movement * Limbs[i].SteerForce * Limbs[i].Mass, pullPos); } + Vector2 mainLimbDiff = MainLimb.PullJointWorldAnchorB - MainLimb.SimPosition; if (CurrentSwimParams.UseSineMovement) { - MainLimb.PullJointWorldAnchorB = Vector2.SmoothStep(MainLimb.PullJointWorldAnchorB, Collider.SimPosition, (float)Math.Abs(Math.Sin(WalkPos))); + MainLimb.PullJointWorldAnchorB = Vector2.SmoothStep( + MainLimb.PullJointWorldAnchorB, + Collider.SimPosition, + mainLimbDiff.LengthSquared() > 10.0f ? 1.0f : (float)Math.Abs(Math.Sin(WalkPos))); } else { //MainLimb.PullJointWorldAnchorB = Collider.SimPosition; - MainLimb.PullJointWorldAnchorB = Vector2.Lerp(MainLimb.PullJointWorldAnchorB, Collider.SimPosition, 0.5f); + MainLimb.PullJointWorldAnchorB = Vector2.Lerp( + MainLimb.PullJointWorldAnchorB, + Collider.SimPosition, + mainLimbDiff.LengthSquared() > 10.0f ? 1.0f : 0.5f); } floorY = Limbs[0].SimPosition.Y; diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Animation/HumanoidAnimController.cs b/Barotrauma/BarotraumaShared/Source/Characters/Animation/HumanoidAnimController.cs index 441f5e373..ce759f21d 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Animation/HumanoidAnimController.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Animation/HumanoidAnimController.cs @@ -1694,26 +1694,33 @@ namespace Barotrauma if (holdable.Pusher != null) { - if (!holdable.Pusher.Enabled) + if (character.IsUnconscious || character.Stun > 0.0f) { - holdable.Pusher.Enabled = true; - holdable.Pusher.ResetDynamics(); - holdable.Pusher.SetTransform(currItemPos, itemAngle); - foreach (Character character in Character.CharacterList) - { - holdable.Pusher.FarseerBody.RestoreCollisionWith(character.AnimController.Collider.FarseerBody); - } - holdable.Pusher.FarseerBody.IgnoreCollisionWith(Collider.FarseerBody); + holdable.Pusher.Enabled = false; } else { - holdable.Pusher.TargetPosition = currItemPos; - holdable.Pusher.TargetRotation = character.IsUnconscious || character.Stun > 0.0f ? itemAngle : holdAngle * Dir; + if (!holdable.Pusher.Enabled) + { + holdable.Pusher.Enabled = true; + holdable.Pusher.ResetDynamics(); + holdable.Pusher.SetTransform(currItemPos, itemAngle); + foreach (Character character in Character.CharacterList) + { + holdable.Pusher.FarseerBody.RestoreCollisionWith(character.AnimController.Collider.FarseerBody); + } + holdable.Pusher.FarseerBody.IgnoreCollisionWith(Collider.FarseerBody); + } + else + { + holdable.Pusher.TargetPosition = currItemPos; + holdable.Pusher.TargetRotation = character.IsUnconscious || character.Stun > 0.0f ? itemAngle : holdAngle * Dir; - holdable.Pusher.MoveToTargetPosition(true); + holdable.Pusher.MoveToTargetPosition(true); - currItemPos = holdable.Pusher.SimPosition; - itemAngle = holdable.Pusher.Rotation; + currItemPos = holdable.Pusher.SimPosition; + itemAngle = holdable.Pusher.Rotation; + } } } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs index 9580cff53..2eca63756 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs @@ -216,6 +216,9 @@ namespace Barotrauma { if (limb.IsSevered) continue; limb.body.SetTransform(Collider.SimPosition, Collider.Rotation); + //reset pull joints (they may be somewhere far away if the character has moved from the position where animations were last updated) + limb.PullJointEnabled = false; + limb.PullJointWorldAnchorB = limb.SimPosition; } } } @@ -903,7 +906,10 @@ namespace Barotrauma else if (newHull != null && currentHull != null && newHull.Submarine != currentHull.Submarine) { character.MemLocalState?.Clear(); - Teleport(ConvertUnits.ToSimUnits(currentHull.Submarine.Position - newHull.Submarine.Position), + Vector2 newSubPos = newHull.Submarine == null ? Vector2.Zero : newHull.Submarine.Position; + Vector2 prevSubPos = currentHull.Submarine == null ? Vector2.Zero : currentHull.Submarine.Position; + + Teleport(ConvertUnits.ToSimUnits(prevSubPos - newSubPos), Vector2.Zero); } } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs index 11b7aea79..518a16277 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs @@ -486,22 +486,25 @@ namespace Barotrauma } } + private bool canBeDragged = true; public bool CanBeDragged { get { - if (Removed || !AnimController.Draggable) return false; + if (!canBeDragged) { return false; } + if (Removed || !AnimController.Draggable) { return false; } return IsDead || Stun > 0.0f || LockHands || IsUnconscious; } + set { canBeDragged = value; } } - + //can other characters access the inventory of this character + private bool canInventoryBeAccessed = true; public bool CanInventoryBeAccessed { get { - if (Removed || Inventory == null) return false; - + if (!canInventoryBeAccessed || Removed || Inventory == null) { return false; } if (!Inventory.AccessibleWhenAlive) { return IsDead; @@ -511,6 +514,7 @@ namespace Barotrauma return (IsDead || Stun > 0.0f || LockHands || IsUnconscious); } } + set { canInventoryBeAccessed = value; } } public override Vector2 SimPosition @@ -1580,12 +1584,12 @@ namespace Barotrauma if (!CanInteractWith(c)) continue; float dist = Vector2.DistanceSquared(mouseSimPos, c.SimPosition); - if (dist < maxDist*maxDist && (closestCharacter == null || dist < closestDist)) + if (dist < maxDist * maxDist && (closestCharacter == null || dist < closestDist)) { closestCharacter = c; closestDist = dist; } - + /*FarseerPhysics.Common.Transform transform; c.AnimController.Collider.FarseerBody.GetTransform(out transform); for (int i = 0; i < c.AnimController.Collider.FarseerBody.FixtureList.Count; i++) @@ -1717,7 +1721,7 @@ namespace Barotrauma { SelectCharacter(focusedCharacter); } - else if (focusedCharacter != null && IsKeyHit(InputType.Health)) + else if (focusedCharacter != null && IsKeyHit(InputType.Health) && focusedCharacter.CharacterHealth.UseHealthWindow) { if (focusedCharacter == SelectedCharacter) { @@ -2018,15 +2022,16 @@ namespace Barotrauma private void UpdateSightRange() { if (aiTarget == null) { return; } + // TODO: the formula might need some tweaking float range = (float)Math.Sqrt(Mass) * 1000.0f + AnimController.Collider.LinearVelocity.Length() * 500.0f; - aiTarget.SightRange = MathHelper.Clamp(range, 2000.0f, 50000.0f); + aiTarget.SightRange = MathHelper.Clamp(range, 0, 15000.0f); } private void UpdateSoundRange() { if (aiTarget == null) { return; } - float range = (float)Math.Sqrt(Mass) * 100.0f + AnimController.Collider.LinearVelocity.Length() * Noise; - aiTarget.SoundRange = MathHelper.Clamp(range, 2000f, 50000f); + float range = Mass / 5 * AnimController.TargetMovement.Length() * Noise; + aiTarget.SoundRange = MathHelper.Clamp(range, 0f, 5000f); } public void SetOrder(Order order, string orderOption, Character orderGiver, bool speak = true) @@ -2306,15 +2311,17 @@ namespace Barotrauma private void Implode(bool isNetworkMessage = false) { + if (CharacterHealth.Unkillable) { return; } + if (!isNetworkMessage) { - if (GameMain.Client != null) return; + if (GameMain.Client != null) return; } Kill(CauseOfDeathType.Pressure, null, isNetworkMessage); CharacterHealth.PressureAffliction.Strength = CharacterHealth.PressureAffliction.Prefab.MaxStrength; CharacterHealth.SetAllDamage(200.0f, 0.0f, 0.0f); - BreakJoints(); + BreakJoints(); } public void BreakJoints() diff --git a/Barotrauma/BarotraumaShared/Source/Characters/CharacterInfo.cs b/Barotrauma/BarotraumaShared/Source/Characters/CharacterInfo.cs index 30eb2922f..6d0959718 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/CharacterInfo.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/CharacterInfo.cs @@ -200,12 +200,9 @@ namespace Barotrauma if (headSpriteId < (int)spriteRange.X) headSpriteId = (int)(spriteRange.Y); if (headSpriteId > (int)spriteRange.Y) headSpriteId = (int)(spriteRange.X); - if (headSpriteId != oldId) - { - headSprite = null; - attachmentSprites = null; - ResetHeadAttachments(); - } + headSprite = null; + attachmentSprites = null; + ResetHeadAttachments(); } } @@ -282,12 +279,15 @@ namespace Barotrauma SourceElement = doc.Root; if (doc.Root.GetAttributeBool("genders", false)) { - this.gender = gender == Gender.None ? SetRandomGender() : gender; + this.gender = gender == Gender.None ? GetRandomGender() : gender; + } + if (!Enum.TryParse(doc.Root.GetAttributeString("race", "None"), true, out race)) + { + race = GetRandomRace(); } - Enum.TryParse(doc.Root.GetAttributeString("race", "None"), true, out race); if (race == Race.None) { - SetRandomRace(); + race = GetRandomRace(); } CalculateHeadSpriteRange(); SetRandomHeadID(); @@ -403,10 +403,6 @@ namespace Barotrauma } } - public Gender SetRandomGender() => gender = (Rand.Range(0.0f, 1.0f, Rand.RandSync.Server) < SourceElement.GetAttributeFloat("femaleratio", 0.5f)) ? Gender.Female : Gender.Male; - public Race SetRandomRace() => race = new Race[] { Race.White, Race.Black, Race.Asian }.GetRandom(Rand.RandSync.Server); - public int SetRandomHead() => HeadSpriteId = SetRandomHeadID(); - private XDocument GetConfig(string file) { if (!cachedConfigs.TryGetValue(file, out XDocument doc)) @@ -418,6 +414,12 @@ namespace Barotrauma return doc; } + public Gender SetRandomGender() => Gender = GetRandomGender(); + public Race SetRandomRace() => Race = GetRandomRace(); + public int SetRandomHead() => HeadSpriteId = SetRandomHeadID(); + public Gender GetRandomGender() => (Rand.Range(0.0f, 1.0f, Rand.RandSync.Server) < SourceElement.GetAttributeFloat("femaleratio", 0.5f)) ? Gender.Female : Gender.Male; + public Race GetRandomRace() => new Race[] { Race.White, Race.Black, Race.Asian }.GetRandom(Rand.RandSync.Server); + private int SetRandomHeadID() { if (headSpriteRange != Vector2.Zero) diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaShared/Source/Characters/Health/CharacterHealth.cs index f2f251777..cdbd58fb7 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Health/CharacterHealth.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Health/CharacterHealth.cs @@ -96,7 +96,7 @@ namespace Barotrauma private Affliction oxygenLowAffliction; private Affliction pressureAffliction; private Affliction stunAffliction; - + public bool IsUnconscious { get { return Vitality <= 0.0f; } @@ -222,11 +222,22 @@ namespace Barotrauma partial void InitProjSpecific(XElement element, Character character); - public IEnumerable GetAllAfflictions() + public IEnumerable GetAllAfflictions(Func limbHealthFilter = null) { - return afflictions.Concat(limbHealths.SelectMany(lh => lh.Afflictions).ToList()); + // TODO: If there can be duplicates, we should use Union instead. + return limbHealthFilter == null + ? afflictions.Concat(limbHealths.SelectMany(lh => lh.Afflictions)) + : afflictions.Concat(limbHealths.SelectMany(lh => lh.Afflictions.Where(limbHealthFilter))); } + private LimbHealth GetMathingLimbHealth(Affliction affliction) => limbHealths[Character.AnimController.GetLimb(affliction.Prefab.IndicatorLimb).HealthIndex]; + + /// + /// Returns the limb afflictions and non-limbspecific afflictions that are set to be displayed on this limb. + /// + private IEnumerable GetMatchingAfflictions(LimbHealth limb, Func predicate) + => limb.Afflictions.Where(predicate).Union(afflictions.Where(a => predicate(a) && GetMathingLimbHealth(a) == limb)); + public Affliction GetAffliction(string afflictionType, bool allowLimbAfflictions = true) { foreach (Affliction affliction in afflictions) @@ -466,9 +477,11 @@ namespace Barotrauma CalculateVitality(); if (Vitality <= MinVitality) Kill(); +#if CLIENT + selectedLimbIndex = -1; +#endif } - private void AddAffliction(Affliction newAffliction) { if (!DoesBleed && newAffliction is AfflictionBleeding) return; @@ -675,7 +688,7 @@ namespace Barotrauma return allAfflictions; } - + public void ServerWrite(NetBuffer msg) { List activeAfflictions = afflictions.FindAll(a => a.Strength > 0.0f && a.Strength >= a.Prefab.ActivationThreshold); diff --git a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs index a588a14c0..4841fff62 100644 --- a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs @@ -1909,11 +1909,20 @@ namespace Barotrauma commands.Add(new Command("fixhulls|fixwalls", "fixwalls/fixhulls: Fixes all walls.", (string[] args) => { - foreach (Structure w in Structure.WallList) + var walls = new List(Structure.WallList); + foreach (Structure w in walls) { - for (int i = 0; i < w.SectionCount; i++) + try { - w.AddDamage(i, -100000.0f); + for (int i = 0; i < w.SectionCount; i++) + { + w.AddDamage(i, -100000.0f); + } + } + catch (InvalidOperationException e) + { + string errorMsg = "Error while executing the fixhulls command.\n" + e.StackTrace; + GameAnalyticsManager.AddErrorEventOnce("DebugConsole.FixHulls", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); } } }, null, null, isCheat: true)); diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/CampaignMode.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/CampaignMode.cs index 3269e9d32..d157a9856 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/CampaignMode.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/CampaignMode.cs @@ -133,8 +133,10 @@ namespace Barotrauma CharacterInfo characterInfo = new CharacterInfo(Character.HumanConfigFile, jobPrefab: watchmanJob); var spawnedCharacter = Character.Create(characterInfo, watchmanSpawnpoint.WorldPosition, Level.Loaded.Seed + (outpost == Level.Loaded.StartOutpost ? "start" : "end")); - spawnedCharacter.CharacterHealth.Unkillable = true; spawnedCharacter.CharacterHealth.UseHealthWindow = false; + spawnedCharacter.CharacterHealth.Unkillable = true; + spawnedCharacter.CanInventoryBeAccessed = false; + spawnedCharacter.CanBeDragged = false; spawnedCharacter.SetCustomInteract( WatchmanInteract, hudText: TextManager.Get("TalkHint").Replace("[key]", GameMain.Config.KeyBind(InputType.Select).ToString())); diff --git a/Barotrauma/BarotraumaShared/Source/GameSettings.cs b/Barotrauma/BarotraumaShared/Source/GameSettings.cs index be4f410ab..fc431c53a 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSettings.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSettings.cs @@ -383,6 +383,10 @@ namespace Barotrauma { CharacterRace = r; } + else + { + CharacterRace = Race.White; + } CharacterHairIndex = subElement.GetAttributeInt("hairindex", -1); CharacterBeardIndex = subElement.GetAttributeInt("beardindex", -1); CharacterMoustacheIndex = subElement.GetAttributeInt("moustacheindex", -1); diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/DockingPort.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/DockingPort.cs index dfc945bd0..df8b6de39 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/DockingPort.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/DockingPort.cs @@ -449,12 +449,11 @@ namespace Barotrauma.Items.Components hullRects[1].Width += rightHullDiff; } } - - + for (int i = 0; i < 2; i++) { hullRects[i].Location -= MathUtils.ToPoint((subs[i].WorldPosition - subs[i].HiddenSubPosition)); - hulls[i] = new Hull(MapEntityPrefab.Find(null, "Hull"), hullRects[i], subs[i]); + hulls[i] = new Hull(MapEntityPrefab.Find(null, "hull"), hullRects[i], subs[i]); hulls[i].AddToGrid(subs[i]); hulls[i].FreeID(); diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/Propulsion.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/Propulsion.cs index 0a15717cf..9f83a302e 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/Propulsion.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/Propulsion.cs @@ -53,6 +53,7 @@ namespace Barotrauma.Items.Components usableIn = UsableIn.Both; break; } + ResetSoundRange(); } public override bool Use(float deltaTime, Character character = null) @@ -108,7 +109,25 @@ namespace Barotrauma.Items.Components useState -= deltaTime; if (useState <= 0.0f) IsActive = false; + + if (item.AiTarget != null) + { + item.AiTarget.SoundRange = IsActive ? item.AiTarget.MaxSoundRange : item.AiTarget.MinSoundRange; + } + } + + public override void Unequip(Character character) + { + base.Unequip(character); + ResetSoundRange(); + } + + private void ResetSoundRange() + { + if (item.AiTarget != null) + { + item.AiTarget.SoundRange = item.AiTarget.MinSoundRange; + } } - } } diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Fabricator.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Fabricator.cs index 7f52abd52..f6d3fd08e 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Fabricator.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Fabricator.cs @@ -210,6 +210,7 @@ namespace Barotrauma.Items.Components private void StartFabricating(FabricableItem selectedItem, Character user) { if (selectedItem == null) return; + if (!outputContainer.Inventory.IsEmpty()) return; if (user != null) { diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Reactor.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Reactor.cs index 0f3b40804..e03d80744 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Reactor.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Reactor.cs @@ -355,6 +355,7 @@ namespace Barotrauma.Items.Components { float desiredTurbineOutput = (optimalTurbineOutput.X + optimalTurbineOutput.Y) / 2.0f; targetTurbineOutput += MathHelper.Clamp(desiredTurbineOutput - targetTurbineOutput, -speed, speed) * deltaTime; + targetTurbineOutput = MathHelper.Clamp(targetTurbineOutput, 0.0f, 100.0f); float desiredFissionRate = (optimalFissionRate.X + optimalFissionRate.Y) / 2.0f; targetFissionRate += MathHelper.Clamp(desiredFissionRate - targetFissionRate, -speed, speed) * deltaTime; @@ -367,6 +368,7 @@ namespace Barotrauma.Items.Components { targetFissionRate = Math.Min(targetFissionRate + speed * 2 * deltaTime, allowedFissionRate.Y); } + targetFissionRate = MathHelper.Clamp(targetFissionRate, 0.0f, 100.0f); } public override void UpdateBroken(float deltaTime, Camera cam) diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Power/PowerContainer.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Power/PowerContainer.cs index cee29a2fc..22f578a89 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Power/PowerContainer.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Power/PowerContainer.cs @@ -83,7 +83,8 @@ namespace Barotrauma.Items.Components if (!MathUtils.IsValid(value)) return; charge = MathHelper.Clamp(value, 0.0f, capacity); - if (Math.Abs(charge - lastSentCharge) / capacity > 1.0f) + //send a network event if the charge has changed by more than 5% + if (Math.Abs(charge - lastSentCharge) / capacity > 0.05f) { if (GameMain.Server != null) item.CreateServerEvent(this); lastSentCharge = charge; diff --git a/Barotrauma/BarotraumaShared/Source/Items/Inventory.cs b/Barotrauma/BarotraumaShared/Source/Items/Inventory.cs index c3ac3ef39..dab458614 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Inventory.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Inventory.cs @@ -189,6 +189,16 @@ namespace Barotrauma } } + public bool IsEmpty() + { + for (int i = 0; i < capacity; i++) + { + if (Items[i] != null) return false; + } + + return true; + } + protected bool TrySwapping(int index, Item item, Character user, bool createNetworkEvent) { if (item?.ParentInventory == null || Items[index] == null) return false; diff --git a/Barotrauma/BarotraumaShared/Source/Map/Levels/Ruins/RuinGenerator.cs b/Barotrauma/BarotraumaShared/Source/Map/Levels/Ruins/RuinGenerator.cs index 7d8b22a56..e863979f3 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Levels/Ruins/RuinGenerator.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Levels/Ruins/RuinGenerator.cs @@ -191,6 +191,14 @@ namespace Barotrauma.RuinGeneration private BTRoom entranceRoom; + private List ruinEntities = new List(); + private List doors = new List(); + + public IEnumerable RuinEntities + { + get { return ruinEntities; } + } + public List RuinShapes { get { return allShapes; } @@ -303,7 +311,7 @@ namespace Barotrauma.RuinGeneration GenerateRuinEntities(caveCells, area, mirror); } - class RuinEntity + public class RuinEntity { public readonly RuinEntityConfig Config; public readonly MapEntity Entity; @@ -319,8 +327,6 @@ namespace Barotrauma.RuinGeneration } } - private List ruinEntities = new List(); - private List doors = new List(); private void GenerateRuinEntities(List caveCells, Rectangle ruinArea, bool mirror) { var entityGrid = Hull.GenerateEntityGrid(new Rectangle(ruinArea.X, ruinArea.Y + ruinArea.Height, ruinArea.Width, ruinArea.Height)); diff --git a/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs b/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs index 3d2e231c7..4e39f612e 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs @@ -208,16 +208,16 @@ namespace Barotrauma } //remove connections that are too short - float minDistance = generationParams.MinConnectionDistance; + float minConnectionDistanceSqr = generationParams.MinConnectionDistance * generationParams.MinConnectionDistance; for (int i = connections.Count - 1; i >= 0; i--) { LocationConnection connection = connections[i]; - if (Vector2.Distance(connection.Locations[0].MapPosition, connection.Locations[1].MapPosition) > minDistance) + if (Vector2.DistanceSquared(connection.Locations[0].MapPosition, connection.Locations[1].MapPosition) > minConnectionDistanceSqr) { continue; } - + //locations.Remove(connection.Locations[0]); connections.Remove(connection); @@ -227,7 +227,7 @@ namespace Barotrauma if (connection2.Locations[1] == connection.Locations[0]) connection2.Locations[1] = connection.Locations[1]; } } - + HashSet connectedLocations = new HashSet(); foreach (LocationConnection connection in connections) { @@ -238,15 +238,44 @@ namespace Barotrauma connectedLocations.Add(connection.Locations[1]); } + //remove orphans + Locations.RemoveAll(c => !connectedLocations.Contains(c)); + + //remove locations that are too close to each other + float minLocationDistanceSqr = generationParams.MinLocationDistance * generationParams.MinLocationDistance; + for (int i = Locations.Count - 1; i >= 0; i--) + { + for (int j = Locations.Count - 1; j > i; j--) + { + float dist = Vector2.DistanceSquared(Locations[i].MapPosition, Locations[j].MapPosition); + if (dist > minLocationDistanceSqr) + { + continue; + } + //move connections from Locations[j] to Locations[i] + foreach (LocationConnection connection in Locations[j].Connections) + { + if (connection.Locations[0] == Locations[j]) + { + connection.Locations[0] = Locations[i]; + } + else + { + connection.Locations[1] = Locations[i]; + } + Locations[i].Connections.Add(connection); + } + Locations.RemoveAt(j); + } + } + //remove orphans Locations.RemoveAll(c => !connectedLocations.Contains(c)); for (int i = connections.Count - 1; i >= 0; i--) { i = Math.Min(i, connections.Count - 1); - LocationConnection connection = connections[i]; - for (int n = Math.Min(i - 1, connections.Count - 1); n >= 0; n--) { if (connection.Locations.Contains(connections[n].Locations[0]) @@ -399,6 +428,7 @@ namespace Barotrauma GameAnalyticsManager.AddErrorEventOnce("Map.SelectLocation:LocationNotFound", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return; } + CurrentLocation.SelectedMissionIndex = missionIndex; SelectedLocation = location; SelectedConnection = connections.Find(c => c.Locations.Contains(CurrentLocation) && c.Locations.Contains(SelectedLocation)); diff --git a/Barotrauma/BarotraumaShared/Source/Map/Map/MapGenerationParams.cs b/Barotrauma/BarotraumaShared/Source/Map/Map/MapGenerationParams.cs index 0c1d4535d..9acff82e9 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Map/MapGenerationParams.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Map/MapGenerationParams.cs @@ -108,6 +108,9 @@ namespace Barotrauma [Serialize(10.0f, true), Editable(0.0f, 500.0f, ToolTip = "Connections smaller than this are removed.")] public float MinConnectionDistance { get; set; } + [Serialize(5.0f, true), Editable(0.0f, 100.0f, ToolTip = "Locations that are closer than this to another location are removed.")] + public float MinLocationDistance { get; set; } + [Serialize(0.2f, true), Editable(0.0f, 10.0f, ToolTip = "Affects how many iterations are done when generating the jagged shape of the connections (iterations = Sqrt(connectionLength * multiplier)).")] public float ConnectionIterationMultiplier { get; set; } diff --git a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs index 312c182cb..594927260 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs @@ -1897,6 +1897,8 @@ namespace Barotrauma.Networking Log(msg, ServerLog.MessageType.ServerMessage); + if (client.SteamID > 0) { SteamManager.StopAuthSession(client.SteamID); } + client.Connection.Disconnect(targetmsg); connectedClients.Remove(client); diff --git a/Barotrauma/BarotraumaShared/Source/Networking/GameServerLogin.cs b/Barotrauma/BarotraumaShared/Source/Networking/GameServerLogin.cs index e2c43da0f..1f6507cd3 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/GameServerLogin.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/GameServerLogin.cs @@ -183,6 +183,7 @@ namespace Barotrauma.Networking { //server is full, can't allow new connection connection.Disconnect(DisconnectReason.ServerFull.ToString()); + if (steamID > 0) { Steam.SteamManager.StopAuthSession(steamID); } return; } @@ -224,6 +225,7 @@ namespace Barotrauma.Networking { //client did not ask for nonce first, can't authorize inc.SenderConnection.Disconnect(DisconnectReason.AuthenticationRequired.ToString()); + if (unauthClient.SteamID > 0) { Steam.SteamManager.StopAuthSession(unauthClient.SteamID); } return; } @@ -450,7 +452,7 @@ namespace Barotrauma.Networking private void DisconnectUnauthClient(NetIncomingMessage inc, UnauthenticatedClient unauthClient, DisconnectReason reason, string message) { inc.SenderConnection.Disconnect(reason.ToString() + "; " + message); - + if (unauthClient.SteamID > 0) { Steam.SteamManager.StopAuthSession(unauthClient.SteamID); } if (unauthClient != null) { unauthenticatedClients.Remove(unauthClient); diff --git a/Barotrauma/BarotraumaShared/Source/Networking/SteamManager.cs b/Barotrauma/BarotraumaShared/Source/Networking/SteamManager.cs index a01228194..f08a1a5e9 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/SteamManager.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/SteamManager.cs @@ -408,6 +408,14 @@ namespace Barotrauma.Steam return true; } + public static void StopAuthSession(ulong clientSteamID) + { + if (instance == null || !instance.isInitialized || instance.server == null) return; + + DebugConsole.Log("SteamManager ending auth session with Steam client " + clientSteamID); + instance.server.Auth.EndSession(clientSteamID); + } + public static bool CloseServer() { if (instance == null || !instance.isInitialized || instance.server == null) return false; diff --git a/Barotrauma/BarotraumaShared/Submarines/Humpback.sub b/Barotrauma/BarotraumaShared/Submarines/Humpback.sub index 433eff333..7ccd5c2b3 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Humpback.sub and b/Barotrauma/BarotraumaShared/Submarines/Humpback.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Orca.sub b/Barotrauma/BarotraumaShared/Submarines/Orca.sub index 31b4db621..9205d10de 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Orca.sub and b/Barotrauma/BarotraumaShared/Submarines/Orca.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Typhon.sub b/Barotrauma/BarotraumaShared/Submarines/Typhon.sub index 8d4c9f11a..b8a5f90fb 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Typhon.sub and b/Barotrauma/BarotraumaShared/Submarines/Typhon.sub differ diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index 06e3f1c6c..b6d5ad3b2 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,3 +1,68 @@ +--------------------------------------------------------------------------------------------------------- +v0.8.9.3 +--------------------------------------------------------------------------------------------------------- + +- Made molochs slower. +- Watchmen cannot be dragged or grabbed. +- AI characters can give treatment to characters who aren't unconscious. +- Added a button that dismisses the tutorial popups to prevent accidentally closing the popups. +- Underwater scooters now attract monsters. +- Improvements and balancing to vanilla submarines. +- Made alien ruin walls more durable. +- Reduced item deterioration speeds. +- Added "yes to all" and "no to all" buttons to the prompts when deleting containers in the submarine editor. +- Improved the background smoke texture in hydrothermal wastes. +- Baby moloch, doo doo doo doo doo doo + +- Fixed console errors in the chemical shipment mission due to auxiliorizine being still present in the +mission configuration despite the item being removed. +- Made coilgun ammunition boxes craftable and purchaseable, coilgun bolts cannot be purchased anymore. +- Fixed AI-controlled husk not spawning when a huskified player dies. +- Fixed AI crew occasionally going outside to fix leaks. +- Fixed server failing to sync clients who join the server after a character has been removed during +the round (e.g. eaten, turned into a husk). +- Fixed server-side console errors when clients attempt to use a fabricator. +- Display Steam authentication errors in the server logs. +- Fixed status effects with a ReduceAffliction value of 0 freezing the game. +- Fixed sliders not moving in the battery/supercapacitor interface when an AI character is operating it. +- Fixed chatbox being deselected in the net lobby when receiving a lobby update from the server (i.e. +whenever the server host changes any setting). +- Fixed OnBroken status effects firing in the submarine editor when an item's condition is set to zero +(for example, reactors exploding and breaking all the nearby walls). +- Fixed file number being added to the file extension of debug console log files ("file123.txt (2)" +instead of "file123 (2).txt"). +- Fixed battery positioning in charging docks. +- Fixed crashing when ending a single player round while a character is outside the sub. +- Fixed "attempting to remove an already removed item" console errors when ending a round. +- Fixed fire sounds persisting in menus. +- Fixed the layout of the extra cargo menu in server settings. +- Fixed depth charges disappearing from loaders when interacting them with both hand slots full. +- Fixed StatusEffects not being able to target item components. Caused doors to be impossible to weld +and most likely other issues with item StatusEffects as well. +- Artifacts spawn in artifact holders again. +- Fixes to "attempted to move pulljoint extremely far" errors which occasionally caused severe problems +in syncing characters' positions. +- Fixed a bug that occasionally caused monsters to spawn very close to the submarine in monster missions. +- Fixed servers occasionally starting the round multiple times when automatically starting the game via +autorestart or clients being ready. +- Fixed up-to-date content packages being reported as incompatible in the Steam workshop menu. +- Changed the default radio chat hotkey to T. +- Fixed the line of sight effect not working on ruins when looking at them from inside a sub. +- Fixed fabricator allowing new items to be created when the output is not empty, resulting in wasted materials. +- Fixed servers reporting incorrect player counts in the server list. +- Fixed order messages not being visible in single player if the character issuing the order has no headset. +- Fixed riot shields retaining their pushing ability even when the user is stunned or unconscious. +- Fixed rubber ducks not floating like a good duck should. +- Prevent locations from being generated too close to each other in the campaign map. +- Fixed battery and supercapacitor charges not staying in sync between the server and clients. +- Fixed watchmen imploding continuously if they end up outside. +- Fixed non-downloaded workshop items showing zero as the file size. +- Fixed spectate button staying disabled if starting a round fails (due to a missing sub file for example). +- Fixed crashing when teleporting characters from a submarine to ruins in multiplayer. +- Fixed automatic temperature control setting turbine output above 100 if the power consumption is higher +than what the reactor can generate. Caused "failed to write an event for the entity" errors in multiplayer. +- Fixed AI characters attempting to treat dead characters. + --------------------------------------------------------------------------------------------------------- v0.8.9.2 --------------------------------------------------------------------------------------------------------- diff --git a/Libraries/Facepunch.Steamworks/Interfaces/Workshop.Item.cs b/Libraries/Facepunch.Steamworks/Interfaces/Workshop.Item.cs index a8c7f1f7d..718fce135 100644 --- a/Libraries/Facepunch.Steamworks/Interfaces/Workshop.Item.cs +++ b/Libraries/Facepunch.Steamworks/Interfaces/Workshop.Item.cs @@ -26,6 +26,7 @@ namespace Facepunch.Steamworks public uint VotesUp { get; private set; } public DateTime Modified { get; private set; } public DateTime Created { get; private set; } + public int DownloadSize { get; private set; } public Item( ulong Id, Workshop workshop ) { @@ -46,6 +47,7 @@ namespace Facepunch.Steamworks item.VotesDown = details.VotesDown; item.Modified = Utility.Epoch.ToDateTime( details.TimeUpdated ); item.Created = Utility.Epoch.ToDateTime( details.TimeCreated ); + item.DownloadSize = details.FileSize; return item; }