From e4f41789b04cf8d98665998d9f10467e60a389b0 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Thu, 16 May 2019 05:25:02 +0300 Subject: [PATCH] (143d158cb) Merge branch 'dev' into human-ai --- .../Source/Characters/Animation/Ragdoll.cs | 83 ---- .../Source/GUI/GUIComponent.cs | 2 +- .../BarotraumaClient/Source/GUI/GUIImage.cs | 6 +- .../Source/GameSession/CrewManager.cs | 247 ++---------- .../Source/Items/Components/Machines/Sonar.cs | 236 ++++++++---- .../Items/Components/Machines/Steering.cs | 281 +++++++++++--- .../BarotraumaClient/Source/Map/Map/Map.cs | 4 +- .../Source/Screens/CampaignSetupUI.cs | 2 + .../BarotraumaShared/SharedContent.projitems | 3 + .../Components/Machines/Deconstructor.cs | 19 + .../Source/Items/Components/Machines/Sonar.cs | 53 ++- .../Items/Components/Machines/Steering.cs | 353 +----------------- .../BarotraumaShared/Source/Items/Item.cs | 61 ++- .../BarotraumaShared/Source/Map/Hull.cs | 19 + .../Source/Map/Map/LocationTypeChange.cs | 4 + .../BarotraumaShared/Source/Map/Submarine.cs | 8 +- .../BarotraumaShared/Source/PlayerInput.cs | 15 + .../Source/Utils/MathUtils.cs | 12 + 18 files changed, 594 insertions(+), 814 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs index fa30d8a82..8f9276859 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs @@ -121,90 +121,7 @@ namespace Barotrauma MainLimb.PullJointWorldAnchorB = Collider.SimPosition; MainLimb.PullJointEnabled = true; } - character.SelectedConstruction = character.MemState[0].SelectedItem; } - - if (character.MemState[0].Animation == AnimController.Animation.CPR) - { - character.AnimController.Anim = AnimController.Animation.CPR; - } - else if (character.AnimController.Anim == AnimController.Animation.CPR) - { - character.AnimController.Anim = AnimController.Animation.None; - } - - Vector2 newVelocity = Collider.LinearVelocity; - Vector2 newPosition = Collider.SimPosition; - float newRotation = Collider.Rotation; - float newAngularVelocity = Collider.AngularVelocity; - Collider.CorrectPosition(character.MemState, out newPosition, out newVelocity, out newRotation, out newAngularVelocity); - - newVelocity = newVelocity.ClampLength(100.0f); - if (!MathUtils.IsValid(newVelocity)) { newVelocity = Vector2.Zero; } - overrideTargetMovement = newVelocity.LengthSquared() > 0.01f ? newVelocity : Vector2.Zero; - - Collider.LinearVelocity = newVelocity; - Collider.AngularVelocity = newAngularVelocity; - - float distSqrd = Vector2.DistanceSquared(newPosition, Collider.SimPosition); - float errorTolerance = character.AllowInput ? 0.01f : 0.2f; - if (distSqrd > errorTolerance) - { - if (distSqrd > 10.0f || !character.AllowInput) - { - Collider.TargetRotation = newRotation; - SetPosition(newPosition, lerp: distSqrd < 5.0f, ignorePlatforms: false); - } - else - { - Collider.TargetRotation = newRotation; - Collider.TargetPosition = newPosition; - Collider.MoveToTargetPosition(true); - } - } - - //unconscious/dead characters can't correct their position using AnimController movement - // -> we need to correct it manually - if (!character.AllowInput) - { - float mainLimbDistSqrd = Vector2.DistanceSquared(MainLimb.PullJointWorldAnchorA, Collider.SimPosition); - float mainLimbErrorTolerance = 0.1f; - //if the main limb is roughly at the correct position and the collider isn't moving (much at least), - //don't attempt to correct the position. - if (mainLimbDistSqrd > mainLimbErrorTolerance || Collider.LinearVelocity.LengthSquared() > 0.05f) - { - MainLimb.PullJointWorldAnchorB = Collider.SimPosition; - MainLimb.PullJointEnabled = true; - } - } - } - character.MemLocalState.Clear(); - } - else - { - //remove states with a timestamp (there may still timestamp-based states - //in the list if the controlled character switches from timestamp-based interpolation to ID-based) - character.MemState.RemoveAll(m => m.Timestamp > 0.0f); - - for (int i = 0; i < character.MemLocalState.Count; i++) - { - if (character.Submarine == null) - { - //transform in-sub coordinates to outside coordinates - if (character.MemLocalState[i].Position.Y > lowestSubPos) - { - character.MemLocalState[i].TransformInToOutside(); - } - } - else if (currentHull?.Submarine != null) - { - //transform outside coordinates to in-sub coordinates - if (character.MemLocalState[i].Position.Y < lowestSubPos) - { - character.MemLocalState[i].TransformOutToInside(currentHull.Submarine); - } - } - } character.MemLocalState.Clear(); } diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUIComponent.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUIComponent.cs index 1c546467b..e49bb3810 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUIComponent.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUIComponent.cs @@ -128,7 +128,7 @@ namespace Barotrauma protected Color flashColor; protected float flashDuration = 1.5f; private bool useRectangleFlash; - public float FlashTimer + public virtual float FlashTimer { get { return flashTimer; } } diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUIImage.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUIImage.cs index d4f13ecad..27743748b 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUIImage.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUIImage.cs @@ -108,18 +108,18 @@ namespace Barotrauma { float scale = Math.Min(Rect.Width / uiSprite.Sprite.size.X, Rect.Height / uiSprite.Sprite.size.Y); spriteBatch.Draw(uiSprite.Sprite.Texture, Rect.Center.ToVector2(), uiSprite.Sprite.SourceRect, currColor * (currColor.A / 255.0f), Rotation, uiSprite.Sprite.size / 2, - Scale * scale, SpriteEffects.None, 0.0f); + Scale * scale, SpriteEffects, 0.0f); } else { - uiSprite.Draw(spriteBatch, Rect, currColor * (currColor.A / 255.0f), SpriteEffects.None); + uiSprite.Draw(spriteBatch, Rect, currColor * (currColor.A / 255.0f), SpriteEffects); } } } else if (sprite?.Texture != null) { spriteBatch.Draw(sprite.Texture, Rect.Center.ToVector2(), sourceRect, currColor * (currColor.A / 255.0f), Rotation, sprite.size / 2, - Scale, SpriteEffects.None, 0.0f); + Scale, SpriteEffects, 0.0f); } } diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs b/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs index c888d06cd..5300dbd54 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs @@ -74,17 +74,12 @@ namespace Barotrauma public CrewManager(XElement element, bool isSinglePlayer) : this(isSinglePlayer) { - if (GameMain.Client != null) + if (!isSinglePlayer) { - //let the server create random conversations in MP + DebugConsole.ThrowError("Cannot add messages to single player chat box in multiplayer mode!\n" + Environment.StackTrace); return; } - List availableSpeakers = Character.CharacterList.FindAll(c => - c.AIController is HumanAIController && - !c.IsDead && - c.SpeechImpediment <= 100.0f); - pendingConversationLines.AddRange(NPCConversation.CreateRandom(availableSpeakers)); - } + if (string.IsNullOrEmpty(text)) { return; } var characterInfo = new CharacterInfo(subElement); characterInfos.Add(characterInfo); @@ -95,6 +90,7 @@ namespace Barotrauma break; } } + ChatBox.AddMessage(ChatMessage.Create(senderName, text, messageType, sender)); } partial void InitProjectSpecific() @@ -242,24 +238,27 @@ namespace Barotrauma public IEnumerable GetCharacters() { - if (characterInfos.Contains(characterInfo)) - { - DebugConsole.ThrowError("Tried to add the same character info to CrewManager twice.\n" + Environment.StackTrace); - return; - } + if (character?.Inventory == null) return null; - characterInfos.Add(characterInfo); + var radioItem = character.Inventory.Items.FirstOrDefault(it => it != null && it.GetComponent() != null); + if (radioItem == null) return null; + if (requireEquipped && !character.HasEquippedItem(radioItem)) return null; + + return radioItem.GetComponent(); } public IEnumerable GetCharacterInfos() { - if (character == null) + if (GameMain.Client != null) { - DebugConsole.ThrowError("Tried to remove a null character from CrewManager.\n" + Environment.StackTrace); + //let the server create random conversations in MP return; } - characters.Remove(character); - if (removeInfo) characterInfos.Remove(character.Info); + List availableSpeakers = Character.CharacterList.FindAll(c => + c.AIController is HumanAIController && + !c.IsDead && + c.SpeechImpediment <= 100.0f); + pendingConversationLines.AddRange(NPCConversation.CreateRandom(availableSpeakers)); } public void AddCharacter(Character character) @@ -633,183 +632,9 @@ namespace Barotrauma { characterListBox.BarScroll = roundedPos; } - var characterArea = new GUIButton(new RectTransform(new Point(characterInfoWidth, frame.Rect.Height), frame.RectTransform, Anchor.CenterLeft), style: "GUITextBox") - { - UserData = character, - Color = frame.Color, - SelectedColor = frame.SelectedColor, - HoverColor = frame.HoverColor, - ToolTip = characterToolTip - }; - - var soundIcon = new GUIImage(new RectTransform(new Point((int)(characterArea.Rect.Height * 0.5f)), characterArea.RectTransform, Anchor.CenterRight) { AbsoluteOffset = new Point(5, 0) }, - "GUISoundIcon") - { - UserData = "soundicon", - CanBeFocused = false, - Visible = true - }; - soundIcon.Color = new Color(soundIcon.Color, 0.0f); - new GUIImage(new RectTransform(new Point((int)(characterArea.Rect.Height * 0.5f)), characterArea.RectTransform, Anchor.CenterRight) { AbsoluteOffset = new Point(5, 0) }, - "GUISoundIconDisabled") - { - UserData = "soundicondisabled", - CanBeFocused = true, - Visible = false - }; - - if (isSinglePlayer) - { - characterArea.OnClicked = CharacterClicked; - } - else - { - characterArea.CanBeFocused = false; - characterArea.CanBeSelected = false; - } - - var characterImage = new GUICustomComponent(new RectTransform(new Point(characterArea.Rect.Height), characterArea.RectTransform, Anchor.CenterLeft), - onDraw: (sb, component) => character.Info.DrawIcon(sb, component.Rect.Center.ToVector2(), targetAreaSize: component.Rect.Size.ToVector2())) - { - CanBeFocused = false, - HoverColor = Color.White, - SelectedColor = Color.White, - ToolTip = characterToolTip - }; - - var characterName = new GUITextBlock(new RectTransform(new Point(characterArea.Rect.Width - characterImage.Rect.Width - soundIcon.Rect.Width - 10, characterArea.Rect.Height), - characterArea.RectTransform, Anchor.CenterRight) { AbsoluteOffset = new Point(soundIcon.Rect.Width + 10, 0) }, - character.Name, textColor: frame.Color, font: GUI.SmallFont, wrap: true) - { - Color = frame.Color, - HoverColor = Color.Transparent, - SelectedColor = Color.Transparent, - CanBeFocused = false, - ToolTip = characterToolTip, - AutoScale = true - }; - - //---------------- order buttons ---------------- - - var orderButtonFrame = new GUILayoutGroup(new RectTransform(new Point(100, frame.Rect.Height), frame.RectTransform) - { AbsoluteOffset = new Point(characterInfoWidth + spacing, 0) }, - isHorizontal: true, childAnchor: Anchor.CenterLeft) - { - AbsoluteSpacing = (int)(10 * GUI.Scale), - UserData = "orderbuttons", - CanBeFocused = false - }; - - //listbox for holding the orders inappropriate for this character - //(so we can easily toggle their visibility) - var wrongOrderList = new GUIListBox(new RectTransform(new Point(50, orderButtonFrame.Rect.Height), orderButtonFrame.RectTransform), isHorizontal: true, style: null) - { - ScrollBarEnabled = false, - ScrollBarVisible = false, - Enabled = false, - Spacing = spacing, - ClampMouseRectToParent = false - }; - wrongOrderList.Content.ClampMouseRectToParent = false; - - for (int i = 0; i < orders.Count; i++) - { - var order = orders[i]; - if (order.TargetAllCharacters) continue; - - RectTransform btnParent = (i >= correctOrderCount + neutralOrderCount) ? - wrongOrderList.Content.RectTransform : - orderButtonFrame.RectTransform; - - var btn = new GUIButton(new RectTransform(new Point(iconSize, iconSize), btnParent, Anchor.CenterLeft), - style: null) - { - UserData = order - }; - - new GUIFrame(new RectTransform(new Vector2(1.5f), btn.RectTransform, Anchor.Center), "OuterGlow") - { - Color = Color.Lerp(order.Color, frame.Color, 0.5f) * 0.8f, - HoverColor = Color.Lerp(order.Color, frame.Color, 0.5f) * 1.0f, - PressedColor = Color.Lerp(order.Color, frame.Color, 0.5f) * 0.6f, - UserData = "selected", - CanBeFocused = false, - Visible = false - }; - - var img = new GUIImage(new RectTransform(Vector2.One, btn.RectTransform), order.Prefab.SymbolSprite); - img.Scale = iconSize / (float)img.SourceRect.Width; - img.Color = Color.Lerp(order.Color, frame.Color, 0.5f); - img.ToolTip = order.Name; - img.HoverColor = Color.Lerp(img.Color, Color.White, 0.5f); - - btn.OnClicked += (GUIButton button, object userData) => - { - if (Character.Controlled == null || Character.Controlled.SpeechImpediment >= 100.0f) return false; - - if (btn.GetChildByUserData("selected").Visible) - { - SetCharacterOrder(character, Order.PrefabList.Find(o => o.AITag == "dismissed"), null, Character.Controlled); - } - else - { - if (order.ItemComponentType != null || order.ItemIdentifiers.Length > 0 || order.Options.Length > 1) - { - CreateOrderTargetFrame(button, character, order); - } - else - { - SetCharacterOrder(character, order, null, Character.Controlled); - } - } - return true; - }; - btn.UserData = order; - btn.ToolTip = order.Name; - - //divider between different groups of orders - if (i == correctOrderCount - 1 || i == correctOrderCount + neutralOrderCount - 1) - { - //TODO: divider sprite - new GUIFrame(new RectTransform(new Point(8, iconSize), orderButtonFrame.RectTransform), style: "GUIButton"); - } - } - - var toggleWrongOrderBtn = new GUIButton(new RectTransform(new Point((int)(30 * GUI.Scale), wrongOrderList.Rect.Height), wrongOrderList.Content.RectTransform), - "", style: "UIToggleButton") - { - UserData = "togglewrongorder", - CanBeFocused = false - }; - - wrongOrderList.RectTransform.NonScaledSize = new Point( - wrongOrderList.Content.Children.Sum(c => c.Rect.Width + wrongOrderList.Spacing), - wrongOrderList.RectTransform.NonScaledSize.Y); - wrongOrderList.RectTransform.SetAsLastChild(); - - new GUIFrame(new RectTransform(new Point( - wrongOrderList.Rect.Width - toggleWrongOrderBtn.Rect.Width - wrongOrderList.Spacing * 2, - wrongOrderList.Rect.Height), wrongOrderList.Content.RectTransform), - style: null) - { - CanBeFocused = false - }; - - //scale to fit the content - orderButtonFrame.RectTransform.NonScaledSize = new Point( - orderButtonFrame.Children.Sum(c => c.Rect.Width + orderButtonFrame.AbsoluteSpacing), - orderButtonFrame.RectTransform.NonScaledSize.Y); - - frame.RectTransform.NonScaledSize = new Point( - characterInfoWidth + spacing + (orderButtonFrame.Rect.Width - wrongOrderList.Rect.Width), - frame.RectTransform.NonScaledSize.Y); - - characterListBox.RectTransform.NonScaledSize = new Point( - characterListBox.Content.Children.Max(c => c.Rect.Width) + wrongOrderList.Rect.Width, - characterListBox.RectTransform.NonScaledSize.Y); - characterListBox.Content.RectTransform.NonScaledSize = characterListBox.RectTransform.NonScaledSize; - characterListBox.UpdateScrollBarSize(); - return frame; + soundIcon.Visible = !muted && !mutedLocally; + soundIconDisabled.Visible = muted || mutedLocally; + soundIconDisabled.ToolTip = TextManager.Get(mutedLocally ? "MutedLocally" : "MutedGlobally"); } private IEnumerable KillCharacterAnim(GUIComponent component) @@ -953,12 +778,6 @@ namespace Barotrauma } return; } - List availableSpeakers = Character.CharacterList.FindAll(c => - c.AIController is HumanAIController && - !c.IsDead && - c.SpeechImpediment <= 100.0f); - pendingConversationLines.AddRange(NPCConversation.CreateRandom(availableSpeakers)); - } character.SetOrder(order, option, orderGiver, speak: orderGiver != character); if (IsSinglePlayer) @@ -1016,23 +835,19 @@ namespace Barotrauma } } } - - character.SetOrder(order, option, orderGiver, speak: orderGiver != character); - if (IsSinglePlayer) + //only one target (or an order with no particular targets), just show options + else { - orderGiver?.Speak( - order.GetChatMessage(character.Name, orderGiver.CurrentHull?.DisplayName, givingOrderToSelf: character == orderGiver, orderOption: option), null); - } - else if (orderGiver != null) - { - OrderChatMessage msg = new OrderChatMessage(order, option, order.TargetItemComponent?.Item, character, orderGiver); - if (GameMain.Client != null) + orderTargetFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.2f + order.Options.Length * 0.1f, 0.18f), GUI.Canvas) + { AbsoluteOffset = new Point(orderButton.Rect.Center.X, orderButton.Rect.Bottom) }, + isHorizontal: true, childAnchor: Anchor.BottomLeft) { - GameMain.Client.SendChatMessage(msg); - } - } - DisplayCharacterOrder(character, order); - } + UserData = character, + Stretch = true + }; + //line connecting the order button to the option buttons + //TODO: sprite + new GUIFrame(new RectTransform(new Vector2(0.5f, 1.0f), orderTargetFrame.RectTransform), style: null); /// /// Create the UI panel that's used to select the target and options for a given order diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Sonar.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Sonar.cs index 0c7c9c058..aaa57c4af 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Sonar.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Sonar.cs @@ -64,6 +64,8 @@ namespace Barotrauma.Items.Components new Color(255, 255, 255) }; + private float prevDockingDist; + public Vector2 DisplayOffset { get; private set; } public float DisplayRadius { get; private set; } @@ -171,6 +173,31 @@ namespace Barotrauma.Items.Components sonarMode.Selected = Mode.Passive; GuiFrame.CanBeFocused = false; + + foreach (XElement subElement in element.Elements()) + { + switch (subElement.Name.ToString().ToLowerInvariant()) + { + case "pingcircle": + pingCircle = new Sprite(subElement); + break; + case "directionalpingcircle": + directionalPingCircle = new Sprite(subElement); + break; + case "screenoverlay": + screenOverlay = new Sprite(subElement); + break; + case "screenbackground": + screenBackground = new Sprite(subElement); + break; + case "blip": + sonarBlip = new Sprite(subElement); + break; + case "linesprite": + lineSprite = new Sprite(subElement); + break; + } + } } public override void OnItemLoaded() @@ -235,8 +262,7 @@ namespace Barotrauma.Items.Components return; } - Vector2 transducerCenter = UseTransducers ? GetTransducerCenter() : item.WorldPosition; - transducerCenter += DisplayOffset; + Vector2 transducerCenter = GetTransducerPos() + DisplayOffset; if (Level.Loaded != null) { @@ -285,8 +311,31 @@ namespace Barotrauma.Items.Components sonarBlips.Add(flowBlip); } } - } - + } + + Steering steering = item.GetComponent(); + if (steering != null && steering.DockingModeEnabled) + { + float dockingDist = Vector2.Distance(steering.DockingSource.Item.WorldPosition, steering.DockingTarget.Item.WorldPosition); + if (prevDockingDist > steering.DockingAssistThreshold && dockingDist <= steering.DockingAssistThreshold) + { + zoom = Math.Max(zoom, MathHelper.Lerp(MinZoom, MaxZoom, 0.25f)); + } + else if (prevDockingDist > steering.DockingAssistThreshold * 0.75f && dockingDist <= steering.DockingAssistThreshold * 0.75f) + { + zoom = Math.Max(zoom, MathHelper.Lerp(MinZoom, MaxZoom, 0.5f)); + } + else if (prevDockingDist > steering.DockingAssistThreshold * 0.5f && dockingDist <= steering.DockingAssistThreshold * 0.5f) + { + zoom = Math.Max(zoom, MathHelper.Lerp(MinZoom, MaxZoom, 0.25f)); + } + prevDockingDist = Math.Min(dockingDist, prevDockingDist); + } + else + { + prevDockingDist = float.MaxValue; + } + if (IsActive) { float pingRadius = DisplayRadius * pingState / zoom; @@ -357,7 +406,7 @@ namespace Barotrauma.Items.Components } } - Vector2 transducerCenter = UseTransducers && connectedTransducers.Count > 0 ? GetTransducerCenter() : item.WorldPosition; + Vector2 transducerCenter = GetTransducerPos(); if (item.Submarine != null && !DetectSubmarineWalls) { @@ -370,7 +419,6 @@ namespace Barotrauma.Items.Components DisplayOffset = Vector2.Zero; } - if (sonarBlips.Count > 0) { zoomSqrt = (float)Math.Sqrt(zoom); @@ -391,8 +439,8 @@ namespace Barotrauma.Items.Components { Vector2 sector1 = MathUtils.RotatePointAroundTarget(pingDirection * DisplayRadius, Vector2.Zero, DirectionalPingSector * 0.5f); Vector2 sector2 = MathUtils.RotatePointAroundTarget(pingDirection * DisplayRadius, Vector2.Zero, -DirectionalPingSector * 0.5f); - GUI.DrawLine(spriteBatch, center, center + sector1, Color.LightCyan * 0.2f * directionalPingVisibility, width: 3); - GUI.DrawLine(spriteBatch, center, center + sector2, Color.LightCyan * 0.2f * directionalPingVisibility, width: 3); + DrawLine(spriteBatch, center, center + sector1, Color.LightCyan * 0.2f * directionalPingVisibility, width: 3); + DrawLine(spriteBatch, center, center + sector2, Color.LightCyan * 0.2f * directionalPingVisibility, width: 3); } if (GameMain.DebugDraw) @@ -495,7 +543,7 @@ namespace Barotrauma.Items.Components Vector2 end = (submarine.HullVertices[(i + 1) % submarine.HullVertices.Count] + offset) * simScale; end.Y = -end.Y; - DrawLine(spriteBatch, start, end, Color.LightBlue * signalStrength * 0.5f, width: 3); + DrawLine(spriteBatch, start, end, Color.LightBlue * signalStrength * 0.5f, width: 4); } } } @@ -512,22 +560,38 @@ namespace Barotrauma.Items.Components { if (MathUtils.GetLineCircleIntersections(Vector2.Zero, DisplayRadius, end, start, true, out Vector2? intersection1, out Vector2? intersection2) == 1) { - GUI.DrawLine(spriteBatch, center + intersection1.Value, center + end, color, width: width); + DrawLineSprite(spriteBatch, center + intersection1.Value, center + end, color, width: width); } } else if (endOutside) { if (MathUtils.GetLineCircleIntersections(Vector2.Zero, DisplayRadius, start, end, true, out Vector2? intersection1, out Vector2? intersection2) == 1) { - GUI.DrawLine(spriteBatch, center + start, center + intersection1.Value, color, width: width); + DrawLineSprite(spriteBatch, center + start, center + intersection1.Value, color, width: width); } } else { - GUI.DrawLine(spriteBatch, center + start, center + end, color, width: width); + DrawLineSprite(spriteBatch, center + start, center + end, color, width: width); } } + private void DrawLineSprite(SpriteBatch spriteBatch, Vector2 start, Vector2 end, Color color, int width) + { + if (lineSprite == null) + { + GUI.DrawLine(spriteBatch, start, end, color, width: width); + } + else + { + Vector2 dir = end - start; + float angle = (float)Math.Atan2(dir.Y, dir.X); + lineSprite.Draw(spriteBatch, start, color, origin: lineSprite.Origin, rotate: angle, + scale: new Vector2(dir.Length() / lineSprite.size.X, 1.0f)); + } + } + + private void DrawDockingPorts(SpriteBatch spriteBatch, Vector2 transducerCenter, float signalStrength) { float scale = displayScale * zoom; @@ -535,61 +599,12 @@ namespace Barotrauma.Items.Components Steering steering = item.GetComponent(); if (steering != null && steering.DockingModeEnabled) { - DisplayOffset = - Vector2.Lerp(DisplayOffset, - (steering.DockingSource.Item.WorldPosition + steering.DockingTarget.Item.WorldPosition) / 2.0f - transducerCenter, - 0.1f); - transducerCenter += DisplayOffset; - - Vector2 sourcePortDiff = (steering.DockingSource.Item.WorldPosition - transducerCenter) * scale; - Vector2 sourcePortPos = new Vector2(sourcePortDiff.X, -sourcePortDiff.Y); - Vector2 targetPortDiff = (steering.DockingTarget.Item.WorldPosition - transducerCenter) * scale; - Vector2 targetPortPos = new Vector2(targetPortDiff.X, -targetPortDiff.Y); - - Vector2 midPos = (sourcePortPos + targetPortPos) / 2.0f; - - System.Diagnostics.Debug.Assert(steering.DockingSource.IsHorizontal == steering.DockingTarget.IsHorizontal); - - float xDist = Math.Abs(steering.DockingSource.Item.WorldPosition.X - steering.DockingTarget.Item.WorldPosition.X); - float normalizedXDist = xDist / steering.DockingSource.DistanceTolerance.X; - float yDist = Math.Abs(steering.DockingSource.Item.WorldPosition.Y - steering.DockingTarget.Item.WorldPosition.Y); - float normalizedYDist = yDist / steering.DockingSource.DistanceTolerance.Y; - - Color xColor = normalizedXDist <= 1.0f ? Color.Lime : Color.Lerp(Color.Orange, Color.Red, normalizedXDist - 1.0f); - Color yColor = normalizedYDist <= 1.0f ? Color.Lime : Color.Lerp(Color.Orange, Color.Red, normalizedYDist - 1.0f); - - if (steering.DockingSource.IsHorizontal) - { - if (yDist < steering.DockingSource.DistanceTolerance.Y) - { - DrawLine(spriteBatch, sourcePortPos, new Vector2(targetPortPos.X, sourcePortPos.Y), xColor, width: 3); - } - else - { - DrawLine(spriteBatch, sourcePortPos, new Vector2(midPos.X, sourcePortPos.Y), xColor, width: 3); - DrawLine(spriteBatch, targetPortPos, new Vector2(midPos.X, targetPortPos.Y), xColor, width: 3); - DrawLine(spriteBatch, new Vector2(midPos.X, sourcePortPos.Y), new Vector2(midPos.X, targetPortPos.Y), yColor, width: 3); - } - } - else - { - if (xDist < steering.DockingSource.DistanceTolerance.X) - { - DrawLine(spriteBatch, sourcePortPos, new Vector2(sourcePortPos.X, targetPortPos.Y), yColor, width: 3); - } - else - { - DrawLine(spriteBatch, sourcePortPos, new Vector2(sourcePortPos.X, midPos.Y), yColor, width: 3); - DrawLine(spriteBatch, targetPortPos, new Vector2(targetPortPos.X, midPos.Y), yColor, width: 3); - DrawLine(spriteBatch, new Vector2(sourcePortPos.X, midPos.Y), new Vector2(targetPortPos.X, midPos.Y), xColor, width: 3); - } - } + DrawDockingIndicator(spriteBatch, steering, ref transducerCenter); } else { DisplayOffset = Vector2.Lerp(DisplayOffset, Vector2.Zero, 0.1f); - } - + } foreach (DockingPort dockingPort in DockingPort.List) { @@ -608,9 +623,102 @@ namespace Barotrauma.Items.Components { size.Y = 0.0f; } - GUI.DrawLine(spriteBatch, center + offset - size / 2, center + offset + size / 2, Color.LightGreen, width: (int)(zoom)); + GUI.DrawLine(spriteBatch, center + offset - size, center + offset + size, Color.LightGreen, width: (int)(zoom * 2.5f)); + } + } + + private void DrawDockingIndicator(SpriteBatch spriteBatch, Steering steering, ref Vector2 transducerCenter) + { + float scale = displayScale * zoom; + + Vector2 worldFocusPos = (steering.DockingSource.Item.WorldPosition + steering.DockingTarget.Item.WorldPosition) / 2.0f; + worldFocusPos.X = steering.DockingTarget.Item.WorldPosition.X; + + DisplayOffset = Vector2.Lerp(DisplayOffset, worldFocusPos - transducerCenter, 0.1f); + transducerCenter += DisplayOffset; + + Vector2 sourcePortDiff = (steering.DockingSource.Item.WorldPosition - transducerCenter) * scale; + Vector2 sourcePortPos = new Vector2(sourcePortDiff.X, -sourcePortDiff.Y); + Vector2 targetPortDiff = (steering.DockingTarget.Item.WorldPosition - transducerCenter) * scale; + Vector2 targetPortPos = new Vector2(targetPortDiff.X, -targetPortDiff.Y); + + Vector2 midPos = (sourcePortPos + targetPortPos) / 2.0f; + + System.Diagnostics.Debug.Assert(steering.DockingSource.IsHorizontal == steering.DockingTarget.IsHorizontal); + Vector2 diff = steering.DockingTarget.Item.WorldPosition - steering.DockingSource.Item.WorldPosition; + float dist = diff.Length(); + bool readyToDock = + Math.Abs(diff.X) < steering.DockingTarget.DistanceTolerance.X && + Math.Abs(diff.Y) < steering.DockingTarget.DistanceTolerance.Y; + + Vector2 dockingDir = sourcePortPos - targetPortPos; + Vector2 normalizedDockingDir = Vector2.Normalize(dockingDir); + if (!DynamicDockingIndicator) + { + if (steering.DockingSource.IsHorizontal) + { + normalizedDockingDir = new Vector2(Math.Sign(normalizedDockingDir.X), 0.0f); + } + else + { + normalizedDockingDir = new Vector2(0.0f, Math.Sign(normalizedDockingDir.Y)); + } } + Color staticLineColor = Color.White * 0.2f; + + float sector = MathHelper.ToRadians(MathHelper.Lerp(10.0f, 45.0f, MathHelper.Clamp(dist / steering.DockingAssistThreshold, 0.0f, 1.0f))); + float sectorLength = DisplayRadius; + //use law of cosines to calculate the length of the center line + float midLength = (float)(Math.Cos(sector) * sectorLength); + + Vector2 midNormal = new Vector2(-normalizedDockingDir.Y, normalizedDockingDir.X); + + DrawLine(spriteBatch, targetPortPos, targetPortPos + normalizedDockingDir * midLength, readyToDock ? Color.LightGreen : staticLineColor, width: 2); + DrawLine(spriteBatch, targetPortPos, + targetPortPos + MathUtils.RotatePoint(normalizedDockingDir, sector) * sectorLength, staticLineColor, width: 2); + DrawLine(spriteBatch, targetPortPos, + targetPortPos + MathUtils.RotatePoint(normalizedDockingDir, -sector) * sectorLength, staticLineColor, width: 2); + + for (float z = 0; z < 1.0f; z += 0.1f * zoom) + { + Vector2 linePos = targetPortPos + normalizedDockingDir * midLength * z; + DrawLine(spriteBatch, linePos + midNormal * 3.0f, linePos - midNormal * 3.0f, staticLineColor, width: 3); + } + + if (readyToDock) + { + Color indicatorColor = Color.LightGreen * 0.8f; + + float indicatorSize = (float)Math.Sin((float)Timing.TotalTime * 5.0f) * DisplayRadius * 0.75f; + Vector2 midPoint = (sourcePortPos + targetPortPos) / 2.0f; + DrawLine(spriteBatch, + midPoint + Vector2.UnitY * indicatorSize, + midPoint - Vector2.UnitY * indicatorSize, + indicatorColor, width: 3); + DrawLine(spriteBatch, + midPoint + Vector2.UnitX * indicatorSize, + midPoint - Vector2.UnitX * indicatorSize, + indicatorColor, width: 3); + } + else + { + float indicatorSector = sector * 0.75f; + float indicatorSectorLength = (float)(midLength / Math.Cos(indicatorSector)); + + bool withinSector = + (Math.Abs(diff.X) < steering.DockingSource.DistanceTolerance.X && Math.Abs(diff.Y) < steering.DockingSource.DistanceTolerance.Y) || + Vector2.Dot(normalizedDockingDir, MathUtils.RotatePoint(normalizedDockingDir, indicatorSector)) < + Vector2.Dot(normalizedDockingDir, Vector2.Normalize(dockingDir)); + + Color indicatorColor = withinSector ? Color.LightGreen * 0.8f : Color.Red * 0.8f; + + DrawLine(spriteBatch, targetPortPos, + targetPortPos + MathUtils.RotatePoint(normalizedDockingDir,indicatorSector) * indicatorSectorLength, indicatorColor, width: 3); + DrawLine(spriteBatch, targetPortPos, + targetPortPos + MathUtils.RotatePoint(normalizedDockingDir, -indicatorSector) * indicatorSectorLength, indicatorColor, width: 3); + } + } private void UpdateDisruptions(Vector2 pingSource, float worldPingRadius, float worldPrevPingRadius) diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Steering.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Steering.cs index 723b7c70f..9c9afcbbb 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Steering.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Steering.cs @@ -4,7 +4,9 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Graphics; using System; +using System.Linq; using System.Collections.Generic; +using System.Xml.Linq; namespace Barotrauma.Items.Components { @@ -25,6 +27,11 @@ namespace Barotrauma.Items.Components }; private GUITickBox maintainPosTickBox, levelEndTickBox, levelStartTickBox; + private GUIComponent statusContainer, dockingContainer; + + private GUIButton dockingButton; + private string dockText, undockText; + private GUIFrame autoPilotControlsDisabler; private GUIComponent steerArea; @@ -35,6 +42,9 @@ namespace Barotrauma.Items.Components private string noPowerTip, autoPilotMaintainPosTip, autoPilotLevelStartTip, autoPilotLevelEndTip; + private Sprite maintainPosIndicator, maintainPosOriginIndicator; + private Sprite steeringIndicator; + private Vector2 keyboardInput = Vector2.Zero; private float inputCumulation; @@ -66,10 +76,12 @@ namespace Barotrauma.Items.Components get; set; } - + public DockingPort DockingSource, DockingTarget; - partial void InitProjSpecific() + private bool searchedConnectedDockingPort; + + partial void InitProjSpecific(XElement element) { int viewSize = (int)Math.Min(GuiFrame.Rect.Width - 150, GuiFrame.Rect.Height * 0.9f); var controlContainer = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.35f), GuiFrame.RectTransform, Anchor.CenterLeft) @@ -80,7 +92,7 @@ namespace Barotrauma.Items.Components Stretch = true }; - var statusContainer = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.25f), GuiFrame.RectTransform, Anchor.BottomLeft) + statusContainer = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.25f), GuiFrame.RectTransform, Anchor.BottomLeft) { MinSize = new Point(150, 0), AbsoluteOffset = new Point((int)(viewSize * 0.9f), 0) }, "SonarFrame"); var paddedStatusContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), statusContainer.RectTransform, Anchor.Center)) { @@ -121,7 +133,9 @@ namespace Barotrauma.Items.Components AutoPilot = box.Selected; if (AutoPilot && MaintainPos) { - posToMaintain = controlledSub == null ? item.WorldPosition : controlledSub.WorldPosition; + posToMaintain = controlledSub != null ? + controlledSub.WorldPosition : + item.Submarine == null ? item.WorldPosition : item.Submarine.WorldPosition; } unsentChanges = true; user = Character.Controlled; @@ -292,6 +306,80 @@ namespace Barotrauma.Items.Components steerArea = new GUICustomComponent(new RectTransform(new Point(viewSize), GuiFrame.RectTransform, Anchor.CenterLeft), (spriteBatch, guiCustomComponent) => { DrawHUD(spriteBatch, guiCustomComponent.Rect); }, null); + + //docking interface ---------------------------------------------------- + dockingContainer = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.25f), GuiFrame.RectTransform, Anchor.BottomLeft) + { MinSize = new Point(150, 0), AbsoluteOffset = new Point((int)(viewSize * 0.9f), 0) }, style: null); + var paddedDockingContainer = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), dockingContainer.RectTransform, Anchor.Center), style: null); + + //TODO: add new texts for these ("Dock" & "Undock") + dockText = TextManager.Get("captain.dock"); + undockText = TextManager.Get("captain.undock"); + dockingButton = new GUIButton(new RectTransform(new Vector2(0.5f, 0.5f), paddedDockingContainer.RectTransform, Anchor.Center), dockText, style: "GUIButtonLarge") + { + OnClicked = (btn, userdata) => + { + item.SendSignal(0, "1", "toggle_docking", sender: Character.Controlled); + return true; + } + }; + dockingButton.Font = GUI.SmallFont; + + var leftButton = new GUIButton(new RectTransform(new Vector2(0.2f, 0.5f), paddedDockingContainer.RectTransform, Anchor.CenterLeft), "") + { + OnClicked = NudgeButtonClicked, + UserData = -Vector2.UnitX + }; + new GUIImage(new RectTransform(new Vector2(0.7f), leftButton.RectTransform, Anchor.Center), "GUIButtonHorizontalArrow").SpriteEffects = SpriteEffects.FlipHorizontally; + var rightButton = new GUIButton(new RectTransform(new Vector2(0.2f, 0.5f), paddedDockingContainer.RectTransform, Anchor.CenterRight), "") + { + OnClicked = NudgeButtonClicked, + UserData = Vector2.UnitX + }; + new GUIImage(new RectTransform(new Vector2(0.7f), rightButton.RectTransform, Anchor.Center), "GUIButtonHorizontalArrow"); + var upButton = new GUIButton(new RectTransform(new Vector2(0.5f, 0.2f), paddedDockingContainer.RectTransform, Anchor.TopCenter), "") + { + OnClicked = NudgeButtonClicked, + UserData = Vector2.UnitY + }; + new GUIImage(new RectTransform(new Vector2(0.7f), upButton.RectTransform, Anchor.Center), "GUIButtonVerticalArrow"); + var downButton = new GUIButton(new RectTransform(new Vector2(0.5f, 0.2f), paddedDockingContainer.RectTransform, Anchor.BottomCenter), "") + { + OnClicked = NudgeButtonClicked, + UserData = -Vector2.UnitY + }; + new GUIImage(new RectTransform(new Vector2(0.7f), downButton.RectTransform, Anchor.Center), "GUIButtonVerticalArrow").SpriteEffects = SpriteEffects.FlipVertically; + + foreach (XElement subElement in element.Elements()) + { + switch (subElement.Name.ToString().ToLowerInvariant()) + { + case "steeringindicator": + steeringIndicator = new Sprite(subElement); + break; + case "maintainposindicator": + maintainPosIndicator = new Sprite(subElement); + break; + case "maintainposoriginindicator": + maintainPosOriginIndicator = new Sprite(subElement); + break; + } + } + } + + private void FindConnectedDockingPort() + { + DockingSource = + (item.linkedTo.FirstOrDefault(l => l is Item item && item.GetComponent() != null) as Item)?.GetComponent(); + if (DockingSource == null) + { + var dockingConnection = item.Connections.FirstOrDefault(c => c.Name == "toggle_docking"); + if (dockingConnection != null) + { + var connectedPorts = item.GetConnectedComponentsRecursive(dockingConnection); + DockingSource = connectedPorts.Find(p => p.Item.Submarine == item.Submarine); + } + } } /// @@ -303,6 +391,12 @@ namespace Barotrauma.Items.Components sonarView.OnDraw += (spriteBatch, guiCustomComponent) => { DrawHUD(spriteBatch, guiCustomComponent.Rect); }; } + public void DrawHUD(SpriteBatch spriteBatch, Rectangle rect) + { + int width = rect.Width, height = rect.Height; + int x = rect.X; + int y = rect.Y; + public void DrawHUD(SpriteBatch spriteBatch, Rectangle rect) { int width = rect.Width, height = rect.Height; @@ -311,12 +405,12 @@ namespace Barotrauma.Items.Components if (voltage < minVoltage && currPowerConsumption > 0.0f) return; - Rectangle velRect = new Rectangle(x + 20, y + 20, width - 40, height - 40); - GUI.DrawLine(spriteBatch, - new Vector2(velRect.Center.X, velRect.Center.Y), - new Vector2(velRect.Center.X + currVelocity.X, velRect.Center.Y - currVelocity.Y), - Color.Gray); - + Rectangle velRect = new Rectangle(x + 20, y + 20, width - 40, height - 40); + Vector2 displaySubPos = (-sonar.DisplayOffset * sonar.Zoom) / sonar.Range * sonar.DisplayRadius * sonar.Zoom; + displaySubPos.Y = -displaySubPos.Y; + displaySubPos = displaySubPos.ClampLength(velRect.Width / 2); + displaySubPos = steerArea.Rect.Center.ToVector2() + displaySubPos; + if (!AutoPilot) { Vector2 unitSteeringInput = steeringInput / 100.0f; @@ -324,20 +418,24 @@ namespace Barotrauma.Items.Components Vector2 steeringInputPos = new Vector2( steeringInput.X * (float)Math.Sqrt(1.0f - 0.5f * unitSteeringInput.Y * unitSteeringInput.Y), -steeringInput.Y * (float)Math.Sqrt(1.0f - 0.5f * unitSteeringInput.X * unitSteeringInput.X)); - steeringInputPos.X += velRect.Center.X; - steeringInputPos.Y += velRect.Center.Y; + steeringInputPos += displaySubPos; - GUI.DrawLine(spriteBatch, - new Vector2(velRect.Center.X, velRect.Center.Y), - steeringInputPos, - Color.LightGray); + if (steeringIndicator != null) + { + Vector2 dir = steeringInputPos - displaySubPos; + float angle = (float)Math.Atan2(dir.Y, dir.X); + steeringIndicator.Draw(spriteBatch, displaySubPos, Color.White, origin: steeringIndicator.Origin, rotate: angle, + scale: new Vector2(dir.Length() / steeringIndicator.size.X, 1.0f)); + } + else + { + GUI.DrawLine(spriteBatch, displaySubPos, steeringInputPos, Color.LightGray); + GUI.DrawRectangle(spriteBatch, new Rectangle((int)steeringInputPos.X - 5, (int)steeringInputPos.Y - 5, 10, 10), Color.White); + } - GUI.DrawRectangle(spriteBatch, new Rectangle((int)steeringInputPos.X - 5, (int)steeringInputPos.Y - 5, 10, 10), Color.White); - - //if (keyboardInput.Length() > 0 || Vector2.Distance(PlayerInput.MousePosition, new Vector2(velRect.Center.X, velRect.Center.Y)) < 200.0f) if (velRect.Contains(PlayerInput.MousePosition)) { - GUI.DrawRectangle(spriteBatch, new Rectangle((int)steeringInputPos.X - 10, (int)steeringInputPos.Y - 10, 20, 20), Color.Red); + GUI.DrawRectangle(spriteBatch, new Rectangle((int)steeringInputPos.X - 4, (int)steeringInputPos.Y - 4, 8, 8), Color.Red, thickness: 2); } } else if (posToMaintain.HasValue && !LevelStartSelected && !LevelEndSelected) @@ -348,35 +446,53 @@ namespace Barotrauma.Items.Components Vector2 displayPosToMaintain = ((posToMaintain.Value - sonar.DisplayOffset * sonar.Zoom - controlledSub.WorldPosition)) / sonar.Range * sonar.DisplayRadius * sonar.Zoom; displayPosToMaintain.Y = -displayPosToMaintain.Y; displayPosToMaintain = displayPosToMaintain.ClampLength(velRect.Width / 2); - displayPosToMaintain = velRect.Center.ToVector2() + displayPosToMaintain; + displayPosToMaintain = steerArea.Rect.Center.ToVector2() + displayPosToMaintain; - float crossHairSize = 8.0f; Color crosshairColor = Color.Orange * (0.5f + ((float)Math.Sin(Timing.TotalTime * 5.0f) + 1.0f) / 4.0f); + if (maintainPosIndicator != null) + { + maintainPosIndicator.Draw(spriteBatch, displayPosToMaintain, crosshairColor, scale: 0.5f * sonar.Zoom); + } + else + { + float crossHairSize = 8.0f; + GUI.DrawLine(spriteBatch, displayPosToMaintain + Vector2.UnitY * crossHairSize, displayPosToMaintain - Vector2.UnitY * crossHairSize, crosshairColor, width: 3); + GUI.DrawLine(spriteBatch, displayPosToMaintain + Vector2.UnitX * crossHairSize, displayPosToMaintain - Vector2.UnitX * crossHairSize, crosshairColor, width: 3); + } - GUI.DrawLine(spriteBatch, displayPosToMaintain + Vector2.UnitY * crossHairSize, displayPosToMaintain - Vector2.UnitY * crossHairSize, crosshairColor, width: 3); - GUI.DrawLine(spriteBatch, displayPosToMaintain + Vector2.UnitX * crossHairSize, displayPosToMaintain - Vector2.UnitX * crossHairSize, crosshairColor, width: 3); - - Vector2 neutralPos = ((controlledSub.WorldPosition - sonar.DisplayOffset * sonar.Zoom - controlledSub.WorldPosition)) / sonar.Range * sonar.DisplayRadius * sonar.Zoom; - - neutralPos.Y = -neutralPos.Y; - neutralPos = neutralPos.ClampLength(velRect.Width / 2); - neutralPos = velRect.Center.ToVector2() + neutralPos; - GUI.DrawRectangle(spriteBatch, new Rectangle((int)neutralPos.X - 5, (int)neutralPos.Y - 5, 10, 10), Color.Orange); + if (maintainPosOriginIndicator != null) + { + maintainPosOriginIndicator.Draw(spriteBatch, displaySubPos, Color.Orange, scale: 0.5f * sonar.Zoom); + } + else + { + GUI.DrawRectangle(spriteBatch, new Rectangle((int)displaySubPos.X - 5, (int)displaySubPos.Y - 5, 10, 10), Color.Orange); + } } } - + //map velocity from rectangle to circle Vector2 unitTargetVel = targetVelocity / 100.0f; Vector2 steeringPos = new Vector2( targetVelocity.X * 0.9f * (float)Math.Sqrt(1.0f - 0.5f * unitTargetVel.Y * unitTargetVel.Y), -targetVelocity.Y * 0.9f * (float)Math.Sqrt(1.0f - 0.5f * unitTargetVel.X * unitTargetVel.X)); - steeringPos.X += velRect.Center.X; - steeringPos.Y += velRect.Center.Y; + steeringPos += displaySubPos; - GUI.DrawLine(spriteBatch, - new Vector2(velRect.Center.X, velRect.Center.Y), - steeringPos, - Color.CadetBlue, 0, 2); + + if (steeringIndicator != null) + { + Vector2 dir = steeringPos - displaySubPos; + float angle = (float)Math.Atan2(dir.Y, dir.X); + steeringIndicator.Draw(spriteBatch, displaySubPos, Color.Gray, origin: steeringIndicator.Origin, rotate: angle, + scale: new Vector2(dir.Length() / steeringIndicator.size.X, 0.7f)); + } + else + { + GUI.DrawLine(spriteBatch, + displaySubPos, + steeringPos, + Color.CadetBlue, 0, 2); + } } public void DebugDrawHUD(SpriteBatch spriteBatch, Vector2 transducerCenter, float displayScale, float displayRadius, Vector2 center) @@ -433,7 +549,6 @@ namespace Barotrauma.Items.Components Color.Lerp(Color.Green, Color.Orange, obstacle.Dot), width: 2); } } - } public override void UpdateHUD(Character character, float deltaTime, Camera cam) { @@ -446,6 +561,12 @@ namespace Barotrauma.Items.Components } } + if (!searchedConnectedDockingPort) + { + FindConnectedDockingPort(); + searchedConnectedDockingPort = true; + } + if (steerArea.Rect.Contains(PlayerInput.MousePosition)) { if (!PlayerInput.KeyDown(InputType.Deselect) && !PlayerInput.KeyHit(InputType.Deselect)) @@ -454,6 +575,38 @@ namespace Barotrauma.Items.Components } } + dockingContainer.Visible = DockingModeEnabled; + statusContainer.Visible = !DockingModeEnabled; + + if (DockingModeEnabled) + { + if (Math.Abs(DockingSource.Item.WorldPosition.X - DockingTarget.Item.WorldPosition.X) < DockingSource.DistanceTolerance.X && + Math.Abs(DockingSource.Item.WorldPosition.Y - DockingTarget.Item.WorldPosition.Y) < DockingSource.DistanceTolerance.Y) + { + dockingButton.Text = dockText; + if (dockingButton.FlashTimer <= 0.0f) + { + dockingButton.Flash(Color.LightGreen, 0.5f); + dockingButton.Pulsate(Vector2.One, Vector2.One * 1.2f, dockingButton.FlashTimer); + } + } + } + else if (DockingSource != null && DockingSource.Docked) + { + dockingButton.Text = undockText; + dockingContainer.Visible = true; + statusContainer.Visible = false; + if (dockingButton.FlashTimer <= 0.0f) + { + dockingButton.Flash(Color.OrangeRed); + dockingButton.Pulsate(Vector2.One, Vector2.One * 1.2f, dockingButton.FlashTimer); + } + } + else + { + dockingButton.Text = dockText; + } + autoPilotControlsDisabler.Visible = !AutoPilot; if (voltage < minVoltage && currPowerConsumption > 0.0f) @@ -491,13 +644,17 @@ namespace Barotrauma.Items.Components { if (PlayerInput.LeftButtonHeld()) { - Vector2 inputPos = PlayerInput.MousePosition - steerArea.Rect.Center.ToVector2(); + Vector2 displaySubPos = (-sonar.DisplayOffset * sonar.Zoom) / sonar.Range * sonar.DisplayRadius * sonar.Zoom; + displaySubPos.Y = -displaySubPos.Y; + displaySubPos = steerArea.Rect.Center.ToVector2() + displaySubPos; + + Vector2 inputPos = PlayerInput.MousePosition - displaySubPos; inputPos.Y = -inputPos.Y; if (AutoPilot && !LevelStartSelected && !LevelEndSelected) { - posToMaintain = controlledSub == null ? - item.WorldPosition : - controlledSub.WorldPosition + (sonar.DisplayOffset * sonar.Zoom) + inputPos / sonar.DisplayRadius * sonar.Range / sonar.Zoom; + posToMaintain = controlledSub != null ? + controlledSub.WorldPosition + inputPos / sonar.DisplayRadius * sonar.Range / sonar.Zoom : + item.Submarine == null ? item.WorldPosition : item.Submarine.WorldPosition; } else { @@ -563,16 +720,6 @@ namespace Barotrauma.Items.Components if (sourcePort.Docked || sourcePort.Item.Submarine == null) { continue; } if (sourcePort.Item.Submarine != controlledSub) { continue; } - - float closestDist = DockingAssistThreshold * DockingAssistThreshold; - DockingModeEnabled = false; - DockingSource = null; - DockingTarget = null; - foreach (DockingPort sourcePort in DockingPort.List) - { - if (sourcePort.Docked || sourcePort.Item.Submarine == null) { continue; } - if (sourcePort.Item.Submarine != controlledSub) { continue; } - int sourceDir = sourcePort.IsHorizontal ? Math.Sign(sourcePort.Item.WorldPosition.X - sourcePort.Item.Submarine.WorldPosition.X) : Math.Sign(sourcePort.Item.WorldPosition.Y - sourcePort.Item.Submarine.WorldPosition.Y); @@ -600,6 +747,34 @@ namespace Barotrauma.Items.Components } } + private bool NudgeButtonClicked(GUIButton btn, object userdata) + { + if (!MaintainPos || !AutoPilot) + { + AutoPilot = true; + posToMaintain = item.Submarine.WorldPosition; + } + MaintainPos = true; + if (userdata is Vector2) + { + Sonar sonar = item.GetComponent(); + Vector2 nudgeAmount = (Vector2)userdata; + if (sonar != null) + { + nudgeAmount *= sonar == null ? 500.0f : 500.0f / sonar.Zoom; + } + PosToMaintain += nudgeAmount; + } + return true; + } + + protected override void RemoveComponentSpecific() + { + maintainPosIndicator?.Remove(); + maintainPosOriginIndicator?.Remove(); + steeringIndicator?.Remove(); + } + public void ClientWrite(Lidgren.Network.NetBuffer msg, object[] extraData = null) { msg.Write(autoPilot); diff --git a/Barotrauma/BarotraumaClient/Source/Map/Map/Map.cs b/Barotrauma/BarotraumaClient/Source/Map/Map/Map.cs index 4abd51d76..1726040a0 100644 --- a/Barotrauma/BarotraumaClient/Source/Map/Map/Map.cs +++ b/Barotrauma/BarotraumaClient/Source/Map/Map/Map.cs @@ -255,9 +255,9 @@ namespace Barotrauma Duration = CurrentLocation == location ? 1.0f : 2.0f, StartDelay = 1.0f }; - if (change.Messages.Count > 0) + if (change.Messages != null && change.Messages.Count > 0) { - mapAnim.EndMessage = change.Messages[Rand.Range(0,change.Messages.Count)] + mapAnim.EndMessage = change.Messages[Rand.Range(0, change.Messages.Count)] .Replace("[previousname]", prevName) .Replace("[name]", location.Name); } diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs index 870cdca0f..8d18c6beb 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs @@ -94,6 +94,8 @@ namespace Barotrauma private GUILayoutGroup subPreviewContainer; + private GUILayoutGroup subPreviewContainer; + private GUIButton loadGameButton; public Action StartNewGame; diff --git a/Barotrauma/BarotraumaShared/SharedContent.projitems b/Barotrauma/BarotraumaShared/SharedContent.projitems index 0cfdcd61a..ce6b11cf1 100644 --- a/Barotrauma/BarotraumaShared/SharedContent.projitems +++ b/Barotrauma/BarotraumaShared/SharedContent.projitems @@ -376,6 +376,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Deconstructor.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Deconstructor.cs index 740f3302f..36645d27e 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Deconstructor.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Deconstructor.cs @@ -810,6 +810,25 @@ namespace Barotrauma.Items.Components } } + if (targetItem.Prefab.DeconstructItems.Any()) + { + inputContainer.Inventory.RemoveItem(targetItem); + Entity.Spawner.AddToRemoveQueue(targetItem); + MoveInputQueue(); + PutItemsToLinkedContainer(); + } + else + { + if (outputContainer.Inventory.Items.All(i => i != null)) + { + targetItem.Drop(dropper: null); + } + else + { + outputContainer.Inventory.TryPutItem(targetItem, user: null, createNetworkEvent: true); + } + } + if (targetItem.Prefab.DeconstructItems.Any()) { inputContainer.Inventory.RemoveItem(targetItem); diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Sonar.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Sonar.cs index 144d8da1a..fb62df7af 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Sonar.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Sonar.cs @@ -47,8 +47,9 @@ namespace Barotrauma.Items.Components //was the last ping sent with directional pinging private bool isLastPingDirectional; - private readonly Sprite pingCircle, directionalPingCircle, screenOverlay, screenBackground; - private readonly Sprite sonarBlip; + private Sprite pingCircle, directionalPingCircle, screenOverlay, screenBackground; + private Sprite sonarBlip; + private Sprite lineSprite; private bool aiPingCheckPending; @@ -86,6 +87,16 @@ namespace Barotrauma.Items.Components get { return zoom; } } + //TODO: remove, only for testing +#if DEBUG + [Serialize(false, false), Editable] + public bool DynamicDockingIndicator + { + get; + set; + } +#endif + public override bool IsActive { get @@ -111,29 +122,7 @@ namespace Barotrauma.Items.Components : base(item, element) { connectedTransducers = new List(); - - foreach (XElement subElement in element.Elements()) - { - switch (subElement.Name.ToString().ToLowerInvariant()) - { - case "pingcircle": - pingCircle = new Sprite(subElement); - break; - case "directionalpingcircle": - directionalPingCircle = new Sprite(subElement); - break; - case "screenoverlay": - screenOverlay = new Sprite(subElement); - break; - case "screenbackground": - screenBackground = new Sprite(subElement); - break; - case "blip": - sonarBlip = new Sprite(subElement); - break; - } - } - + IsActive = false; InitProjSpecific(element); } @@ -205,6 +194,7 @@ namespace Barotrauma.Items.Components directionalPingCircle?.Remove(); screenOverlay?.Remove(); screenBackground?.Remove(); + lineSprite?.Remove(); } public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective) @@ -262,12 +252,21 @@ namespace Barotrauma.Items.Components return TextManager.Get("roomname.subdiroclock").Replace("[dir]", clockDir.ToString()); } - private Vector2 GetTransducerCenter() + private Vector2 GetTransducerPos() { - if (!UseTransducers || connectedTransducers.Count == 0) return Vector2.Zero; + if (!UseTransducers || connectedTransducers.Count == 0) + { + //use the position of the sub if the item is static (no body) and inside a sub + return item.Submarine != null && item.body == null ? item.Submarine.WorldPosition : item.WorldPosition; + } + Vector2 transducerPosSum = Vector2.Zero; foreach (ConnectedTransducer transducer in connectedTransducers) { + if (transducer.Transducer.Item.Submarine != null) + { + return transducer.Transducer.Item.Submarine.WorldPosition; + } transducerPosSum += transducer.Transducer.Item.WorldPosition; } return transducerPosSum / connectedTransducers.Count; diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Steering.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Steering.cs index 8b79db31b..a251165ce 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Steering.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Steering.cs @@ -245,354 +245,11 @@ namespace Barotrauma.Items.Components public Steering(Item item, XElement element) : base(item, element) { - sonar = item.GetComponent(); + IsActive = true; + InitProjSpecific(element); } - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } - - public override void OnItemLoaded() - { - sonar = item.GetComponent(); - } - - public override bool Select(Character character) - { - if (!CanBeSelected) return false; - - user = character; - return true; - } + partial void InitProjSpecific(XElement element); public override void OnItemLoaded() { @@ -909,7 +566,9 @@ namespace Barotrauma.Items.Components if (!posToMaintain.HasValue) { unsentChanges = true; - posToMaintain = controlledSub == null ? item.WorldPosition : controlledSub.WorldPosition; + posToMaintain = controlledSub != null ? + controlledSub.WorldPosition : + item.Submarine == null ? item.WorldPosition : item.Submarine.WorldPosition; } if (!AutoPilot || !MaintainPos) unsentChanges = true; diff --git a/Barotrauma/BarotraumaShared/Source/Items/Item.cs b/Barotrauma/BarotraumaShared/Source/Items/Item.cs index 943ba5b97..71d80c1c3 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Item.cs @@ -1348,6 +1348,10 @@ namespace Barotrauma { ApplyStatusEffects(!waterProof && inWater ? ActionType.InWater : ActionType.NotInWater, deltaTime); } + if (!broken) + { + ApplyStatusEffects(!waterProof && inWater ? ActionType.InWater : ActionType.NotInWater, deltaTime); + } ApplyStatusEffects(!waterProof && inWater ? ActionType.InWater : ActionType.NotInWater, deltaTime); if (body == null || !body.Enabled || !inWater || ParentInventory != null || Removed) { return; } @@ -1490,7 +1494,7 @@ namespace Barotrauma if (recursive) { - List alreadySearched = new List() { this }; + HashSet alreadySearched = new HashSet(); GetConnectedComponentsRecursive(alreadySearched, connectedComponents); return connectedComponents; @@ -1512,7 +1516,7 @@ namespace Barotrauma return connectedComponents; } - private void GetConnectedComponentsRecursive(List alreadySearched, List connectedComponents) where T : ItemComponent + private void GetConnectedComponentsRecursive(HashSet alreadySearched, List connectedComponents) where T : ItemComponent { ConnectionPanel connectionPanel = GetComponent(); if (connectionPanel == null) { return; } @@ -1536,28 +1540,35 @@ namespace Barotrauma } } - recipient.Item.GetConnectedComponentsRecursive(alreadySearched, connectedComponents); - } - } - } - public List GetConnectedComponentsRecursive(Connection c) where T : ItemComponent { - List connectedComponents = new List(); - List alreadySearched = new List() { this }; + List connectedComponents = new List(); + HashSet alreadySearched = new HashSet(); GetConnectedComponentsRecursive(c, alreadySearched, connectedComponents); return connectedComponents; } - - private void GetConnectedComponentsRecursive(Connection c, List alreadySearched, List connectedComponents) where T : ItemComponent + + private static readonly Pair[] connectionPairs = new Pair[] { - alreadySearched.Add(this); + new Pair("power_in", "power_out"), + new Pair("signal_in1", "signal_out1"), + new Pair("signal_in2", "signal_out2"), + new Pair("signal_in3", "signal_out3"), + new Pair("signal_in4", "signal_out4"), + new Pair("signal_in", "signal_out"), + new Pair("signal_in1", "signal_out"), + new Pair("signal_in2", "signal_out") + }; + + private void GetConnectedComponentsRecursive(Connection c, HashSet alreadySearched, List connectedComponents) where T : ItemComponent + { + alreadySearched.Add(c); var recipients = c.Recipients; foreach (Connection recipient in recipients) { - if (alreadySearched.Contains(recipient.Item)) continue; + if (alreadySearched.Contains(recipient)) { continue; } var component = recipient.Item.GetComponent(); if (component != null) @@ -1566,7 +1577,29 @@ namespace Barotrauma } recipient.Item.GetConnectedComponentsRecursive(recipient, alreadySearched, connectedComponents); - } + } + + foreach (Pair connectionPair in connectionPairs) + { + if (connectionPair.First == c.Name) + { + var pairedConnection = c.Item.Connections.FirstOrDefault(c2 => c2.Name == connectionPair.Second); + if (pairedConnection != null) + { + if (alreadySearched.Contains(pairedConnection)) { continue; } + GetConnectedComponentsRecursive(pairedConnection, alreadySearched, connectedComponents); + } + } + else if (connectionPair.Second == c.Name) + { + var pairedConnection = c.Item.Connections.FirstOrDefault(c2 => c2.Name == connectionPair.First); + if (pairedConnection != null) + { + if (alreadySearched.Contains(pairedConnection)) { continue; } + GetConnectedComponentsRecursive(pairedConnection, alreadySearched, connectedComponents); + } + } + } } diff --git a/Barotrauma/BarotraumaShared/Source/Map/Hull.cs b/Barotrauma/BarotraumaShared/Source/Map/Hull.cs index 210df583d..1701f7a6f 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Hull.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Hull.cs @@ -721,6 +721,25 @@ namespace Barotrauma } } + public string DisplayName + { + get; + private set; + } + + private string roomName; + [Editable, Serialize("", true, translationTextTag: "RoomName.")] + public string RoomName + { + get { return roomName; } + set + { + if (roomName == value) { return; } + roomName = value; + DisplayName = TextManager.Get(roomName, returnNull: true) ?? roomName; + } + } + public override Rectangle Rect { get diff --git a/Barotrauma/BarotraumaShared/Source/Map/Map/LocationTypeChange.cs b/Barotrauma/BarotraumaShared/Source/Map/Map/LocationTypeChange.cs index 71cf8dc39..267cf68f8 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Map/LocationTypeChange.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Map/LocationTypeChange.cs @@ -28,6 +28,10 @@ namespace Barotrauma RequiredAdjacentLocations = element.GetAttributeStringArray("requiredadjacentlocations", new string[0]).ToList(); Messages = TextManager.GetAll("LocationChange." + currentType + ".ChangeTo." + ChangeToType); + if (Messages == null) + { + DebugConsole.ThrowError("No messages defined for the location type change " + currentType + " -> " + ChangeToType); + } } } } diff --git a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs index 66a196458..0cb0320ed 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs @@ -428,17 +428,17 @@ namespace Barotrauma //prevent rewiring connectionPanel.Locked = true; } - else if (ic is Pickable pickable) + else if (ic is Holdable holdable && holdable.Attached) { - //prevent picking up (or deattaching) items + //prevent deattaching items from walls #if CLIENT if (GameMain.GameSession?.GameMode is TutorialMode) { continue; } #endif - pickable.CanBePicked = false; - pickable.CanBeSelected = false; + holdable.CanBePicked = false; + holdable.CanBeSelected = false; } } } diff --git a/Barotrauma/BarotraumaShared/Source/PlayerInput.cs b/Barotrauma/BarotraumaShared/Source/PlayerInput.cs index e13028523..8ad826eea 100644 --- a/Barotrauma/BarotraumaShared/Source/PlayerInput.cs +++ b/Barotrauma/BarotraumaShared/Source/PlayerInput.cs @@ -162,6 +162,21 @@ namespace Barotrauma get { return binding; } } + public void SetState() + { + hit = binding.IsHit(); + if (hit) hitQueue = true; + + held = binding.IsDown(); + if (held) heldQueue = true; + } +#endif + + public KeyOrMouse State + { + get { return binding; } + } + public void SetState() { hit = binding.IsHit(); diff --git a/Barotrauma/BarotraumaShared/Source/Utils/MathUtils.cs b/Barotrauma/BarotraumaShared/Source/Utils/MathUtils.cs index bb12617b7..724c807d2 100644 --- a/Barotrauma/BarotraumaShared/Source/Utils/MathUtils.cs +++ b/Barotrauma/BarotraumaShared/Source/Utils/MathUtils.cs @@ -795,6 +795,18 @@ namespace Barotrauma return new Vector2((float)x, (float)y); } + /// + /// Rotates a point in 2d space around the origin + /// + public static Vector2 RotatePoint(Vector2 point, float radians) + { + var sin = Math.Sin(radians); + var cos = Math.Cos(radians); + var x = (cos * point.X) - (sin * point.Y); + var y = (sin * point.X) + (cos * point.Y); + return new Vector2((float)x, (float)y); + } + /// /// Returns the corners of an imaginary rectangle. /// Unlike the XNA rectangle, this can be rotated with the up parameter.