diff --git a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs index 598c5e10d..7eae6e4e6 100644 --- a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs +++ b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.9.0.1")] -[assembly: AssemblyFileVersion("0.9.0.1")] +[assembly: AssemblyVersion("0.9.0.0")] +[assembly: AssemblyFileVersion("0.9.0.0")] diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs index bcf133b30..fa30d8a82 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs @@ -108,6 +108,61 @@ namespace Barotrauma } } + //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.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) @@ -151,32 +206,34 @@ namespace Barotrauma } } - - if (character.MemLocalState.Count > 120) character.MemLocalState.RemoveRange(0, character.MemLocalState.Count - 120); - character.MemState.Clear(); + character.MemLocalState.Clear(); } - } - - partial void ImpactProjSpecific(float impact, Body body) - { - float volume = MathHelper.Clamp(impact - 3.0f, 0.5f, 1.0f); - - if (body.UserData is Limb limb && character.Stun <= 0f) + else { - if (impact > 3.0f) { PlayImpactSound(limb); } - } - else if (body.UserData is Limb || body == Collider.FarseerBody) - { - if (!character.IsRemotePlayer && impact > ImpactTolerance) + //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++) { - SoundPlayer.PlayDamageSound("LimbBlunt", strongestImpact, Collider); + 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); + } + } + } - } - if (Character.Controlled == character) - { - GameMain.GameScreen.Cam.Shake = Math.Min(Math.Max(strongestImpact, GameMain.GameScreen.Cam.Shake), 3.0f); - } - } if (character.MemState.Count < 1) return; diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs b/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs index 8b52b1fd9..e9bd2ba83 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() @@ -243,24 +239,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) @@ -634,183 +633,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) @@ -954,12 +779,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) @@ -1017,23 +836,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/GameSession/GameModes/Tutorials/DoctorTutorial.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/DoctorTutorial.cs index 866383206..b372f675b 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/DoctorTutorial.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/DoctorTutorial.cs @@ -53,9 +53,9 @@ namespace Barotrauma.Tutorials doctor_suppliesCabinet = Item.ItemList.Find(i => i.HasTag("doctor_suppliescabinet"))?.GetComponent(); doctor_medBayCabinet = Item.ItemList.Find(i => i.HasTag("doctor_medbaycabinet"))?.GetComponent(); - var patientHull1 = WayPoint.WayPointList.Find(wp => wp.IdCardDesc == "waitingroom").CurrentHull; - var patientHull2 = WayPoint.WayPointList.Find(wp => wp.IdCardDesc == "airlock").CurrentHull; - medBay = WayPoint.WayPointList.Find(wp => wp.IdCardDesc == "medbay").CurrentHull; + var patientHull1 = Hull.hullList.Find(h => h.RoomName == "Waiting room" && h.Submarine == doctor.Submarine); + var patientHull2 = Hull.hullList.Find(h => h.RoomName == "Airlock" && h.Submarine == doctor.Submarine); + medBay = Hull.hullList.Find(h => h.RoomName == "Med bay" && h.Submarine == doctor.Submarine); var assistantInfo = new CharacterInfo(Character.HumanConfigFile, "", JobPrefab.List.Find(jp => jp.Identifier == "assistant")); patient1 = Character.Create(assistantInfo, patientHull1.WorldPosition, "1"); diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/CustomInterface.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/CustomInterface.cs index 3e09036c4..e3480c50a 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/CustomInterface.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/CustomInterface.cs @@ -36,7 +36,6 @@ namespace Barotrauma.Items.Components { UserData = ciElement }; - tickBox.TextBlock.AutoScale = true; tickBox.OnSelected += (tBox) => { if (GameMain.Client == null) @@ -58,7 +57,6 @@ namespace Barotrauma.Items.Components { UserData = ciElement }; - btn.TextBlock.AutoScale = true; btn.OnClicked += (_, userdata) => { if (GameMain.Client == null) diff --git a/Barotrauma/BarotraumaClient/Source/Items/Item.cs b/Barotrauma/BarotraumaClient/Source/Items/Item.cs index a783d7ae6..a0c4f5d1f 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Item.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Item.cs @@ -1114,10 +1114,8 @@ namespace Barotrauma //---------------------------------------- - var itemPrefab = string.IsNullOrEmpty(itemIdentifier) ? - MapEntityPrefab.Find(itemName, null, showErrorMessages: false) as ItemPrefab : - MapEntityPrefab.Find(itemName, itemIdentifier, showErrorMessages: false) as ItemPrefab; - if (itemPrefab == null) { return null; } + var itemPrefab = MapEntityPrefab.Find(itemName, itemIdentifier) as ItemPrefab; + if (itemPrefab == null) return null; Inventory inventory = null; diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs index a0c224262..b53a3157a 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs @@ -686,6 +686,8 @@ namespace Barotrauma private GUILayoutGroup subPreviewContainer; + private GUILayoutGroup subPreviewContainer; + private GUIButton loadGameButton; public Action StartNewGame; diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CreditsPlayer.cs b/Barotrauma/BarotraumaClient/Source/Screens/CreditsPlayer.cs index edd14786a..2406d8970 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/CreditsPlayer.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/CreditsPlayer.cs @@ -9,6 +9,7 @@ namespace Barotrauma private GUIListBox listBox; private readonly float scrollSpeed; + public CreditsPlayer(RectTransform rectT, string configFile) : base(null, rectT) { var doc = XMLExtensions.TryLoadXml(configFile); @@ -113,11 +114,6 @@ namespace Barotrauma } } - public void Restart() - { - listBox.BarScroll = 0.0f; - } - protected override void Update(float deltaTime) { listBox.BarScroll += scrollSpeed / listBox.TotalSize * deltaTime; diff --git a/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs index b6baac0d0..bacc84c2e 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs @@ -470,7 +470,6 @@ namespace Barotrauma break; case Tab.Credits: titleText.Visible = false; - creditsPlayer.Restart(); break; } } diff --git a/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs index 62a738a43..ad4b8fdb0 100644 --- a/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs +++ b/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.9.0.1")] -[assembly: AssemblyFileVersion("0.9.0.1")] +[assembly: AssemblyVersion("0.9.0.0")] +[assembly: AssemblyFileVersion("0.9.0.0")] diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/HumanAIController.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/HumanAIController.cs index a22274784..65aefd0a7 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/HumanAIController.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/HumanAIController.cs @@ -169,7 +169,15 @@ namespace Barotrauma bool highPressure = Character.CurrentHull == null || Character.CurrentHull.LethalPressure > 0 && Character.PressureProtection <= 0; bool shouldKeepTheGearOn = !ObjectiveManager.IsCurrentObjective(); - bool removeDivingSuit = (oxygenLow && !highPressure) || (!shouldKeepTheGearOn && Character.CurrentHull.WaterPercentage < 1 && !Character.IsClimbing && steeringManager == insideSteering && !PathSteering.InStairs); + // Don't allow to drop the diving suit in water or while climbing or if the current path has stairs + bool removeDivingSuit = + (oxygenLow && !highPressure) || + (!shouldKeepTheGearOn && + Character.CurrentHull.WaterPercentage < 1 && + !Character.IsClimbing && + steeringManager == insideSteering && + !PathSteering.InStairs); + if (removeDivingSuit) { var divingSuit = Character.Inventory.FindItemByIdentifier("divingsuit") ?? Character.Inventory.FindItemByTag("divingsuit"); @@ -495,8 +503,10 @@ namespace Barotrauma public static void DoForEachCrewMember(Character character, Action action) { + if (character == null) { return; } foreach (var c in Character.CharacterList) { + if (c == null || c.IsDead || c.Removed) { continue; } if (c.AIController is HumanAIController humanAi && humanAi.IsFriendly(character)) { action(humanAi); diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/IndoorsSteeringManager.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/IndoorsSteeringManager.cs index b6d45ca1d..c51f69382 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/IndoorsSteeringManager.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/IndoorsSteeringManager.cs @@ -53,13 +53,9 @@ namespace Barotrauma (currentPath.NextNode != null && currentPath.NextNode.Ladders != null)); /// - /// Returns true if the previous, current or the next node is in stairs. + /// Returns true if any node in the path is in stairs /// - public bool InStairs => - currentPath != null && ( - currentPath.PrevNode != null && currentPath.PrevNode.Stairs != null || - currentPath.CurrentNode != null && currentPath.CurrentNode.Stairs != null || - currentPath.NextNode != null && currentPath.NextNode.Stairs != null); + public bool InStairs => currentPath != null && currentPath.Nodes.Any(n => n.Stairs != null); public bool IsNextNodeLadder { @@ -304,7 +300,9 @@ namespace Barotrauma float horizontalDistance = Math.Abs(collider.SimPosition.X - currentPath.CurrentNode.SimPosition.X); bool isAboveFeet = currentPath.CurrentNode.SimPosition.Y > colliderBottom.Y; bool isNotTooHigh = currentPath.CurrentNode.SimPosition.Y < colliderBottom.Y + characterHeight; - if (currentPath.CurrentNode != null && currentPath.CurrentNode.Stairs != null) + float margin = MathHelper.Lerp(1, 10, MathHelper.Clamp(Math.Abs(velocity.X) / 10, 0, 1)); + float targetDistance = collider.radius * margin; + if (horizontalDistance < targetDistance && isAboveFeet && isNotTooHigh) { float multiplierX = MathHelper.Lerp(1, 10, MathHelper.Clamp(Math.Abs(velocity.X) / 10, 0, 1)); float multiplierY = MathHelper.Lerp(1, 10, MathHelper.Clamp(Math.Abs(velocity.Y) / 10, 0, 1)); diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeak.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeak.cs index 3ed0b9472..c5f66fe91 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeak.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeak.cs @@ -1141,6 +1141,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 71bfd44b5..dc103bb9f 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveIdle.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveIdle.cs @@ -73,6 +73,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 be45188a9..86f2a3242 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveOperateItem.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveOperateItem.cs @@ -773,6 +773,10 @@ namespace Barotrauma { isCompleted = true; } + if (component.AIOperate(deltaTime, character, this)) + { + isCompleted = true; + } } else { diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Params/Animation/AnimationParams.cs b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Params/Animation/AnimationParams.cs index f4e118652..0d3b77f8a 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Params/Animation/AnimationParams.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Params/Animation/AnimationParams.cs @@ -97,12 +97,11 @@ namespace Barotrauma public static string GetDefaultFileName(string speciesName, AnimationType animType) => $"{speciesName.CapitaliseFirstInvariant()}{animType.ToString()}"; public static string GetDefaultFolder(string speciesName) => $"Content/Characters/{speciesName.CapitaliseFirstInvariant()}/Animations/"; - public static string GetDefaultFile(string speciesName, AnimationType animType, ContentPackage contentPackage = null) => - $"{GetFolder(speciesName, contentPackage)}{GetDefaultFileName(speciesName, animType)}.xml"; + public static string GetDefaultFile(string speciesName, AnimationType animType) => $"{GetFolder(speciesName)}{GetDefaultFileName(speciesName, animType)}.xml"; - public static string GetFolder(string speciesName, ContentPackage contentPackage = null) + public static string GetFolder(string speciesName) { - var folder = XMLExtensions.TryLoadXml(Character.GetConfigFile(speciesName, contentPackage))?.Root?.Element("animations")?.GetAttributeString("folder", string.Empty); + var folder = XMLExtensions.TryLoadXml(Character.GetConfigFile(speciesName))?.Root?.Element("animations")?.GetAttributeString("folder", string.Empty); if (string.IsNullOrEmpty(folder) || folder.ToLowerInvariant() == "default") { folder = GetDefaultFolder(speciesName); diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Params/Ragdoll/RagdollParams.cs b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Params/Ragdoll/RagdollParams.cs index 0ca685008..81677d50f 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Params/Ragdoll/RagdollParams.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Params/Ragdoll/RagdollParams.cs @@ -64,7 +64,7 @@ namespace Barotrauma public static string GetDefaultFileName(string speciesName) => $"{speciesName.CapitaliseFirstInvariant()}DefaultRagdoll"; public static string GetDefaultFolder(string speciesName) => $"Content/Characters/{speciesName.CapitaliseFirstInvariant()}/Ragdolls/"; - public static string GetDefaultFile(string speciesName, ContentPackage contentPackage = null) => $"{GetFolder(speciesName, contentPackage)}{GetDefaultFileName(speciesName)}.xml"; + public static string GetDefaultFile(string speciesName) => $"{GetFolder(speciesName)}{GetDefaultFileName(speciesName)}.xml"; private static readonly object[] dummyParams = new object[] { @@ -79,9 +79,9 @@ namespace Barotrauma new XAttribute("sourcerect", $"0, 0, 1, 1"))) }; - public static string GetFolder(string speciesName, ContentPackage contentPackage = null) + public static string GetFolder(string speciesName) { - var folder = XMLExtensions.TryLoadXml(Character.GetConfigFile(speciesName, contentPackage))?.Root?.Element("ragdolls")?.GetAttributeString("folder", string.Empty); + var folder = XMLExtensions.TryLoadXml(Character.GetConfigFile(speciesName))?.Root?.Element("ragdolls")?.GetAttributeString("folder", string.Empty); if (string.IsNullOrEmpty(folder) || folder.ToLowerInvariant() == "default") { //DebugConsole.NewMessage("[RagollParams] Using the default folder."); diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs index fcf32ff1c..ea49bed59 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs @@ -853,26 +853,15 @@ namespace Barotrauma { if (characterConfigFiles == null) { - characterConfigFiles = GameMain.Instance.GetFilesOfType(ContentType.Character); + characterConfigFiles = GameMain.Instance.GetFilesOfType(ContentType.Character, searchAllContentPackages: true); } return characterConfigFiles; } } - public static string GetConfigFile(string speciesName, ContentPackage contentPackage = null) + public static string GetConfigFile(string speciesName) { - string configFile = null; - if (contentPackage == null) - { - configFile = GameMain.Instance.GetFilesOfType(ContentType.Character, searchAllContentPackages: true) - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - else - { - configFile = contentPackage.GetFilesOfType(ContentType.Character)? - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - + string configFile = CharacterConfigFiles.FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); if (configFile == null) { DebugConsole.ThrowError($"Couldn't find a config file for {speciesName} from the selected content packages!"); @@ -1147,33 +1136,7 @@ namespace Barotrauma if (!(this is AICharacter) || Controlled == this || IsRemotePlayer) { - SmoothedCursorPosition = cursorPosition; - } - else - { - //apply some smoothing to the cursor positions of remote players when playing as a client - //to make aiming look a little less choppy - Vector2 smoothedCursorDiff = cursorPosition - SmoothedCursorPosition; - smoothedCursorDiff = NetConfig.InterpolateCursorPositionError(smoothedCursorDiff); - SmoothedCursorPosition = cursorPosition - smoothedCursorDiff; - } - - if (!(this is AICharacter) || Controlled == this || IsRemotePlayer) - { - SmoothedCursorPosition = cursorPosition; - } - else - { - //apply some smoothing to the cursor positions of remote players when playing as a client - //to make aiming look a little less choppy - Vector2 smoothedCursorDiff = cursorPosition - SmoothedCursorPosition; - smoothedCursorDiff = NetConfig.InterpolateCursorPositionError(smoothedCursorDiff); - SmoothedCursorPosition = cursorPosition - smoothedCursorDiff; - } - - if (!(this is AICharacter) || Controlled == this || IsRemotePlayer) - { - if (speedMultipliers.Count == 0) return 1f; + Vector2 targetMovement = GetTargetMovement(); AnimController.TargetMovement = targetMovement; AnimController.IgnorePlatforms = AnimController.TargetMovement.Y < -0.1f; @@ -2681,5 +2644,57 @@ namespace Barotrauma } public AttackContext GetAttackContext() => AnimController.CurrentAnimationParams.IsGroundedAnimation ? AttackContext.Ground : AttackContext.Water; + + private List visibleHulls = new List(); + private HashSet tempList = new HashSet(); + /// + /// Returns hulls that are visible to the player, including the current hull. + /// Can be heavy if used every frame. + /// + public List GetVisibleHulls() + { + visibleHulls.Clear(); + tempList.Clear(); + if (CurrentHull != null) + { + visibleHulls.Add(CurrentHull); + var adjacentHulls = CurrentHull.GetConnectedHulls(true, 1); + float maxDistance = 1000f; + foreach (var hull in adjacentHulls) + { + if (hull.ConnectedGaps.Any(g => g.Open > 0.9f && g.linkedTo.Contains(CurrentHull) && + Vector2.DistanceSquared(g.WorldPosition, WorldPosition) < Math.Pow(maxDistance / 2, 2))) + { + if (Vector2.DistanceSquared(hull.WorldPosition, WorldPosition) < Math.Pow(maxDistance, 2)) + { + visibleHulls.Add(hull); + } + } + } + visibleHulls.AddRange(CurrentHull.GetLinkedEntities(tempList, filter: h => + { + // Ignore adjacent hulls because they were already handled above + if (adjacentHulls.Contains(h)) + { + return false; + } + else + { + if (h.ConnectedGaps.Any(g => + g.Open > 0.9f && + Vector2.DistanceSquared(g.WorldPosition, WorldPosition) < Math.Pow(maxDistance / 2, 2) && + CanSeeTarget(g))) + { + return Vector2.DistanceSquared(h.WorldPosition, WorldPosition) < Math.Pow(maxDistance, 2); + } + else + { + return false; + } + } + })); + } + return visibleHulls; + } } } diff --git a/Barotrauma/BarotraumaShared/Source/ContentPackage.cs b/Barotrauma/BarotraumaShared/Source/ContentPackage.cs index b9071ec17..e51a98e27 100644 --- a/Barotrauma/BarotraumaShared/Source/ContentPackage.cs +++ b/Barotrauma/BarotraumaShared/Source/ContentPackage.cs @@ -362,11 +362,10 @@ namespace Barotrauma case ContentType.Character: XDocument doc = XMLExtensions.TryLoadXml(file.Path); string speciesName = doc.Root.GetAttributeString("name", ""); - //TODO: check non-default paths if defined - filePaths.Add(RagdollParams.GetDefaultFile(speciesName, this)); + filePaths.Add(RagdollParams.GetDefaultFile(speciesName)); foreach (AnimationType animationType in Enum.GetValues(typeof(AnimationType))) { - filePaths.Add(AnimationParams.GetDefaultFile(speciesName, animationType, this)); + filePaths.Add(AnimationParams.GetDefaultFile(speciesName, animationType)); } break; } @@ -492,11 +491,6 @@ namespace Barotrauma public ContentFile(string path, ContentType type, Workshop.Item workShopItem = null) { Path = path; - -#if OSX - Path = Path.Replace("\\", "/"); -#endif - Type = type; WorkShopItem = workShopItem; } diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Deconstructor.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Deconstructor.cs index d20a57d69..bf78419aa 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Deconstructor.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Deconstructor.cs @@ -582,6 +582,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/Steering.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Steering.cs index 7a471a65c..f6d19e87b 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Steering.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Steering.cs @@ -144,17 +144,6 @@ namespace Barotrauma.Items.Components } } - public Vector2 SteeringInput - { - get { return steeringInput; } - set - { - if (!MathUtils.IsValid(value)) return; - steeringInput.X = MathHelper.Clamp(value.X, -100.0f, 100.0f); - steeringInput.Y = MathHelper.Clamp(value.Y, -100.0f, 100.0f); - } - } - public SteeringPath SteeringPath { if (!CanBeSelected) return false; @@ -175,6 +164,12 @@ namespace Barotrauma.Items.Components set { posToMaintain = value; } } + public Vector2? PosToMaintain + { + get { return posToMaintain; } + set { posToMaintain = value; } + } + struct ObstacleDebugInfo { public Vector2 Point1; diff --git a/Barotrauma/BarotraumaShared/Source/Items/Item.cs b/Barotrauma/BarotraumaShared/Source/Items/Item.cs index e83b84678..d5e8140bb 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Item.cs @@ -1139,70 +1139,6 @@ namespace Barotrauma } } - public void UpdateTransform() - { - Submarine prevSub = Submarine; - - FindHull(); - - if (Submarine == null && prevSub != null) - { - body.SetTransform(body.SimPosition + prevSub.SimPosition, body.Rotation); - } - else if (Submarine != null && prevSub == null) - { - body.SetTransform(body.SimPosition - Submarine.SimPosition, body.Rotation); - } - else if (Submarine != null && prevSub != null && Submarine != prevSub) - { - body.SetTransform(body.SimPosition + prevSub.SimPosition - Submarine.SimPosition, body.Rotation); - } - - 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; - - FindHull(); - - if (Submarine == null && prevSub != null) - { - body.SetTransform(body.SimPosition + prevSub.SimPosition, body.Rotation); - } - else if (Submarine != null && prevSub == null) - { - body.SetTransform(body.SimPosition - Submarine.SimPosition, body.Rotation); - } - else if (Submarine != null && prevSub != null && Submarine != prevSub) - { - body.SetTransform(body.SimPosition + prevSub.SimPosition - Submarine.SimPosition, body.Rotation); - } - - 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; @@ -1591,7 +1527,11 @@ namespace Barotrauma if (!picked) return false; - if (picker != null) + if (picker.SelectedConstruction == this) + { + if (picker.IsKeyHit(InputType.Select) || forceSelectKey) picker.SelectedConstruction = null; + } + else if (selected) { if (picker.SelectedConstruction == this) { @@ -2006,7 +1946,6 @@ namespace Barotrauma return Load(element, submarine, createNetworkEvent: false); } - /// /// Instantiate a new item and load its data from the XML element. /// @@ -2019,10 +1958,30 @@ namespace Barotrauma string name = element.Attribute("name").Value; string identifier = element.GetAttributeString("identifier", ""); - ItemPrefab prefab = ItemPrefab.Find(name, identifier); + ItemPrefab prefab; + if (string.IsNullOrEmpty(identifier)) + { + //legacy support: + //1. attempt to find a prefab with an empty identifier and a matching name + prefab = MapEntityPrefab.Find(name, "", showErrorMessages: false) as ItemPrefab; + //2. not found, attempt to find a prefab with a matching name + if (prefab == null) prefab = MapEntityPrefab.Find(name) as ItemPrefab; + } + else + { + prefab = MapEntityPrefab.Find(null, identifier, showErrorMessages: false) as ItemPrefab; + + //not found, see if we can find a prefab with a matching alias + if (prefab == null) + { + string lowerCaseName = name.ToLowerInvariant(); + prefab = MapEntityPrefab.List.Find(me => me.Aliases != null && me.Aliases.Contains(lowerCaseName)) as ItemPrefab; + } + } if (prefab == null) { + DebugConsole.ThrowError("Error loading item - item prefab \"" + name + "\" (identifier \"" + identifier + "\") not found."); return null; } diff --git a/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs b/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs index 9877d9044..faea48579 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; using System.Xml.Linq; using System.Linq; +using Barotrauma.Extensions; namespace Barotrauma { @@ -440,7 +441,6 @@ namespace Barotrauma configFile = filePath; ConfigElement = element; - string nonTranslatedName = element.GetAttributeString("name", ""); identifier = element.GetAttributeString("identifier", ""); //nameidentifier can be used to make multiple items use the same names and descriptions @@ -448,21 +448,20 @@ namespace Barotrauma if (string.IsNullOrEmpty(nameIdentifier)) { - name = TextManager.Get("EntityName." + identifier, true) ?? nonTranslatedName; + name = TextManager.Get("EntityName." + identifier, true) ?? element.GetAttributeString("name", ""); } else { - name = TextManager.Get("EntityName." + nameIdentifier, true) ?? nonTranslatedName; + name = TextManager.Get("EntityName." + nameIdentifier, true) ?? element.GetAttributeString("name", ""); } if (name == "") { DebugConsole.ThrowError("Unnamed item in " + filePath + "!"); } DebugConsole.Log(" " + name); - Aliases = new HashSet - (element.GetAttributeStringArray("aliases", null, convertToLowerInvariant: true) ?? - element.GetAttributeStringArray("Aliases", new string[0], convertToLowerInvariant: true)); - Aliases.Add(nonTranslatedName.ToLowerInvariant()); + Aliases = + element.GetAttributeStringArray("aliases", null, convertToLowerInvariant: true) ?? + element.GetAttributeStringArray("Aliases", new string[0], convertToLowerInvariant: true); if (!Enum.TryParse(element.GetAttributeString("category", "Misc"), true, out MapEntityCategory category)) { @@ -482,7 +481,7 @@ namespace Barotrauma } Tags = new HashSet(element.GetAttributeStringArray("tags", new string[0], convertToLowerInvariant: true)); - if (!Tags.Any()) + if (Tags.None()) { Tags = new HashSet(element.GetAttributeStringArray("Tags", new string[0], convertToLowerInvariant: true)); } @@ -720,42 +719,7 @@ namespace Barotrauma return prices[location.Type.Identifier.ToLowerInvariant()]; } - public static ItemPrefab Find(string name, string identifier) - { - ItemPrefab prefab; - if (string.IsNullOrEmpty(identifier)) - { - //legacy support: - //1. attempt to find a prefab with an empty identifier and a matching name - prefab = Find(name, "", showErrorMessages: false) as ItemPrefab; - //2. not found, attempt to find a prefab with a matching name - if (prefab == null) prefab = Find(name) as ItemPrefab; - //not found, see if we can find a prefab with a matching alias - if (prefab == null) - { - string lowerCaseName = name.ToLowerInvariant(); - prefab = List.Find(me => me.Aliases != null && me.Aliases.Contains(lowerCaseName)) as ItemPrefab; - } - } - else - { - prefab = Find(null, identifier, showErrorMessages: false) as ItemPrefab; - - //not found, see if we can find a prefab with a matching alias - if (prefab == null) - { - string lowerCaseName = name.ToLowerInvariant(); - prefab = List.Find(me => me.Aliases != null && me.Aliases.Contains(lowerCaseName)) as ItemPrefab; - } - } - - if (prefab == null) - { - DebugConsole.ThrowError("Error loading item - item prefab \"" + name + "\" (identifier \"" + identifier + "\") not found."); - } - return prefab; - } public IEnumerable GetPrices() { return prices?.Values; diff --git a/Barotrauma/BarotraumaShared/Source/Map/Hull.cs b/Barotrauma/BarotraumaShared/Source/Map/Hull.cs index d7a563238..711ffa3a7 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Hull.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Hull.cs @@ -78,11 +78,30 @@ namespace Barotrauma private float[] leftDelta; private float[] rightDelta; - - public List ConnectedGaps; public readonly List ConnectedGaps = new List(); + public readonly List ConnectedGaps = new List(); + + 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 string DisplayName + { + get; + private set; + } + private string roomName; [Editable, Serialize("", true, translationTextTag: "RoomName.")] public string RoomName @@ -838,9 +857,6 @@ namespace Barotrauma OxygenPercentage = 100.0f; FireSources = new List(); - linkedTo = new System.Collections.ObjectModel.ObservableCollection(); - - properties = SerializableProperty.GetProperties(this); @@ -1205,93 +1221,36 @@ namespace Barotrauma FireSources.Remove(fire); } - public IEnumerable GetConnectedHulls(int? searchDepth) + private HashSet adjacentHulls = new HashSet(); + public IEnumerable GetConnectedHulls(bool includingThis, int? searchDepth = null) { - return GetAdjacentHulls(new HashSet(), 0, searchDepth); + adjacentHulls.Clear(); + int startStep = 0; + return GetAdjacentHulls(includingThis, adjacentHulls, ref startStep, searchDepth); } - private HashSet GetAdjacentHulls(HashSet connectedHulls, int steps, int? searchDepth) + private HashSet GetAdjacentHulls(bool includingThis, HashSet connectedHulls, ref int step, int? searchDepth) { - if (distance >= maxDistance) return float.MaxValue; - if (this == target) + if (includingThis) { - return distance + Vector2.Distance(startPos, endPos); + connectedHulls.Add(this); + } + if (step > searchDepth.Value) + { + return connectedHulls; } - - connectedHulls.Add(this); - foreach (Gap g in ConnectedGaps) { - if (g.ConnectedDoor != null) - { - //gap blocked if the door is not open or the predicted state is not open - if (!g.ConnectedDoor.IsOpen || (g.ConnectedDoor.PredictedState.HasValue && !g.ConnectedDoor.PredictedState.Value)) - { - if (g.ConnectedDoor.OpenState < 0.1f) continue; - } - } - else if (g.Open <= 0.0f) - { - continue; - } - for (int i = 0; i < 2 && i < g.linkedTo.Count; i++) { if (g.linkedTo[i] is Hull hull && !connectedHulls.Contains(hull)) { - float dist = hull.GetApproximateHullDistance(g.Position, endPos, connectedHulls, target, distance + Vector2.Distance(startPos, g.Position), maxDistance); - if (dist < float.MaxValue) return dist; + step++; + hull.GetAdjacentHulls(true, connectedHulls, ref step, searchDepth); } } } - - return float.MaxValue; - } - - /// - /// Approximate distance from this hull to the target hull, moving through open gaps without passing through walls. - /// Uses a greedy algo and may not use the most optimal path. Returns float.MaxValue if no path is found. - /// - public float GetApproximateDistance(Vector2 startPos, Vector2 endPos, Hull targetHull, float maxDistance) - { - return GetApproximateHullDistance(startPos, endPos, new HashSet(), targetHull, 0.0f, maxDistance); - } - - private float GetApproximateHullDistance(Vector2 startPos, Vector2 endPos, HashSet connectedHulls, Hull target, float distance, float maxDistance) - { - if (distance >= maxDistance) return float.MaxValue; - if (this == target) - { - return distance + Vector2.Distance(startPos, endPos); - } - - connectedHulls.Add(this); - - foreach (Gap g in ConnectedGaps) - { - if (g.ConnectedDoor != null) - { - //gap blocked if the door is not open or the predicted state is not open - if (!g.ConnectedDoor.IsOpen || (g.ConnectedDoor.PredictedState.HasValue && !g.ConnectedDoor.PredictedState.Value)) - { - if (g.ConnectedDoor.OpenState < 0.1f) continue; - } - } - else if (g.Open <= 0.0f) - { - continue; - } - - for (int i = 0; i < 2 && i < g.linkedTo.Count; i++) - { - if (g.linkedTo[i] is Hull hull && !connectedHulls.Contains(hull)) - { - hull.GetAdjacentHulls(connectedHulls, steps++, searchDepth); - } - } - } - - return float.MaxValue; + return connectedHulls; } /// diff --git a/Barotrauma/BarotraumaShared/Source/Map/MapEntity.cs b/Barotrauma/BarotraumaShared/Source/Map/MapEntity.cs index 4e959da6f..84bcce6c5 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/MapEntity.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/MapEntity.cs @@ -20,12 +20,12 @@ namespace Barotrauma protected List linkedToID; //observable collection because some entities may need to be notified when the collection is modified - public ObservableCollection linkedTo; + public readonly ObservableCollection linkedTo = new ObservableCollection(); private bool flippedX, flippedY; public bool FlippedX { get { return flippedX; } } public bool FlippedY { get { return flippedY; } } - + public bool ShouldBeSaved = true; //the position and dimensions of the entity @@ -41,7 +41,7 @@ namespace Barotrauma get { return isHighlighted || ExternalHighlight; } set { isHighlighted = value; } } - + public virtual Rectangle Rect { get { return rect; } @@ -161,7 +161,7 @@ namespace Barotrauma // Quick undo/redo for size and movement only. TODO: Remove if we do a more general implementation. private Memento rectMemento; - public MapEntity(MapEntityPrefab prefab, Submarine submarine) : base(submarine) + public MapEntity(MapEntityPrefab prefab, Submarine submarine) : base(submarine) { this.prefab = prefab; Scale = prefab != null ? prefab.Scale : 1; @@ -289,7 +289,7 @@ namespace Barotrauma mapEntityList.Insert(i, this); } - + /// /// Remove the entity from the entity list without removing links to other entities /// @@ -409,7 +409,7 @@ namespace Barotrauma try { - MethodInfo loadMethod = t.GetMethod("Load", new [] { typeof(XElement), typeof(Submarine) }); + MethodInfo loadMethod = t.GetMethod("Load", new[] { typeof(XElement), typeof(Submarine) }); if (loadMethod == null) { DebugConsole.ThrowError("Could not find the method \"Load\" in " + t + "."); @@ -499,6 +499,38 @@ namespace Barotrauma if (linkedTo.Contains(e)) linkedTo.Remove(e); } + /// + /// Gets all linked entities of specific type. + /// + public HashSet GetLinkedEntities(HashSet list = null, int? maxDepth = null, Func filter = null) where T : MapEntity + { + list = list ?? new HashSet(); + int startDepth = 0; + GetLinkedEntitiesRecursive(this, list, ref startDepth, maxDepth, filter); + return list; + } + + /// + /// Gets all linked entities of specific type. + /// + private static void GetLinkedEntitiesRecursive(MapEntity mapEntity, HashSet linkedTargets, ref int depth, int? maxDepth = null, Func filter = null) + where T : MapEntity + { + if (depth > maxDepth) { return; } + foreach (var linkedEntity in mapEntity.linkedTo) + { + if (linkedEntity is T linkedTarget) + { + if (!linkedTargets.Contains(linkedTarget) && (filter == null || filter(linkedTarget))) + { + linkedTargets.Add(linkedTarget); + depth++; + GetLinkedEntitiesRecursive(linkedEntity, linkedTargets, ref depth, maxDepth, filter); + } + } + } + } + #region Serialized properties // We could use NaN or nullables, but in this case the first is not preferable, because it needs to be checked every time the value is used. // Nullable on the other requires boxing that we don't want to do too often, since it generates garbage. diff --git a/Barotrauma/BarotraumaShared/Source/Map/MapEntityPrefab.cs b/Barotrauma/BarotraumaShared/Source/Map/MapEntityPrefab.cs index 7e308f7f4..664a9173d 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/MapEntityPrefab.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/MapEntityPrefab.cs @@ -115,7 +115,6 @@ namespace Barotrauma Linkable = true }; ep.AllowedLinks.Add("hull"); - ep.Aliases = new HashSet { "hull" }; List.Add(ep); ep = new MapEntityPrefab diff --git a/Barotrauma/BarotraumaShared/Source/Map/StructurePrefab.cs b/Barotrauma/BarotraumaShared/Source/Map/StructurePrefab.cs index 6105b453b..336bd33a6 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/StructurePrefab.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/StructurePrefab.cs @@ -225,6 +225,12 @@ namespace Barotrauma string nonTranslatedName = element.GetAttributeString("name", null) ?? element.Name.ToString(); sp.Aliases.Add(nonTranslatedName.ToLowerInvariant()); + SerializableProperty.DeserializeProperties(sp, element); + if (sp.Body) + { + sp.Tags.Add("wall"); + } + SerializableProperty.DeserializeProperties(sp, element); if (sp.Body) { diff --git a/Barotrauma/BarotraumaShared/Source/Networking/ChatMessage.cs b/Barotrauma/BarotraumaShared/Source/Networking/ChatMessage.cs index 609348ce7..e40d6c714 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/ChatMessage.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/ChatMessage.cs @@ -131,12 +131,7 @@ namespace Barotrauma.Networking float dist = Vector2.Distance(listener.WorldPosition, sender.WorldPosition); if (dist > range) { return 1.0f; } - Hull listenerHull = listener == null ? null : Hull.FindHull(listener.WorldPosition); - Hull sourceHull = sender == null ? null : Hull.FindHull(sender.WorldPosition); - if (sourceHull != listenerHull) - { - if (Submarine.CheckVisibility(listener.SimPosition, sender.SimPosition) != null) dist = (dist + 100f) * obstructionmult; - } + if (Submarine.CheckVisibility(listener.SimPosition, sender.SimPosition) != null) dist = (dist + 100f) * obstructionmult; if (dist > range) { return 1.0f; } return dist / range; diff --git a/Barotrauma/BarotraumaShared/Submarines/Bunyip.sub b/Barotrauma/BarotraumaShared/Submarines/Bunyip.sub index c186e63ad..e6adeedd5 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Bunyip.sub and b/Barotrauma/BarotraumaShared/Submarines/Bunyip.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Dugong.sub b/Barotrauma/BarotraumaShared/Submarines/Dugong.sub index 4572c25d7..bbf0b0d3e 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Dugong.sub and b/Barotrauma/BarotraumaShared/Submarines/Dugong.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Humpback.sub b/Barotrauma/BarotraumaShared/Submarines/Humpback.sub index 7eb668411..0fc545445 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Humpback.sub and b/Barotrauma/BarotraumaShared/Submarines/Humpback.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Orca.sub b/Barotrauma/BarotraumaShared/Submarines/Orca.sub index f4dd57ac0..324b50fa4 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Orca.sub and b/Barotrauma/BarotraumaShared/Submarines/Orca.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Remora.sub b/Barotrauma/BarotraumaShared/Submarines/Remora.sub index 1d06b7947..32f4d725c 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Remora.sub and b/Barotrauma/BarotraumaShared/Submarines/Remora.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Selkie.sub b/Barotrauma/BarotraumaShared/Submarines/Selkie.sub index 2b0082dd4..dcef9aa2c 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Selkie.sub and b/Barotrauma/BarotraumaShared/Submarines/Selkie.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Typhon.sub b/Barotrauma/BarotraumaShared/Submarines/Typhon.sub index 4a0fe1857..e60780866 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Typhon.sub and b/Barotrauma/BarotraumaShared/Submarines/Typhon.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Venture.sub b/Barotrauma/BarotraumaShared/Submarines/Venture.sub index ce2074cc1..a8a7c3e21 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Venture.sub and b/Barotrauma/BarotraumaShared/Submarines/Venture.sub differ diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index c2d283eb7..1a241fb5f 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,19 +1,3 @@ ---------------------------------------------------------------------------------------------------------- -v0.9.0.1 ---------------------------------------------------------------------------------------------------------- - -- Added a bunch of missing translations. -- Fixed Steam Workshop on Mac. -- Fixed docking interface button not working in the multiplayer. -- Fixed medical doctor tutorial crashing on languages other than English. -- Fixed a bug that caused AI characters to occasionally get stuck next to stairways. -- Fixed animation and ragdoll file paths getting messed up if there are multiple content packages -installed that include monsters with the same name. -- Fixed crashing when a StatusEffect causes an item to be used on a target. -- Fixed a gap between Remora and the drone. -- Added more supplies to Remora. -- Fixed watchman's dialogue getting muffled. - --------------------------------------------------------------------------------------------------------- v0.9.0.0 ---------------------------------------------------------------------------------------------------------