From 9da8a437ebb54f29efb3b715616d1e01690d8b7b Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Thu, 16 May 2019 06:32:06 +0300 Subject: [PATCH] (aebd2c4c0) tweaks part 666 --- .../Source/Characters/Animation/Ragdoll.cs | 83 --- .../Source/GameSession/CrewManager.cs | 247 +++++++-- .../Source/Screens/CampaignSetupUI.cs | 2 + .../Source/Screens/MainMenuScreen.cs | 4 + .../AI/Objectives/AIObjectiveFixLeak.cs | 26 + .../AI/Objectives/AIObjectiveIdle.cs | 15 + .../AI/Objectives/AIObjectiveOperateItem.cs | 4 + .../Components/Machines/Deconstructor.cs | 513 ------------------ .../Items/Components/Machines/Steering.cs | 27 - .../BarotraumaShared/Source/Items/Item.cs | 25 + .../BarotraumaShared/Source/Map/Hull.cs | 21 + .../BarotraumaShared/Source/Map/Submarine.cs | 2 +- .../BarotraumaShared/Submarines/Remora.sub | Bin 587370 -> 587456 bytes 13 files changed, 314 insertions(+), 655 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/GameSession/CrewManager.cs b/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs index e9bd2ba83..8b52b1fd9 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs @@ -74,12 +74,17 @@ namespace Barotrauma public CrewManager(XElement element, bool isSinglePlayer) : this(isSinglePlayer) { - if (!isSinglePlayer) + if (GameMain.Client != null) { - DebugConsole.ThrowError("Cannot add messages to single player chat box in multiplayer mode!\n" + Environment.StackTrace); + //let the server create random conversations in MP return; } - if (string.IsNullOrEmpty(text)) { return; } + List availableSpeakers = Character.CharacterList.FindAll(c => + c.AIController is HumanAIController && + !c.IsDead && + c.SpeechImpediment <= 100.0f); + pendingConversationLines.AddRange(NPCConversation.CreateRandom(availableSpeakers)); + } var characterInfo = new CharacterInfo(subElement); characterInfos.Add(characterInfo); @@ -90,7 +95,6 @@ namespace Barotrauma break; } } - ChatBox.AddMessage(ChatMessage.Create(senderName, text, messageType, sender)); } partial void InitProjectSpecific() @@ -239,27 +243,24 @@ namespace Barotrauma public IEnumerable GetCharacters() { - if (character?.Inventory == null) return null; + if (characterInfos.Contains(characterInfo)) + { + DebugConsole.ThrowError("Tried to add the same character info to CrewManager twice.\n" + Environment.StackTrace); + return; + } - 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(); + characterInfos.Add(characterInfo); } public IEnumerable GetCharacterInfos() { - if (GameMain.Client != null) + if (character == null) { - //let the server create random conversations in MP + DebugConsole.ThrowError("Tried to remove a null character from CrewManager.\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)); + characters.Remove(character); + if (removeInfo) characterInfos.Remove(character.Info); } public void AddCharacter(Character character) @@ -633,9 +634,183 @@ namespace Barotrauma { characterListBox.BarScroll = roundedPos; } - soundIcon.Visible = !muted && !mutedLocally; - soundIconDisabled.Visible = muted || mutedLocally; - soundIconDisabled.ToolTip = TextManager.Get(mutedLocally ? "MutedLocally" : "MutedGlobally"); + 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; } private IEnumerable KillCharacterAnim(GUIComponent component) @@ -779,6 +954,12 @@ 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) @@ -836,19 +1017,23 @@ namespace Barotrauma } } } - //only one target (or an order with no particular targets), just show options - else + + character.SetOrder(order, option, orderGiver, speak: orderGiver != character); + if (IsSinglePlayer) { - 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) + 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) { - 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); + GameMain.Client.SendChatMessage(msg); + } + } + DisplayCharacterOrder(character, order); + } /// /// Create the UI panel that's used to select the target and options for a given order diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs index 6f23be9fd..0915f36af 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs @@ -568,6 +568,8 @@ namespace Barotrauma private GUILayoutGroup subPreviewContainer; + private GUILayoutGroup subPreviewContainer; + private GUIButton loadGameButton; public Action StartNewGame; diff --git a/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs index 287ac0265..96c441896 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs @@ -789,6 +789,10 @@ namespace Barotrauma GUI.Draw(Cam, spriteBatch); + spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, GameMain.ScissorTestEnable); + + GUI.Draw(Cam, spriteBatch); + GUI.Draw(Cam, spriteBatch); #if DEBUG diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeak.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeak.cs index 039800ed2..a7809d205 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeak.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeak.cs @@ -777,6 +777,32 @@ namespace Barotrauma { #if DEBUG DebugConsole.ThrowError("AIObjectiveFixLeak failed - the item \"" + weldingTool + "\" has no RepairTool component but is tagged as a welding tool"); +#endif + abandon = true; + return; + } + Vector2 gapDiff = Leak.WorldPosition - character.WorldPosition; + // TODO: use the collider size/reach? + if (!character.AnimController.InWater && Math.Abs(gapDiff.X) < 100 && gapDiff.Y < 0.0f && gapDiff.Y > -150) + { + HumanAIController.AnimController.Crouching = true; + } + float reach = ConvertUnits.ToSimUnits(repairTool.Range); + bool canOperate = ConvertUnits.ToSimUnits(gapDiff.Length()) < reach * 1.5f; + if (canOperate) + { + TryAddSubObjective(ref operateObjective, () => new AIObjectiveOperateItem(repairTool, character, objectiveManager, option: "", requireEquip: true, operateTarget: Leak)); + } + else + { + TryAddSubObjective(ref gotoObjective, () => new AIObjectiveGoTo(ConvertUnits.ToSimUnits(GetStandPosition()), character, objectiveManager) { CloseEnough = reach * 0.75f }); + } + if (subObjectives.Any()) { return; } + var repairTool = weldingTool.GetComponent(); + if (repairTool == null) + { +#if DEBUG + DebugConsole.ThrowError("AIObjectiveFixLeak failed - the item \"" + weldingTool + "\" has no RepairTool component but is tagged as a welding tool"); #endif abandon = true; return; diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveIdle.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveIdle.cs index dc103bb9f..e3dfba206 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveIdle.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveIdle.cs @@ -88,6 +88,21 @@ namespace Barotrauma } } + public override void Update(float deltaTime) + { + if (objectiveManager.CurrentObjective == this) + { + if (randomTimer > 0) + { + randomTimer -= deltaTime; + } + else + { + SetRandom(); + } + } + } + public override bool IsCompleted() => false; public override bool CanBeCompleted => true; diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveOperateItem.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveOperateItem.cs index 3cf32adc3..ec6c01422 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveOperateItem.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveOperateItem.cs @@ -537,6 +537,10 @@ namespace Barotrauma { isCompleted = true; } + if (component.AIOperate(deltaTime, character, this)) + { + isCompleted = true; + } } else { diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Deconstructor.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Deconstructor.cs index 69e06880e..5e0c16b68 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Deconstructor.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Deconstructor.cs @@ -544,519 +544,6 @@ 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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/Steering.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Steering.cs index a251165ce..2aafee648 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Steering.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Steering.cs @@ -212,33 +212,6 @@ namespace Barotrauma.Items.Components } } - public Vector2? PosToMaintain - { - get { return posToMaintain; } - set { posToMaintain = value; } - } - - struct ObstacleDebugInfo - { - public Vector2 Point1; - public Vector2 Point2; - - public Vector2? Intersection; - - public float Dot; - - public Vector2 AvoidStrength; - - public ObstacleDebugInfo(GraphEdge edge, Vector2? intersection, float dot, Vector2 avoidStrength) - { - Point1 = edge.Point1; - Point2 = edge.Point2; - Intersection = intersection; - Dot = dot; - AvoidStrength = avoidStrength; - } - } - //edge point 1, edge point 2, avoid strength private List debugDrawObstacles = new List(); diff --git a/Barotrauma/BarotraumaShared/Source/Items/Item.cs b/Barotrauma/BarotraumaShared/Source/Items/Item.cs index 39bdfb8f0..4392ee683 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Item.cs @@ -1128,6 +1128,10 @@ namespace Barotrauma { ApplyStatusEffects(!waterProof && inWater ? ActionType.InWater : ActionType.NotInWater, deltaTime); } + if (!broken) + { + ApplyStatusEffects(!waterProof && inWater ? ActionType.InWater : ActionType.NotInWater, deltaTime); + } if (body == null || !body.Enabled || !inWater || ParentInventory != null || Removed) { return; } @@ -1172,6 +1176,27 @@ namespace Barotrauma } } + public void UpdateTransform() + { + Submarine prevSub = Submarine; + + FindHull(); + + if (body == null || !body.Enabled || !inWater || ParentInventory != null || Removed) { return; } + + Vector2 displayPos = ConvertUnits.ToDisplayUnits(body.SimPosition); + rect.X = (int)(displayPos.X - rect.Width / 2.0f); + rect.Y = (int)(displayPos.Y + rect.Height / 2.0f); + + if (Math.Abs(body.LinearVelocity.X) > NetConfig.MaxPhysicsBodyVelocity || + Math.Abs(body.LinearVelocity.Y) > NetConfig.MaxPhysicsBodyVelocity) + { + body.LinearVelocity = new Vector2( + MathHelper.Clamp(body.LinearVelocity.X, -NetConfig.MaxPhysicsBodyVelocity, NetConfig.MaxPhysicsBodyVelocity), + MathHelper.Clamp(body.LinearVelocity.Y, -NetConfig.MaxPhysicsBodyVelocity, NetConfig.MaxPhysicsBodyVelocity)); + } + } + public void UpdateTransform() { Submarine prevSub = Submarine; diff --git a/Barotrauma/BarotraumaShared/Source/Map/Hull.cs b/Barotrauma/BarotraumaShared/Source/Map/Hull.cs index 31a6553ef..3e934a177 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Hull.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Hull.cs @@ -15,6 +15,8 @@ namespace Barotrauma public static List hullList = new List(); public static List EntityGrids { get; } = new List(); + public static bool ShowHulls = true; + public static bool EditWater, EditFire; public const float OxygenDistributionSpeed = 500.0f; public const float OxygenDeteriorationSpeed = 0.3f; @@ -206,6 +208,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/Submarine.cs b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs index 405199541..6d94989cc 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs @@ -1364,7 +1364,7 @@ namespace Barotrauma foreach (Hull hull in matchingHulls) { - if (string.IsNullOrEmpty(hull.RoomName) || !hull.RoomName.ToLower().Contains("roomname.")) + if (string.IsNullOrEmpty(hull.RoomName) || !hull.RoomName.Contains("RoomName.")) { hull.RoomName = hull.CreateRoomName(); } diff --git a/Barotrauma/BarotraumaShared/Submarines/Remora.sub b/Barotrauma/BarotraumaShared/Submarines/Remora.sub index 744f1d2f00bb265151349a3d46a4a15f4d350c78..32376a763bd2a883a35459526c92a9dd1fa847b9 100644 GIT binary patch delta 564932 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