diff --git a/Barotrauma/BarotraumaClient/ClientSource/Camera.cs b/Barotrauma/BarotraumaClient/ClientSource/Camera.cs index 8d7e7d4e0..f0182f806 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Camera.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Camera.cs @@ -338,15 +338,18 @@ namespace Barotrauma previousOffset = offset; } - //how much to zoom out (zoom completely out when offset is 1000) - float zoomOutAmount = GetZoomAmount(offset); - //scaled zoom amount - float scaledZoom = MathHelper.Lerp(DefaultZoom, MinZoom, zoomOutAmount) * globalZoomScale; - //zoom in further if zoomOutAmount is low and resolution is lower than reference - float newZoom = scaledZoom * (MathHelper.Lerp(0.3f * (1f - Math.Min(globalZoomScale, 1f)), 0f, - (GameMain.Config == null || GameMain.Config.EnableMouseLook) ? (float)Math.Sqrt(offsetUnscaledLen) : 0.3f) + 1f); + if (allowZoom) + { + //how much to zoom out (zoom completely out when offset is 1000) + float zoomOutAmount = GetZoomAmount(offset); + //scaled zoom amount + float scaledZoom = MathHelper.Lerp(DefaultZoom, MinZoom, zoomOutAmount) * globalZoomScale; + //zoom in further if zoomOutAmount is low and resolution is lower than reference + float newZoom = scaledZoom * (MathHelper.Lerp(0.3f * (1f - Math.Min(globalZoomScale, 1f)), 0f, + (GameMain.Config == null || GameMain.Config.EnableMouseLook) ? (float)Math.Sqrt(offsetUnscaledLen) : 0.3f) + 1f); - Zoom += (newZoom - zoom) / ZoomSmoothness; + Zoom += (newZoom - zoom) / ZoomSmoothness; + } //force targetzoom to the current zoom value, so the camera stays at the same zoom when switching to freecam targetZoom = Zoom; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/Character.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/Character.cs index 3ee39ef88..fb1cd7d6b 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/Character.cs @@ -332,7 +332,7 @@ namespace Barotrauma { cam.OffsetAmount = targetOffsetAmount = 0.0f; cursorPosition = - SelectedConstruction.Position + + Position + PlayerInput.MouseSpeed.ClampLength(10.0f); //apply a little bit of movement to the cursor pos to prevent AFK kicking } else if (!GameMain.Config.EnableMouseLook) @@ -1096,6 +1096,7 @@ namespace Barotrauma private SoundChannel soundChannel; public void PlaySound(CharacterSound.SoundType soundType, float soundIntervalFactor = 1.0f, float maxInterval = 0) { + if (Removed) { return; } if (sounds == null || sounds.Count == 0) { return; } if (soundChannel != null && soundChannel.IsPlaying) { return; } if (GameMain.SoundManager?.Disabled ?? true) { return; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs index 5897105f1..1c618e46e 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs @@ -452,11 +452,17 @@ namespace Barotrauma ushort itemID = msg.ReadUInt16(); if (!(Entity.FindEntityByID(itemID) is Item item)) { continue; } item.AllowStealing = true; - var wifiComponent = item.GetComponent(); + var wifiComponent = item.GetComponent(); if (wifiComponent != null) { wifiComponent.TeamID = teamID; } + var idCard = item.GetComponent(); + if (idCard != null) + { + idCard.TeamID = teamID; + idCard.SubmarineSpecificID = 0; + } } break; case 10: //NetEntityEvent.Type.UpdateExperience diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/Jobs/JobPrefab.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/Jobs/JobPrefab.cs index f4ceb3ce9..248bbe71d 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/Jobs/JobPrefab.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/Jobs/JobPrefab.cs @@ -83,7 +83,13 @@ namespace Barotrauma var equipIdentifiers = Element.GetChildElements("ItemSet").Elements().Where(e => e.GetAttributeBool("outfit", false)).Select(e => e.GetAttributeString("identifier", "")); - var outfitPrefabs = ItemPrefab.Prefabs.Where(itemPrefab => equipIdentifiers.Contains(itemPrefab.Identifier)).ToList(); + List outfitPrefabs = new List(); + foreach (var equipIdentifier in equipIdentifiers) + { + var itemPrefab = ItemPrefab.Prefabs.Find(ip => ip.Identifier == equipIdentifier); + if (itemPrefab != null) { outfitPrefabs.Add(itemPrefab); } + } + if (!outfitPrefabs.Any()) { return null; } for (int i = 0; i < outfitPrefabs.Count; i++) diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIListBox.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIListBox.cs index 2a010e707..87bfe9d98 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIListBox.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIListBox.cs @@ -770,8 +770,13 @@ namespace Barotrauma BarScroll += speed * Math.Sign(diff) / TotalSize; } } - - if (PlayerInput.ScrollWheelSpeed != 0 && AllowMouseWheelScroll && (FindScrollableParentListBox(GUI.MouseOn) == this || GUI.IsMouseOn(ScrollBar))) + + bool IsMouseOn() => + FindScrollableParentListBox(GUI.MouseOn) == this || + GUI.IsMouseOn(ScrollBar) || + (CanInteractWhenUnfocusable && Content.Rect.Contains(PlayerInput.MousePosition)); + + if (PlayerInput.ScrollWheelSpeed != 0 && AllowMouseWheelScroll && IsMouseOn()) { if (SmoothScroll) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/SinglePlayerCampaign.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/SinglePlayerCampaign.cs index c51a4a68d..3aa3f47ea 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/SinglePlayerCampaign.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/SinglePlayerCampaign.cs @@ -463,7 +463,6 @@ namespace Barotrauma { SubmarineInfo previousSub = GameMain.GameSession.SubmarineInfo; GameMain.GameSession.SubmarineInfo = PendingSubmarineSwitch; - PendingSubmarineSwitch = null; for (int i = 0; i < GameMain.GameSession.OwnedSubmarines.Count; i++) { @@ -476,6 +475,7 @@ namespace Barotrauma } SaveUtil.SaveGame(GameMain.GameSession.SavePath); + PendingSubmarineSwitch = null; } else { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/CharacterInventory.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/CharacterInventory.cs index 2e3782d15..9257d4209 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/CharacterInventory.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/CharacterInventory.cs @@ -516,6 +516,9 @@ namespace Barotrauma } } + private readonly static List hideSubInventories = new List(); + private readonly static List tempHighlightedSubInventorySlots = new List(); + public override void Update(float deltaTime, Camera cam, bool isSubInventory = false) { if (!AccessibleWhenAlive && !character.IsDead) @@ -579,15 +582,17 @@ namespace Barotrauma } } } - - List hideSubInventories = new List(); + + hideSubInventories.Clear(); //remove highlighted subinventory slots that can no longer be accessed highlightedSubInventorySlots.RemoveWhere(s => s.ParentInventory == this && ((s.SlotIndex < 0 || s.SlotIndex >= slots.Length || slots[s.SlotIndex] == null) || (Character.Controlled != null && !Character.Controlled.CanAccessInventory(s.Inventory)))); //remove highlighted subinventory slots that refer to items no longer in this inventory highlightedSubInventorySlots.RemoveWhere(s => s.Item != null && s.ParentInventory == this && s.Item.ParentInventory != this); - foreach (var highlightedSubInventorySlot in highlightedSubInventorySlots) + tempHighlightedSubInventorySlots.Clear(); + tempHighlightedSubInventorySlots.AddRange(highlightedSubInventorySlots); + foreach (var highlightedSubInventorySlot in tempHighlightedSubInventorySlots) { if (highlightedSubInventorySlot.ParentInventory == this) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Fabricator.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Fabricator.cs index 53c770df7..7da3659a6 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Fabricator.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Fabricator.cs @@ -300,6 +300,8 @@ namespace Barotrauma.Items.Components { requiresRecipeText.RectTransform.RepositionChildInHierarchy(itemList.Content.RectTransform.GetChildIndex(firstRequiresRecipe.RectTransform)); } + + HideEmptyItemListCategories(); } private void DrawInputOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent) @@ -479,6 +481,13 @@ namespace Barotrauma.Items.Components child.Visible = recipe.DisplayName.ToLower().Contains(filter); } + HideEmptyItemListCategories(); + + return true; + } + + private void HideEmptyItemListCategories() + { //go through the elements backwards, and disable the labels ("insufficient skills to fabricate", "recipe required...") if there's no items below them bool recipeVisible = false; foreach (GUIComponent child in itemList.Content.Children.Reverse()) @@ -490,14 +499,12 @@ namespace Barotrauma.Items.Components } else { - recipeVisible = child.Visible; + recipeVisible |= child.Visible; } } itemList.UpdateScrollBarSize(); itemList.BarScroll = 0.0f; - - return true; } public bool ClearFilter() diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/MiniMap.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/MiniMap.cs index 890b2910a..5e0ff3193 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/MiniMap.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/MiniMap.cs @@ -36,7 +36,7 @@ namespace Barotrauma.Items.Components internal readonly struct MiniMapSprite { - public readonly Sprite Sprite; + public readonly Sprite? Sprite; public readonly Color Color; public MiniMapSprite(JobPrefab prefab) @@ -1302,6 +1302,8 @@ namespace Barotrauma.Items.Components int i = 0; foreach (MiniMapSprite info in cardsToDraw) { + if (info.Sprite is null) { continue; } + float spriteSize = info.Sprite.size.X * (parentWidth / info.Sprite.size.X) + padding; if (totalWidth + spriteSize > frame.Rect.Width) { break; } @@ -1318,7 +1320,8 @@ namespace Barotrauma.Items.Components foreach (MiniMapSprite info in cardsToDraw) { - Sprite sprite = info.Sprite; + Sprite? sprite = info.Sprite; + if (sprite is null) { continue; } float scale = parentWidth / sprite.size.X; float spriteSize = sprite.size.X * scale; float posX = adjustedCenterX + offset; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Rope.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Rope.cs index 25d45c773..436e99507 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Rope.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Rope.cs @@ -88,7 +88,7 @@ namespace Barotrauma.Items.Components Vector2 startPos = GetSourcePos(); startPos.Y = -startPos.Y; - if (source is Item sourceItem) + if (source is Item sourceItem && !sourceItem.Removed) { var turret = sourceItem.GetComponent(); var weapon = sourceItem.GetComponent(); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs index a8d965902..2b50d7e4a 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs @@ -540,7 +540,7 @@ namespace Barotrauma } }*/ - bool mouseOn = interactRect.Contains(PlayerInput.MousePosition) && !Locked && !mouseOnGUI && !slot.Disabled; + bool mouseOn = interactRect.Contains(PlayerInput.MousePosition) && !Locked && !mouseOnGUI && !slot.Disabled && IsMouseOnInventory; // Delete item from container in sub editor if (SubEditorScreen.IsSubEditor() && PlayerInput.IsCtrlDown()) @@ -863,6 +863,8 @@ namespace Barotrauma { return false; } + if (GameSession.IsTabMenuOpen) { return false; } + if (CrewManager.IsCommandInterfaceOpen) { return false; } if (Character.Controlled == null) { return false; } @@ -1313,6 +1315,10 @@ namespace Barotrauma private static bool CanSelectSlot(SlotReference selectedSlot) { + if (!IsMouseOnInventory) + { + return false; + } if (!selectedSlot.Slot.MouseOn()) { return false; @@ -1335,7 +1341,8 @@ namespace Barotrauma if ((parentItem?.GetRootInventoryOwner() is Character ownerCharacter) && ownerCharacter == Character.Controlled && CharacterHealth.OpenHealthWindow?.Character != ownerCharacter && - ownerCharacter.Inventory.IsInLimbSlot(parentItem, InvSlotType.HealthInterface)) + ownerCharacter.Inventory.IsInLimbSlot(parentItem, InvSlotType.HealthInterface) && + Screen.Selected != GameMain.SubEditorScreen) { highlightedSubInventorySlots.RemoveWhere(s => s.Item == parentItem); return false; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Item.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Item.cs index 900731c83..eab3b9777 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Item.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Item.cs @@ -543,6 +543,7 @@ namespace Barotrauma partial void OnCollisionProjSpecific(float impact) { if (impact > 1.0f && + Container == null && !string.IsNullOrEmpty(Prefab.ImpactSoundTag) && Timing.TotalTime > LastImpactSoundTime + ImpactSoundInterval) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/Explosion.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/Explosion.cs index 57d7b3e44..070748dfb 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/Explosion.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/Explosion.cs @@ -98,12 +98,10 @@ namespace Barotrauma private IEnumerable DimLight(LightSource light) { float currBrightness = 1.0f; - float startRange = light.Range; - while (light.Color.A > 0.0f && flashDuration > 0.0f) { - light.Color = new Color(light.Color.R, light.Color.G, light.Color.B, currBrightness); - currBrightness -= (1.0f / flashDuration) * CoroutineManager.DeltaTime; + light.Color = new Color(light.Color.R, light.Color.G, light.Color.B, (byte)(currBrightness * 255)); + currBrightness -= 1.0f / flashDuration * CoroutineManager.DeltaTime; yield return CoroutineStatus.Running; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightManager.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightManager.cs index 8ad1a0596..f178bf7f5 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightManager.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightManager.cs @@ -529,7 +529,7 @@ namespace Barotrauma.Lights graphics.Clear(Color.Black); Vector2 diff = lookAtPosition - ViewTarget.WorldPosition; diff.Y = -diff.Y; - if (diff.LengthSquared() > 30.0f) { losOffset = diff; } + if (diff.LengthSquared() > 20.0f * 20.0f) { losOffset = diff; } float rotation = MathUtils.VectorToAngle(losOffset); Vector2 scale = new Vector2( diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/ChatMessage.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/ChatMessage.cs index 67c758aa6..d76d85470 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/ChatMessage.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/ChatMessage.cs @@ -64,7 +64,18 @@ namespace Barotrauma.Networking string orderOption = orderMessageInfo.OrderOption; orderOption ??= orderMessageInfo.OrderOptionIndex.HasValue && orderMessageInfo.OrderOptionIndex >= 0 && orderMessageInfo.OrderOptionIndex < orderPrefab.Options.Length ? orderPrefab.Options[orderMessageInfo.OrderOptionIndex.Value] : ""; - txt = orderPrefab.GetChatMessage(orderMessageInfo.TargetCharacter?.Name, senderCharacter?.CurrentHull?.DisplayName, + string targetRoom; + + if (orderMessageInfo.TargetEntity is Hull targetHull) + { + targetRoom = targetHull.DisplayName; + } + else + { + targetRoom = senderCharacter?.CurrentHull?.DisplayName; + } + + txt = orderPrefab.GetChatMessage(orderMessageInfo.TargetCharacter?.Name, targetRoom, givingOrderToSelf: orderMessageInfo.TargetCharacter == senderCharacter, orderOption: orderOption, priority: orderMessageInfo.Priority); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Program.cs b/Barotrauma/BarotraumaClient/ClientSource/Program.cs index b8beb4aa6..23a9d554d 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Program.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Program.cs @@ -1,6 +1,7 @@ #region Using Statements using System; +using System.Collections.Generic; using Barotrauma.IO; using System.Linq; using System.Text; @@ -132,8 +133,11 @@ namespace Barotrauma { XElement newElement = new XElement(doc.Root.Name); newElement.Add(doc.Root.Attributes()); - newElement.Add(doc.Root.Elements().Where(e => !e.Name.LocalName.Equals("contentpackage", StringComparison.InvariantCultureIgnoreCase))); - newElement.Add(baseDoc.Root.Elements().Where(e => e.Name.LocalName.Equals("contentpackage", StringComparison.InvariantCultureIgnoreCase))); + string[] contentPackageTags = { "contentpackage", "contentpackages" }; + bool elementNameMatches(XElement element) + => contentPackageTags.Any(t => element.Name.LocalName.Equals(t, StringComparison.InvariantCultureIgnoreCase)); + newElement.Add(doc.Root.Elements().Where(e => !elementNameMatches(e))); + newElement.Add(baseDoc.Root.Elements().Where(e => elementNameMatches(e))); XDocument newDoc = new XDocument(newElement); newDoc.Save(GameSettings.PlayerSavePath); sb.AppendLine("To prevent further startup errors, installed mods will be disabled the next time you launch the game."); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs index e72eb2623..76be7c17f 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs @@ -866,6 +866,8 @@ namespace Barotrauma return true; } + CloseItem(); + backedUpSubInfo = new SubmarineInfo(Submarine.MainSub); GameMain.GameScreen.Select(); @@ -1328,6 +1330,8 @@ namespace Barotrauma { base.Deselect(); + CloseItem(); + autoSaveLabel?.Parent?.RemoveChild(autoSaveLabel); autoSaveLabel = null; @@ -3057,9 +3061,24 @@ namespace Barotrauma new ContextMenuOption("SubEditor.PasteAssembly", isEnabled: true, () => PasteAssembly()), new ContextMenuOption("Editor.SelectSame", isEnabled: targets.Count > 0, onSelected: delegate { + bool doorGapSelected = targets.Any(t => t is Gap gap && gap.ConnectedDoor != null); foreach (MapEntity match in MapEntity.mapEntityList.Where(e => e.prefab != null && targets.Any(t => t.prefab?.Identifier == e.prefab.Identifier) && !MapEntity.SelectedList.Contains(e))) { if (MapEntity.SelectedList.Contains(match)) { continue; } + if (match is Gap gap) + { + //don't add non-door gaps if we've selected a door gap (and vice versa) + if ((gap.ConnectedDoor == null) == doorGapSelected) { continue; } + } + else if (match is Item item) + { + //add door gaps too if we're selecting doors + var door = item.GetComponent(); + if (door?.LinkedGap != null && !MapEntity.SelectedList.Contains(door.LinkedGap)) + { + MapEntity.SelectedList.Add(door.LinkedGap); + } + } MapEntity.SelectedList.Add(match); } }), @@ -4171,6 +4190,11 @@ namespace Barotrauma UpdateEntityList(); } + if (OpenedItem != null && OpenedItem.Removed) + { + OpenedItem = null; + } + if (WiringMode && dummyCharacter != null) { Wire equippedWire = diff --git a/Barotrauma/BarotraumaClient/ClientSource/Sounds/SoundPlayer.cs b/Barotrauma/BarotraumaClient/ClientSource/Sounds/SoundPlayer.cs index 172454cc2..377de997b 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Sounds/SoundPlayer.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Sounds/SoundPlayer.cs @@ -960,7 +960,7 @@ namespace Barotrauma targetMusic[i] = null; break; } - musicChannel[i] = currentMusic[i].Play(0.0f, i == noiseLoopIndex ? "" : "music"); + musicChannel[i] = currentMusic[i].Play(0.0f, i == noiseLoopIndex ? "default" : "music"); if (targetMusic[i].ContinueFromPreviousTime) { musicChannel[i].StreamSeekPos = targetMusic[i].PreviousTime; @@ -974,7 +974,7 @@ namespace Barotrauma if (musicChannel[i] == null || !musicChannel[i].IsPlaying) { musicChannel[i]?.Dispose(); - musicChannel[i] = currentMusic[i].Play(0.0f, i == noiseLoopIndex ? "" : "music"); + musicChannel[i] = currentMusic[i].Play(0.0f, i == noiseLoopIndex ? "default" : "music"); musicChannel[i].Looping = true; } float targetGain = targetMusic[i].Volume; diff --git a/Barotrauma/BarotraumaClient/LinuxClient.csproj b/Barotrauma/BarotraumaClient/LinuxClient.csproj index 2ab72e41c..5b8084010 100644 --- a/Barotrauma/BarotraumaClient/LinuxClient.csproj +++ b/Barotrauma/BarotraumaClient/LinuxClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.15.12.0 + 0.15.13.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/MacClient.csproj b/Barotrauma/BarotraumaClient/MacClient.csproj index 8ed473dd0..0eda78d04 100644 --- a/Barotrauma/BarotraumaClient/MacClient.csproj +++ b/Barotrauma/BarotraumaClient/MacClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.15.12.0 + 0.15.13.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/WindowsClient.csproj b/Barotrauma/BarotraumaClient/WindowsClient.csproj index c8d71c037..a09d8c2d7 100644 --- a/Barotrauma/BarotraumaClient/WindowsClient.csproj +++ b/Barotrauma/BarotraumaClient/WindowsClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.15.12.0 + 0.15.13.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaServer/LinuxServer.csproj b/Barotrauma/BarotraumaServer/LinuxServer.csproj index a08658e40..e0eefab46 100644 --- a/Barotrauma/BarotraumaServer/LinuxServer.csproj +++ b/Barotrauma/BarotraumaServer/LinuxServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.15.12.0 + 0.15.13.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/MacServer.csproj b/Barotrauma/BarotraumaServer/MacServer.csproj index 168d57971..44c6758d0 100644 --- a/Barotrauma/BarotraumaServer/MacServer.csproj +++ b/Barotrauma/BarotraumaServer/MacServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.15.12.0 + 0.15.13.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/ServerSource/DebugConsole.cs b/Barotrauma/BarotraumaServer/ServerSource/DebugConsole.cs index 2b9b3f857..ae7c4e523 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/DebugConsole.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/DebugConsole.cs @@ -1585,6 +1585,10 @@ namespace Barotrauma tpCharacter.Submarine = null; tpCharacter.AnimController.SetPosition(ConvertUnits.ToSimUnits(cursorWorldPos)); tpCharacter.AnimController.FindHull(cursorWorldPos, true); + if (tpCharacter.AIController?.SteeringManager is IndoorsSteeringManager pathSteering) + { + pathSteering.ResetPath(); + } } ); diff --git a/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs b/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs index 7dafc70d0..d3c2fbed0 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs @@ -202,13 +202,11 @@ namespace Barotrauma public void SavePlayers() { - List prevCharacterData = new List(characterData); - //client character has spawned this round -> remove old data (and replace with an up-to-date one if the client still has a character) - characterData.RemoveAll(cd => cd.HasSpawned); - //refresh the character data of clients who are still in the server foreach (Client c in GameMain.Server.ConnectedClients) { + //ignore if the character is controlling a monster + //(we'll just use the previously saved campaign data if there's any) if (c.Character != null && c.Character.Info == null) { c.Character = null; @@ -225,25 +223,30 @@ namespace Barotrauma continue; } } - var characterInfo = c.Character?.Info ?? c.CharacterInfo; + //use the info of the character the client is currently controlling + // or the previously saved info if not (e.g. if the client has been spectating or died) + var characterInfo = c.Character?.Info ?? characterData.Find(d => d.MatchesClient(c))?.CharacterInfo; if (characterInfo == null) { continue; } - if (c.CharacterInfo.CauseOfDeath != null && characterInfo.CauseOfDeath.Type != CauseOfDeathType.Disconnected) + //reduce skills if the character has died + if (characterInfo.CauseOfDeath != null && characterInfo.CauseOfDeath.Type != CauseOfDeathType.Disconnected) { RespawnManager.ReduceCharacterSkills(characterInfo); } c.CharacterInfo = characterInfo; characterData.RemoveAll(cd => cd.MatchesClient(c)); - characterData.Add(new CharacterCampaignData(c)); + characterData.Add(new CharacterCampaignData(c)); } //refresh the character data of clients who aren't in the server anymore + List prevCharacterData = new List(characterData); foreach (CharacterCampaignData data in prevCharacterData) { - if (data.HasSpawned && !characterData.Any(cd => cd.IsDuplicate(data))) + if (data.HasSpawned && !GameMain.Server.ConnectedClients.Any(c => data.MatchesClient(c))) { var character = Character.CharacterList.Find(c => c.Info == data.CharacterInfo && !c.IsHusk); if (character != null && (!character.IsDead || character.CauseOfDeath?.Type == CauseOfDeathType.Disconnected)) { + characterData.RemoveAll(cd => cd.IsDuplicate(data)); data.Refresh(character); characterData.Add(data); } @@ -345,7 +348,6 @@ namespace Barotrauma { SubmarineInfo previousSub = GameMain.GameSession.SubmarineInfo; GameMain.GameSession.SubmarineInfo = PendingSubmarineSwitch; - PendingSubmarineSwitch = null; for (int i = 0; i < GameMain.GameSession.OwnedSubmarines.Count; i++) { @@ -358,6 +360,7 @@ namespace Barotrauma } SaveUtil.SaveGame(GameMain.GameSession.SavePath); + PendingSubmarineSwitch = null; } else { diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs index 1ed8e43cc..4425cbc2d 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs @@ -202,7 +202,7 @@ namespace Barotrauma.Networking GameMain.NetLobbyScreen.Select(); GameMain.NetLobbyScreen.RandomizeSettings(); - if (!string.IsNullOrEmpty(serverSettings.SelectedSubmarine)) + if (!string.IsNullOrEmpty(serverSettings.SelectedSubmarine)) { SubmarineInfo sub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == serverSettings.SelectedSubmarine); if (sub != null) { GameMain.NetLobbyScreen.SelectedSub = sub; } @@ -536,7 +536,7 @@ namespace Barotrauma.Networking initiatedStartGame = false; } } - else if (Screen.Selected == GameMain.NetLobbyScreen && !gameStarted && !initiatedStartGame && + else if (Screen.Selected == GameMain.NetLobbyScreen && !gameStarted && !initiatedStartGame && (GameMain.NetLobbyScreen.SelectedMode != GameModePreset.MultiPlayerCampaign || GameMain.GameSession?.GameMode is MultiPlayerCampaign)) { if (serverSettings.AutoRestart) @@ -970,9 +970,9 @@ namespace Barotrauma.Networking { var spawnData = entityEvent.Data[0] as EntitySpawner.SpawnOrRemove; errorLines.Add( - entityEvent.ID + ": " + - (spawnData.Remove ? "Remove " : "Create ") + - spawnData.Entity.ToString() + + entityEvent.ID + ": " + + (spawnData.Remove ? "Remove " : "Create ") + + spawnData.Entity.ToString() + " (" + spawnData.OriginalID + ", " + spawnData.Entity.ID + ")"); } } @@ -1221,7 +1221,7 @@ namespace Barotrauma.Networking sender.WaitForNextRoundRespawn = null; } } - + private void ClientReadServerCommand(IReadMessage inc) { Client sender = ConnectedClients.Find(x => x.Connection == inc.Sender); @@ -1326,7 +1326,7 @@ namespace Barotrauma.Networking GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine); SaveUtil.SaveGame(GameMain.GameSession.SavePath); } - EndGame(); + EndGame(); } } else @@ -1457,7 +1457,7 @@ namespace Barotrauma.Networking } break; case ClientPermissions.ManageCampaign: - (GameMain.GameSession.GameMode as MultiPlayerCampaign)?.ServerRead(inc, sender); + (GameMain.GameSession.GameMode as MultiPlayerCampaign)?.ServerRead(inc, sender); break; case ClientPermissions.ConsoleCommands: { @@ -1813,7 +1813,7 @@ namespace Barotrauma.Networking outmsg.Write(client.InGame); outmsg.Write(client.Permissions != ClientPermissions.None); outmsg.Write(client.Connection == OwnerConnection); - outmsg.Write(client.Connection != OwnerConnection && + outmsg.Write(client.Connection != OwnerConnection && !client.HasPermission(ClientPermissions.Ban) && !client.HasPermission(ClientPermissions.Kick) && !client.HasPermission(ClientPermissions.Unban)); //is kicking the player allowed @@ -2193,8 +2193,8 @@ namespace Barotrauma.Networking bool isOutpost = campaign != null && campaign.NextLevel?.Type == LevelData.LevelType.Outpost; if (serverSettings.AllowRespawn && missionAllowRespawn) - { - respawnManager = new RespawnManager(this, serverSettings.UseRespawnShuttle && !isOutpost ? selectedShuttle : null); + { + respawnManager = new RespawnManager(this, serverSettings.UseRespawnShuttle && !isOutpost ? selectedShuttle : null); } if (campaign != null) { @@ -2286,7 +2286,7 @@ namespace Barotrauma.Networking } AssignBotJobs(bots, teamID); - if (campaign != null) + if (campaign != null) { foreach (CharacterInfo bot in bots) { @@ -2303,7 +2303,7 @@ namespace Barotrauma.Networking List spawnWaypoints = null; List mainSubWaypoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSubs[n]).ToList(); - if (Level.Loaded?.StartOutpost != null && + if (Level.Loaded?.StartOutpost != null && Level.Loaded.Type == LevelData.LevelType.Outpost && (Level.Loaded.StartOutpost.Info.OutpostGenerationParams?.SpawnCrewInsideOutpost ?? false) && Level.Loaded.StartOutpost.GetConnectedSubs().Any(s => s.Info.Type == SubmarineType.Player)) @@ -2805,7 +2805,7 @@ namespace Barotrauma.Networking //reset karma to a neutral value, so if/when the ban is revoked the client wont get immediately punished by low karma again previousPlayer.Karma = Math.Max(previousPlayer.Karma, 50.0f); - + if (!string.IsNullOrEmpty(previousPlayer.EndPoint) && (previousPlayer.SteamID == 0 || range)) { string ip = previousPlayer.EndPoint; @@ -3142,7 +3142,7 @@ namespace Barotrauma.Networking modifiedMessage, (ChatMessageType)type, senderCharacter, - senderClient, + senderClient, changeType); SendDirectChatMessage(chatMsg, client); @@ -3435,7 +3435,7 @@ namespace Barotrauma.Networking { newCharacter.LastNetworkUpdateID = client.Character.LastNetworkUpdateID; } - + if (newCharacter.Info != null && newCharacter.Info.Character == null) { newCharacter.Info.Character = newCharacter; @@ -3599,7 +3599,6 @@ namespace Barotrauma.Networking List availableSpawnPoints = WayPoint.WayPointList.FindAll(wp => wp.SpawnType == SpawnType.Human && wp.Submarine != null && wp.Submarine.TeamID == teamID); - List unassignedSpawnPoints = new List(availableSpawnPoints); /*bool canAssign = false; do @@ -3627,10 +3626,8 @@ namespace Barotrauma.Networking // First evaluate all the primary preferences, then all the secondary etc. for (int preferenceIndex = 0; preferenceIndex < 3; preferenceIndex++) { - if (unassignedSpawnPoints.None()) { break; } for (int i = unassigned.Count - 1; i >= 0; i--) { - if (unassignedSpawnPoints.None()) { break; } Client client = unassigned[i]; if (preferenceIndex >= client.JobPreferences.Count) { continue; } var preferredJob = client.JobPreferences[preferenceIndex]; @@ -3640,21 +3637,10 @@ namespace Barotrauma.Networking //can't assign this job if maximum number has reached or the clien't karma is too low continue; } - //give the client their preferred job if there's a spawnpoint available for that job - var matchingSpawnPoint = unassignedSpawnPoints.Find(s => s.AssignedJob == jobPrefab); - if (matchingSpawnPoint == null && !availableSpawnPoints.Any(s => s.AssignedJob == jobPrefab)) - { - //if the job is not available in any spawnpoint (custom job?), treat empty spawnpoints - //as a matching ones - matchingSpawnPoint = unassignedSpawnPoints.Find(s => s.AssignedJob == null); - } - if (matchingSpawnPoint != null) - { - unassignedSpawnPoints.Remove(matchingSpawnPoint); - client.AssignedJob = preferredJob; - assignedClientCount[jobPrefab]++; - unassigned.RemoveAt(i); - } + + client.AssignedJob = preferredJob; + assignedClientCount[jobPrefab]++; + unassigned.RemoveAt(i); } } @@ -3689,7 +3675,7 @@ namespace Barotrauma.Networking { c.AssignedJob = preferredJob; assignedClientCount[preferredJob.First]++; - break; + break; } } else //none of the client's preferred jobs available, choose a random job @@ -3746,10 +3732,10 @@ namespace Barotrauma.Networking unassignedBots[0].Job = new Job(jobPrefab, variant); assignedPlayerCount[jobPrefab]++; unassignedBots.Remove(unassignedBots[0]); - canAssign = true; + canAssign = true; } } while (unassignedBots.Count > 0 && canAssign); - + //find a suitable job for the rest of the bots foreach (CharacterInfo c in unassignedBots) { @@ -3857,7 +3843,7 @@ namespace Barotrauma.Networking string submarinesString = string.Empty; for (int i = 0; i < GameMain.NetLobbyScreen.CampaignSubmarines.Count; i++) { - submarinesString += GameMain.NetLobbyScreen.CampaignSubmarines[i].Name + ServerSettings.SubmarineSeparatorChar; + submarinesString += GameMain.NetLobbyScreen.CampaignSubmarines[i].Name + ServerSettings.SubmarineSeparatorChar; } submarinesString.Trim(ServerSettings.SubmarineSeparatorChar); serverSettings.CampaignSubmarines = submarinesString; diff --git a/Barotrauma/BarotraumaServer/ServerSource/Traitors/Goals/GoalFindItem.cs b/Barotrauma/BarotraumaServer/ServerSource/Traitors/Goals/GoalFindItem.cs index a95f200bc..06f43f91b 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Traitors/Goals/GoalFindItem.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Traitors/Goals/GoalFindItem.cs @@ -185,7 +185,7 @@ namespace Barotrauma { existingItems.Add(item); } - Entity.Spawner.AddToSpawnQueue(targetPrefab, targetContainer.OwnInventory, null, item => + Entity.Spawner.AddToSpawnQueue(targetPrefab, targetContainer.OwnInventory, onSpawned: item => { item.AddTag("traitormissionitem"); }); diff --git a/Barotrauma/BarotraumaServer/WindowsServer.csproj b/Barotrauma/BarotraumaServer/WindowsServer.csproj index 575a80c8f..9454f5d56 100644 --- a/Barotrauma/BarotraumaServer/WindowsServer.csproj +++ b/Barotrauma/BarotraumaServer/WindowsServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.15.12.0 + 0.15.13.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs index 719417830..35ffe424e 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs @@ -104,6 +104,7 @@ namespace Barotrauma !pathSteering.CurrentPath.Unreachable && (!requireNonDirty || !pathSteering.IsPathDirty); + public bool IsCurrentPathNullOrUnreachable => IsCurrentPathUnreachable || steeringManager is IndoorsSteeringManager pathSteering && pathSteering.CurrentPath == null; public bool IsCurrentPathUnreachable => steeringManager is IndoorsSteeringManager pathSteering && !pathSteering.IsPathDirty && pathSteering.CurrentPath != null && pathSteering.CurrentPath.Unreachable; public bool IsCurrentPathFinished => steeringManager is IndoorsSteeringManager pathSteering && !pathSteering.IsPathDirty && pathSteering.CurrentPath != null && pathSteering.CurrentPath.Finished; @@ -431,7 +432,7 @@ namespace Barotrauma Vector2 diff = EscapeTarget.WorldPosition - Character.WorldPosition; float sqrDist = diff.LengthSquared(); bool isClose = sqrDist < MathUtils.Pow2(100); - if (Character.CurrentHull == null || isClose && !isClosedDoor || pathSteering == null || IsCurrentPathUnreachable || IsCurrentPathFinished) + if (Character.CurrentHull == null || isClose && !isClosedDoor || pathSteering == null || IsCurrentPathNullOrUnreachable || IsCurrentPathFinished) { // Very close to the target, outside, or at the end of the path -> try to steer through the gap SteeringManager.Reset(); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs index 440bf76ce..611ba59f0 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs @@ -3659,15 +3659,15 @@ namespace Barotrauma { if (SelectedAiTarget == null) { return; } Vector2 escapeDir = Vector2.Normalize(WorldPosition - SelectedAiTarget.WorldPosition); + if (!MathUtils.IsValid(escapeDir)) + { + escapeDir = Vector2.UnitY; + } if (Character.CurrentHull != null && !Character.AnimController.InWater) { // Inside escapeDir = new Vector2(Math.Sign(escapeDir.X), 0); } - if (!MathUtils.IsValid(escapeDir)) - { - escapeDir = Vector2.UnitY; - } SteeringManager.Reset(); SteeringManager.SteeringManual(deltaTime, escapeDir); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/HumanAIController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/HumanAIController.cs index 974af8a20..48d9f18ea 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/HumanAIController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/HumanAIController.cs @@ -250,7 +250,15 @@ namespace Barotrauma { rayEnd += SelectedAiTarget.Entity.Submarine.SimPosition; } - UseIndoorSteeringOutside = Submarine.PickBody(SimPosition, rayEnd, collisionCategory: Physics.CollisionLevel | Physics.CollisionWall) != null; + IEnumerable ignoredBodies = null; + if (SelectedAiTarget.Entity is ISpatialEntity spatialTarget) + { + Submarine targetSub = spatialTarget.Submarine; + if (targetSub != null) + { + ignoredBodies = targetSub.PhysicsBody.FarseerBody.ToEnumerable(); + } + } } } else @@ -340,14 +348,21 @@ namespace Barotrauma IsInsideCave = Character.CurrentHull == null && Level.Loaded?.Caves.FirstOrDefault(c => c.Area.Contains(Character.WorldPosition)) is Level.Cave; } - if (UseIndoorSteeringOutside || IsInsideCave || Character.CurrentHull?.Submarine != null || hasValidPath && IsCloseEnoughToTarget(maxSteeringBuffer) || IsCloseEnoughToTarget(steeringBuffer)) + if (UseIndoorSteeringOutside || IsInsideCave || Character.CurrentHull?.Submarine != null || hasValidPath || IsCloseEnoughToTarget(steeringBuffer)) { if (steeringManager != insideSteering) { insideSteering.Reset(); steeringManager = insideSteering; } - steeringBuffer += steeringBufferIncreaseSpeed * deltaTime; + if (IsCloseEnoughToTarget(maxSteeringBuffer)) + { + steeringBuffer += steeringBufferIncreaseSpeed * deltaTime; + } + else + { + steeringBuffer = minSteeringBuffer; + } } else { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/IndoorsSteeringManager.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/IndoorsSteeringManager.cs index cf2635e9d..74f3d6a0c 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/IndoorsSteeringManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/IndoorsSteeringManager.cs @@ -309,13 +309,15 @@ namespace Barotrauma } if (currentPath.Finished) { - Vector2 pos2 = host.SimPosition; - if (character != null && character.Submarine == null && - CurrentPath.Nodes.Count > 0 && CurrentPath.Nodes.Last().Submarine != null) + var lastNode = currentPath.Nodes.LastOrDefault(); + if (lastNode == null) { - pos2 -= CurrentPath.Nodes.Last().Submarine.SimPosition; + return Vector2.Zero; + } + else + { + return ConvertUnits.ToSimUnits(lastNode.WorldPosition - host.WorldPosition); } - return currentTarget - pos2; } bool doorsChecked = false; if (!character.LockHands && buttonPressCooldown <= 0.0f) @@ -323,29 +325,7 @@ namespace Barotrauma CheckDoorsInPath(); doorsChecked = true; } - Vector2 pos = host.SimPosition; - if (character != null && CurrentPath.CurrentNode != null) - { - var nodeSub = CurrentPath.CurrentNode.Submarine; - if (nodeSub != null) - { - if (character.Submarine == null) - { - // Going inside - pos -= ConvertUnits.ToSimUnits(nodeSub.Position); - } - else if (character.Submarine != nodeSub) - { - // Different subs - pos -= ConvertUnits.ToSimUnits(nodeSub.Position - character.Submarine.Position); - } - } - else if (character.Submarine != null) - { - // Going outside - pos += ConvertUnits.ToSimUnits(character.Submarine.Position); - } - } + Vector2 pos = host.WorldPosition; bool isDiving = character.AnimController.InWater && character.AnimController.HeadInWater; // Only humanoids can climb ladders bool canClimb = character.AnimController is HumanoidAnimController && !character.LockHands; @@ -384,7 +364,7 @@ namespace Barotrauma } if (character.IsClimbing && useLadders) { - Vector2 diff = currentPath.CurrentNode.SimPosition - pos; + Vector2 diff = currentPath.CurrentNode.WorldPosition - pos; bool nextLadderSameAsCurrent = IsNextLadderSameAsCurrent; if (nextLadderSameAsCurrent) { @@ -397,7 +377,7 @@ namespace Barotrauma float heightFromFloor = character.AnimController.GetColliderBottom().Y - character.AnimController.FloorY; if (heightFromFloor <= 0.0f) { - diff.Y = Math.Max(diff.Y, 1.0f); + diff.Y = Math.Max(diff.Y, 100); } // We need some margin, because if a hatch has closed, it's possible that the height from floor is slightly negative. bool isAboveFloor = heightFromFloor > -0.1f; @@ -430,7 +410,7 @@ namespace Barotrauma NextNode(!doorsChecked); } } - return diff; + return ConvertUnits.ToSimUnits(diff); } else if (character.AnimController.InWater) { @@ -481,7 +461,7 @@ namespace Barotrauma { return Vector2.Zero; } - return currentPath.CurrentNode.SimPosition - pos; + return ConvertUnits.ToSimUnits(currentPath.CurrentNode.WorldPosition - pos); } private void NextNode(bool checkDoors) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs index dd98bf747..afc834674 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs @@ -45,6 +45,10 @@ namespace Barotrauma /// public bool AllowStealing { get; set; } public bool TakeWholeStack { get; set; } + /// + /// Are variants of the specified item allowed + /// + public bool AllowVariants { get; set; } public bool Equip { get; set; } public bool Wear { get; set; } @@ -265,7 +269,7 @@ namespace Barotrauma } float priority = Math.Clamp(objectiveManager.GetCurrentPriority(), 10, 100); - bool checkPath = priority >= AIObjectiveManager.LowestOrderPriority && (objectiveManager.IsCurrentOrder() || objectiveManager.CurrentOrder is AIObjectiveGoTo gotoOrder && gotoOrder.followControlledCharacter); + bool checkPath = priority >= AIObjectiveManager.LowestOrderPriority && (objectiveManager.IsCurrentOrder() || objectiveManager.CurrentOrder is AIObjectiveGoTo gotoOrder && gotoOrder.isFollowOrderObjective); bool hasCalledPathFinder = false; int itemsPerFrame = (int)priority; for (int i = 0; i < itemsPerFrame && currSearchIndex < Item.ItemList.Count - 1; i++) @@ -408,7 +412,7 @@ namespace Barotrauma if (ignoredItems.Contains(item)) { return false; }; if (item.Condition < TargetCondition) { return false; } if (ItemFilter != null && !ItemFilter(item)) { return false; } - return identifiersOrTags.Any(id => id == item.Prefab.Identifier || item.HasTag(id)); + return identifiersOrTags.Any(id => id == item.Prefab.Identifier || item.HasTag(id) || (AllowVariants && item.Prefab.VariantOf?.Identifier == id)); } public override void Reset() diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs index a67611486..154e88ec9 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs @@ -24,7 +24,7 @@ namespace Barotrauma public Func priorityGetter; - public bool followControlledCharacter; + public bool isFollowOrderObjective; public bool mimic; public bool SpeakIfFails { get; set; } = true; public bool UsePathingOutside { get; set; } = true; @@ -165,17 +165,10 @@ namespace Barotrauma protected override void Act(float deltaTime) { - if (followControlledCharacter) + if (Target == null) { - if (Character.Controlled != null && HumanAIController.IsFriendly(Character.Controlled)) - { - Target = Character.Controlled; - } - if (Target == null) - { - Abandon = true; - return; - } + Abandon = true; + return; } if (Target == character || character.SelectedBy != null && HumanAIController.IsFriendly(character.SelectedBy)) { @@ -205,7 +198,7 @@ namespace Barotrauma } } Hull targetHull = GetTargetHull(); - if (!followControlledCharacter) + if (!isFollowOrderObjective) { // Abandon if going through unsafe paths. Note ignores unsafe nodes when following an order or when the objective is set to ignore unsafe hulls. bool containsUnsafeNodes = character.IsDismissed && !HumanAIController.ObjectiveManager.CurrentObjective.IgnoreUnsafeHulls @@ -223,7 +216,7 @@ namespace Barotrauma { Abandon = true; } - else if (HumanAIController.IsCurrentPathUnreachable) + else if (HumanAIController.IsCurrentPathNullOrUnreachable) { waitUntilPathUnreachable -= deltaTime; SteeringManager.Reset(); @@ -317,8 +310,8 @@ namespace Barotrauma Character targetCharacter = Target as Character; if (character.AnimController.InWater) { - if (character.CurrentHull == null || - followControlledCharacter && + if (character.CurrentHull == null || + isFollowOrderObjective && targetCharacter != null && (targetCharacter.CurrentHull == null) != (character.CurrentHull == null) && Vector2.DistanceSquared(character.WorldPosition, Target.WorldPosition) < maxGapDistance * maxGapDistance) { @@ -361,7 +354,7 @@ namespace Barotrauma } if (TargetGap != null) { - if (TargetGap.FlowTargetHull != null && HumanAIController.SteerThroughGap(TargetGap, followControlledCharacter ? Target.WorldPosition : TargetGap.FlowTargetHull.WorldPosition, deltaTime)) + if (TargetGap.FlowTargetHull != null && HumanAIController.SteerThroughGap(TargetGap, isFollowOrderObjective ? Target.WorldPosition : TargetGap.FlowTargetHull.WorldPosition, deltaTime)) { SteeringManager.SteeringAvoid(deltaTime, avoidLookAheadDistance, weight: 1); return; @@ -595,7 +588,7 @@ namespace Barotrauma { if (gap.Open < 1) { continue; } if (gap.Submarine == null) { continue; } - if (!followControlledCharacter) + if (!isFollowOrderObjective) { if (gap.FlowTargetHull == null) { continue; } if (gap.Submarine != Target.Submarine) { continue; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveManager.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveManager.cs index 4cb710919..383264b6f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveManager.cs @@ -452,7 +452,7 @@ namespace Barotrauma extraDistanceWhileSwimming = 100, AllowGoingOutside = true, IgnoreIfTargetDead = true, - followControlledCharacter = true, + isFollowOrderObjective = true, mimic = true, DialogueIdentifier = "dialogcannotreachplace" }; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs index fd42eafd6..a6132f8cb 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs @@ -107,7 +107,10 @@ namespace Barotrauma { foreach (RelatedItem requiredItem in kvp.Value) { - var getItemObjective = new AIObjectiveGetItem(character, requiredItem.Identifiers, objectiveManager, true); + var getItemObjective = new AIObjectiveGetItem(character, requiredItem.Identifiers, objectiveManager, true) + { + AllowVariants = requiredItem.AllowVariants + }; if (objectiveManager.IsCurrentOrder()) { if (character.IsOnPlayerTeam) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescue.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescue.cs index 66cc99a4a..3d7b364ca 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescue.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescue.cs @@ -408,7 +408,7 @@ namespace Barotrauma } bool isCompleted = AIObjectiveRescueAll.GetVitalityFactor(targetCharacter) >= AIObjectiveRescueAll.GetVitalityThreshold(objectiveManager, character, targetCharacter) || - targetCharacter.CharacterHealth.GetAllAfflictions().All(a => a.Strength <= a.Prefab.TreatmentThreshold); + targetCharacter.CharacterHealth.GetAllAfflictions().All(a => a.Prefab.IsBuff || a.Strength <= a.Prefab.TreatmentThreshold); if (isCompleted && targetCharacter != character && character.IsOnPlayerTeam) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescueAll.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescueAll.cs index 48936b9f6..eb7504c08 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescueAll.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescueAll.cs @@ -83,7 +83,7 @@ namespace Barotrauma if (character.AIController is HumanAIController humanAI) { if (GetVitalityFactor(target) >= GetVitalityThreshold(humanAI.ObjectiveManager, character, target) || - target.CharacterHealth.GetAllAfflictions().All(a => a.Strength <= a.Prefab.TreatmentThreshold)) + target.CharacterHealth.GetAllAfflictions().All(a => a.Prefab.IsBuff || a.Strength <= a.Prefab.TreatmentThreshold)) { return false; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs index 8edc9b797..639a02146 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs @@ -1367,7 +1367,7 @@ namespace Barotrauma info.Job.GiveJobItems(this, spawnPoint); } - public void GiveIdCardTags(WayPoint spawnPoint) + public void GiveIdCardTags(WayPoint spawnPoint, bool createNetworkEvent = false) { if (info?.Job == null || spawnPoint == null) { return; } @@ -1378,6 +1378,10 @@ namespace Barotrauma { item.AddTag(s); } + if (createNetworkEvent && (GameMain.NetworkMember?.IsServer ?? false)) + { + GameMain.NetworkMember.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ChangeProperty, item.SerializableProperties["tags"] }); + } } } @@ -1756,6 +1760,7 @@ namespace Barotrauma } else if (IsPlayer) { + float dist = -1; Vector2 attackPos = SimPosition + ConvertUnits.ToSimUnits(cursorPosition - Position); List ignoredBodies = AnimController.Limbs.Select(l => l.body.FarseerBody).ToList(); ignoredBodies.Add(AnimController.Collider.FarseerBody); @@ -1787,13 +1792,13 @@ namespace Barotrauma } else { - if (body.UserData is IDamageable) + if (body.UserData is IDamageable damageable) { - attackTarget = (IDamageable)body.UserData; + attackTarget = damageable; } - else if (body.UserData is Limb) + else if (body.UserData is Limb limb) { - attackTarget = ((Limb)body.UserData).character; + attackTarget = limb.character; } } } @@ -1822,7 +1827,20 @@ namespace Barotrauma var attackLimb = sortedLimbs.FirstOrDefault(); if (attackLimb != null) { - attackLimb.UpdateAttack(deltaTime, attackPos, attackTarget, out AttackResult attackResult); + if (attackTarget is Character targetCharacter) + { + dist = ConvertUnits.ToDisplayUnits(Vector2.Distance(Submarine.LastPickedPosition, attackLimb.SimPosition)); + foreach (Limb limb in targetCharacter.AnimController.Limbs) + { + if (limb.IsSevered || limb.Removed) { continue; } + float tempDist = ConvertUnits.ToDisplayUnits(Vector2.Distance(limb.SimPosition, attackLimb.SimPosition)); + if (tempDist < dist) + { + dist = tempDist; + } + } + } + attackLimb.UpdateAttack(deltaTime, attackPos, attackTarget, out AttackResult attackResult, dist); if (!attackLimb.attack.IsRunning) { attackCoolDown = 1.0f; @@ -3438,7 +3456,7 @@ namespace Barotrauma var attackResult = targetLimb == null ? AddDamage(worldPosition, attackAfflictions, attack.Stun, playSound, attackImpulse, out limbHit, attacker, attack.DamageMultiplier * attackData.DamageMultiplier) : - DamageLimb(worldPosition, targetLimb, attackAfflictions, attack.Stun, playSound, attackImpulse, attacker, attack.DamageMultiplier * attackData.DamageMultiplier, penetration: penetration + attackData.AddedPenetration); + DamageLimb(worldPosition, targetLimb, attackAfflictions, attack.Stun, playSound, attackImpulse, attacker, attack.DamageMultiplier * attackData.DamageMultiplier, penetration: penetration + attackData.AddedPenetration, shouldImplode: attackData.ShouldImplode); if (attacker != null) { @@ -3558,12 +3576,12 @@ namespace Barotrauma public void RecordKill(Character target) { - var abilityCharacter = new AbilityCharacter(target); + var abilityCharacterKill = new AbilityCharacterKill(target, this); foreach (Character attackerCrewmember in GetFriendlyCrew(this)) { - attackerCrewmember.CheckTalents(AbilityEffectType.OnCrewKillCharacter, abilityCharacter); + attackerCrewmember.CheckTalents(AbilityEffectType.OnCrewKillCharacter, abilityCharacterKill); } - CheckTalents(AbilityEffectType.OnKillCharacter, abilityCharacter); + CheckTalents(AbilityEffectType.OnKillCharacter, abilityCharacterKill); if (!IsOnPlayerTeam) { return; } if (GameMain.Config.KilledCreatures.Any(name => name.Equals(target.SpeciesName, StringComparison.OrdinalIgnoreCase))) { return; } @@ -3579,7 +3597,7 @@ namespace Barotrauma GameMain.Config.RecentlyEncounteredCreatures.Add(other.SpeciesName); } - public AttackResult DamageLimb(Vector2 worldPosition, Limb hitLimb, IEnumerable afflictions, float stun, bool playSound, float attackImpulse, Character attacker = null, float damageMultiplier = 1, bool allowStacking = true, float penetration = 0f) + public AttackResult DamageLimb(Vector2 worldPosition, Limb hitLimb, IEnumerable afflictions, float stun, bool playSound, float attackImpulse, Character attacker = null, float damageMultiplier = 1, bool allowStacking = true, float penetration = 0f, bool shouldImplode = false) { if (Removed) { return new AttackResult(); } @@ -3638,6 +3656,12 @@ namespace Barotrauma float prevVitality = CharacterHealth.Vitality; AttackResult attackResult = hitLimb.AddDamage(simPos, afflictions, playSound, damageMultiplier: damageMultiplier, penetration: penetration, attacker: attacker); CharacterHealth.ApplyDamage(hitLimb, attackResult, allowStacking); + if (shouldImplode) + { + // Only used by assistant's True Potential talent. Has to run here in order to properly give kill credit when it activates. + Implode(); + } + if (attacker != this) { OnAttacked?.Invoke(attacker, attackResult); @@ -3786,7 +3810,7 @@ namespace Barotrauma } } - public void Implode(bool isNetworkMessage = false) + private void Implode(bool isNetworkMessage = false) { if (CharacterHealth.Unkillable || GodMode || IsDead) { return; } @@ -4626,4 +4650,16 @@ namespace Barotrauma AggressiveBehavior = aggressiveBehavior; } } + + class AbilityCharacterKill : AbilityObject, IAbilityCharacter + { + public AbilityCharacterKill(Character character, Character killer) + { + Character = character; + Killer = killer; + } + public Character Character { get; set; } + public Character Killer { get; set; } + } + } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionHusk.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionHusk.cs index 3878de39b..5203f1728 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionHusk.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionHusk.cs @@ -291,7 +291,7 @@ namespace Barotrauma husk.SetStun(5); yield return new WaitForSeconds(5, false); #if CLIENT - husk.PlaySound(CharacterSound.SoundType.Idle); + husk?.PlaySound(CharacterSound.SoundType.Idle); #endif yield return CoroutineStatus.Success; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs index 9980cb396..bb24a39c9 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs @@ -844,6 +844,8 @@ namespace Barotrauma FaceTint = DefaultFaceTint; BodyTint = Color.TransparentBlack; + if (!(Character?.Params?.Health.ApplyAfflictionColors ?? false)) { return; } + for (int i = 0; i < limbHealths.Count; i++) { for (int j = limbHealths[i].Afflictions.Count - 1; j >= 0; j--) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs index 39016b7d6..be1df08e5 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs @@ -466,6 +466,9 @@ namespace Barotrauma [Serialize(false, true), Editable] public bool StunImmunity { get; set; } + [Serialize(false, true, description: "Can afflictions affect the face/body tint of the character."), Editable] + public bool ApplyAfflictionColors { get; private set; } + // TODO: limbhealths, sprite? public HealthParams(XElement element, CharacterParams character) : base(element, character) { } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionData/AbilityConditionCharacter.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionData/AbilityConditionCharacter.cs index 2670ea21e..407446785 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionData/AbilityConditionCharacter.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionData/AbilityConditionCharacter.cs @@ -14,8 +14,9 @@ namespace Barotrauma.Abilities protected override bool MatchesConditionSpecific(AbilityObject abilityObject) { - if ((abilityObject as IAbilityCharacter)?.Character is Character character) + if (abilityObject is IAbilityCharacter abilityCharacter) { + if (!(abilityCharacter.Character is Character character)) { return false; } if (!IsViableTarget(targetTypes, character)) { return false; } return true; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionData/AbilityConditionGeneHarvester.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionData/AbilityConditionGeneHarvester.cs new file mode 100644 index 000000000..6ea6dd5e9 --- /dev/null +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionData/AbilityConditionGeneHarvester.cs @@ -0,0 +1,23 @@ +using System.Xml.Linq; + +namespace Barotrauma.Abilities +{ + class AbilityConditionGeneHarvester : AbilityConditionData + { + + public AbilityConditionGeneHarvester(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement) { } + + protected override bool MatchesConditionSpecific(AbilityObject abilityObject) + { + if (abilityObject is AbilityCharacterKill abilityCharacterKill) + { + return abilityCharacterKill.Killer.Submarine == null || abilityCharacterKill.Killer.TeamID != abilityCharacterKill.Killer.Submarine.TeamID; + } + else + { + LogAbilityConditionError(abilityObject, typeof(AbilityCharacterKill)); + return false; + } + } + } +} diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityObjects.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityObjects.cs index 49431bb1e..db98b843d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityObjects.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityObjects.cs @@ -136,6 +136,7 @@ namespace Barotrauma.Abilities public float DamageMultiplier { get; set; } = 1f; public float AddedPenetration { get; set; } = 0f; public List Afflictions { get; set; } + public bool ShouldImplode { get; set; } = false; public Attack SourceAttack { get; } public Character Character { get; set; } public Character Attacker { get; set; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityModifyAttackData.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityModifyAttackData.cs index 2e742bb3f..30b6eb7c4 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityModifyAttackData.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityModifyAttackData.cs @@ -37,12 +37,7 @@ namespace Barotrauma.Abilities attackData.DamageMultiplier += addedDamageMultiplier; attackData.AddedPenetration += addedPenetration; - if (implode) - { - // might have issues, as the method used to be private and only used for pressure death - attackData.Character?.Implode(); - } - + attackData.ShouldImplode = implode; } else { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CustomAbilities/CharacterAbilityInsurancePolicy.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CustomAbilities/CharacterAbilityInsurancePolicy.cs index 1583bd53b..94a89cc5b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CustomAbilities/CharacterAbilityInsurancePolicy.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CustomAbilities/CharacterAbilityInsurancePolicy.cs @@ -19,11 +19,10 @@ namespace Barotrauma.Abilities moneyPerMission = abilityElement.GetAttributeInt("moneypermission", 0); } - protected override void ApplyEffect() + protected override void ApplyEffect(AbilityObject abilityObject) { if (Character?.Info is CharacterInfo info) { - Character.GiveMoney(moneyPerMission * info.MissionsCompletedSinceDeath); } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/NPCChangeTeamAction.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/NPCChangeTeamAction.cs index f4aa41aa8..b7c31e334 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/NPCChangeTeamAction.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/NPCChangeTeamAction.cs @@ -45,6 +45,20 @@ namespace Barotrauma { wifiComponent.TeamID = TeamTag; } + var idCard = item.GetComponent(); + if (idCard != null) + { + idCard.TeamID = TeamTag; + idCard.SubmarineSpecificID = 0; + } + } + + WayPoint subWaypoint = + WayPoint.WayPointList.Find(wp => wp.Submarine == Submarine.MainSub && wp.SpawnType == SpawnType.Human && wp.AssignedJob == npc.Info.Job?.Prefab) ?? + WayPoint.WayPointList.Find(wp => wp.Submarine == Submarine.MainSub && wp.SpawnType == SpawnType.Human); + if (subWaypoint != null) + { + npc.GiveIdCardTags(subWaypoint, createNetworkEvent: true); } #if SERVER GameMain.NetworkMember.CreateEntityEvent(npc, new object[] { NetEntityEvent.Type.AddToCrew, TeamTag, npc.Inventory.AllItems.Select(it => it.ID).ToArray() }); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/EventSet.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/EventSet.cs index 7431b31b3..ca7667dca 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/EventSet.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/EventSet.cs @@ -112,13 +112,13 @@ namespace Barotrauma } return prefab; } - + this.Prefabs = prefabIdentifiers .Select(tryFindPrefab) .Where(p => p != null) .ToImmutableArray(); - this.Commonness = commonness ?? this.Prefabs.Select(p => p.Commonness).Max(); - this.Probability = probability ?? this.Prefabs.Select(p => p.Probability).Max(); + this.Commonness = commonness ?? this.Prefabs.Select(p => p.Commonness).MaxOrNull() ?? 0.0f; + this.Probability = probability ?? this.Prefabs.Select(p => p.Probability).MaxOrNull() ?? 0.0f; } public SubEventPrefab(EventPrefab prefab, float commonness, float probability) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/PirateMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/PirateMission.cs index e9d3cef40..39a4e2d01 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/PirateMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/PirateMission.cs @@ -390,7 +390,7 @@ namespace Barotrauma private bool DeadOrCaptured(Character character) { - return character != null && !character.Removed && (character.IsDead || (character.LockHands && character.Submarine == Submarine.MainSub)); + return character == null || character.Removed || character.IsDead || (character.LockHands && character.Submarine == Submarine.MainSub); } public override void End() diff --git a/Barotrauma/BarotraumaShared/SharedSource/Extensions/IEnumerableExtensions.cs b/Barotrauma/BarotraumaShared/SharedSource/Extensions/IEnumerableExtensions.cs index c3d164708..823a3149f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Extensions/IEnumerableExtensions.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Extensions/IEnumerableExtensions.cs @@ -171,5 +171,21 @@ namespace Barotrauma.Extensions } return false; } + + /// + /// Returns the maximum element in a given enumerable, or null if there + /// aren't any elements in the input. + /// + /// Input collection + /// Maximum element or null + public static T? MaxOrNull(this IEnumerable enumerable) where T : struct, IComparable + { + T? retVal = null; + foreach (T v in enumerable) + { + if (!retVal.HasValue || v.CompareTo(retVal.Value) > 0) { retVal = v; } + } + return retVal; + } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Pickable.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Pickable.cs index 49abae0d4..55170d2ea 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Pickable.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Pickable.cs @@ -80,6 +80,8 @@ namespace Barotrauma.Items.Components if ((picker.PickingItem == null || picker.PickingItem == item) && PickingTime <= float.MaxValue) { #if SERVER + // Set active picker before creating the server event to make sure it's set correctly + activePicker = picker; item.CreateServerEvent(this); #endif pickingCoroutine = CoroutineManager.StartCoroutine(WaitForPick(picker, abilityPickingTime.Value)); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/RangedWeapon.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/RangedWeapon.cs index a07db8e19..da04b497b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/RangedWeapon.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/RangedWeapon.cs @@ -72,7 +72,7 @@ namespace Barotrauma.Items.Components { get { - Matrix bodyTransform = Matrix.CreateRotationZ(item.body.Rotation); + Matrix bodyTransform = Matrix.CreateRotationZ(item.body == null ? MathHelper.ToRadians(item.Rotation) : item.body.Rotation); Vector2 flippedPos = barrelPos; if (item.body.Dir < 0.0f) { flippedPos.X = -flippedPos.X; } return Vector2.Transform(flippedPos, bodyTransform) * item.Scale; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Deconstructor.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Deconstructor.cs index e3eb12bcd..f8eb62c33 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Deconstructor.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Deconstructor.cs @@ -202,7 +202,7 @@ namespace Barotrauma.Items.Components { float percentageHealth = targetItem.Condition / targetItem.MaxCondition; - if (percentageHealth <= deconstructProduct.MinCondition || percentageHealth > deconstructProduct.MaxCondition) { return; } + if (percentageHealth < deconstructProduct.MinCondition || percentageHealth > deconstructProduct.MaxCondition) { return; } if (!(MapEntityPrefab.Find(null, deconstructProduct.ItemIdentifier) is ItemPrefab itemPrefab)) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Fabricator.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Fabricator.cs index 461ae0617..c7d83ec42 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Fabricator.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Fabricator.cs @@ -347,22 +347,20 @@ namespace Barotrauma.Items.Components float outCondition = fabricatedItem.OutCondition; if (i < amountFittingContainer) { - Entity.Spawner.AddToSpawnQueue(fabricatedItem.TargetItem, outputContainer.Inventory, fabricatedItem.TargetItem.Health * outCondition, + Entity.Spawner.AddToSpawnQueue(fabricatedItem.TargetItem, outputContainer.Inventory, fabricatedItem.TargetItem.Health * outCondition, quality, onSpawned: (Item spawnedItem) => { onItemSpawned(spawnedItem, tempUser); - spawnedItem.Quality = quality; //reset the condition in case the max condition is higher than the prefab's due to e.g. quality modifiers spawnedItem.Condition = spawnedItem.MaxCondition * outCondition; }); } else { - Entity.Spawner.AddToSpawnQueue(fabricatedItem.TargetItem, item.Position, item.Submarine, fabricatedItem.TargetItem.Health * outCondition, + Entity.Spawner.AddToSpawnQueue(fabricatedItem.TargetItem, item.Position, item.Submarine, fabricatedItem.TargetItem.Health * outCondition, quality, onSpawned: (Item spawnedItem) => { onItemSpawned(spawnedItem, tempUser); - spawnedItem.Quality = quality; //reset the condition in case the max condition is higher than the prefab's due to e.g. quality modifiers spawnedItem.Condition = spawnedItem.MaxCondition * outCondition; }); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Repairable.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Repairable.cs index 3ff601550..38331c971 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Repairable.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Repairable.cs @@ -547,6 +547,11 @@ namespace Barotrauma.Items.Components //power transfer items (junction boxes, relays) don't deteriorate if they're no carrying any power if (Math.Abs(pt.CurrPowerConsumption) > 0.1f) { return true; } } + else if (ic is PowerContainer pc) + { + //batteries don't deteriorate if they're not charging/discharging + if (Math.Abs(pc.CurrPowerConsumption) > 0.1f || Math.Abs(pc.CurrPowerOutput) > 0.1f) { return true; } + } else if (ic is Engine engine) { //engines don't deteriorate if they're not running @@ -555,7 +560,7 @@ namespace Barotrauma.Items.Components else if (ic is Pump pump) { //pumps don't deteriorate if they're not running - if (Math.Abs(pump.FlowPercentage) > 1.0f && pump.IsActive) { return true; } + if (Math.Abs(pump.FlowPercentage) > 1.0f && pump.IsActive && pump.HasPower) { return true; } } else if (ic is Reactor reactor) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Rope.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Rope.cs index 6e9836551..1e696bf14 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Rope.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Rope.cs @@ -127,6 +127,8 @@ namespace Barotrauma.Items.Components if (source == null || target == null || target.Removed || (source is Entity sourceEntity && sourceEntity.Removed)) { + source = null; + target = null; IsActive = false; return; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/ConnectionPanel.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/ConnectionPanel.cs index a52a9600b..79bc7f6a9 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/ConnectionPanel.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/ConnectionPanel.cs @@ -225,10 +225,23 @@ namespace Barotrauma.Items.Components //no electrocution in sub editor if (Screen.Selected == GameMain.SubEditorScreen) { return true; } - var powered = item.GetComponent(); - if (powered != null) + var reactor = item.GetComponent(); + if (reactor != null) { - //unpowered panels can be rewired without a risk of electrical shock + //reactors that arent generating power atm can be rewired without the risk of electrical shock + if (MathUtils.NearlyEqual(reactor.CurrPowerConsumption, 0.0f)) { return true; } + } + var powerContainer = item.GetComponent(); + if (powerContainer != null) + { + //empty batteries/supercapacitors can be rewired without the risk of electrical shock + //non-empty ones always have a chance of zapping the user + if (powerContainer.Charge <= 0.0f) { return true; } + } + var powered = item.GetComponent(); + if (powered != null && powerContainer == null) + { + //unpowered panels can be rewired without the risk of electrical shock if (powered.Voltage < 0.1f) { return true; } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs index 122eebb5b..8b501cd71 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs @@ -13,7 +13,7 @@ namespace Barotrauma struct DeconstructItem { public readonly string ItemIdentifier; - //minCondition does <= check, meaning that below or equeal to min condition will be skipped. + //minCondition does <= check, meaning that below or equal to min condition will be skipped. public readonly float MinCondition; //maxCondition does > check, meaning that above this max the deconstruct item will be skipped. public readonly float MaxCondition; @@ -50,7 +50,6 @@ namespace Barotrauma ActivateButtonText = element.GetAttributeString("activatebuttontext", string.Empty); InfoText = element.GetAttributeString("infotext", string.Empty); InfoTextOnOtherItemMissing = element.GetAttributeString("infotextonotheritemmissing", string.Empty); - } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/RelatedItem.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/RelatedItem.cs index ad9b19866..a5c4b8974 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/RelatedItem.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/RelatedItem.cs @@ -36,7 +36,7 @@ namespace Barotrauma /// public bool ExcludeBroken { get; private set; } - private bool allowVariants = true; + public bool AllowVariants { get; private set; } = true; public RelationType Type { @@ -84,13 +84,13 @@ namespace Barotrauma { if (item == null) { return false; } if (excludedIdentifiers.Any(id => item.Prefab.Identifier == id || item.HasTag(id))) { return false; } - return Identifiers.Any(id => item.Prefab.Identifier == id || item.HasTag(id) || (allowVariants && item.Prefab.VariantOf?.Identifier == id)); + return Identifiers.Any(id => item.Prefab.Identifier == id || item.HasTag(id) || (AllowVariants && item.Prefab.VariantOf?.Identifier == id)); } public bool MatchesItem(ItemPrefab itemPrefab) { if (itemPrefab == null) { return false; } if (excludedIdentifiers.Any(id => itemPrefab.Identifier == id || itemPrefab.Tags.Contains(id))) { return false; } - return Identifiers.Any(id => itemPrefab.Identifier == id || itemPrefab.Tags.Contains(id) || (allowVariants && itemPrefab.VariantOf?.Identifier == id)); + return Identifiers.Any(id => itemPrefab.Identifier == id || itemPrefab.Tags.Contains(id) || (AllowVariants && itemPrefab.VariantOf?.Identifier == id)); } public RelatedItem(string[] identifiers, string[] excludedIdentifiers) @@ -171,7 +171,7 @@ namespace Barotrauma new XAttribute("ignoreineditor", IgnoreInEditor), new XAttribute("excludebroken", ExcludeBroken), new XAttribute("targetslot", TargetSlot), - new XAttribute("allowvariants", allowVariants)); + new XAttribute("allowvariants", AllowVariants)); if (excludedIdentifiers.Length > 0) { @@ -235,7 +235,7 @@ namespace Barotrauma RelatedItem ri = new RelatedItem(identifiers, excludedIdentifiers) { ExcludeBroken = element.GetAttributeBool("excludebroken", true), - allowVariants = element.GetAttributeBool("allowvariants", true) + AllowVariants = element.GetAttributeBool("allowvariants", true) }; string typeStr = element.GetAttributeString("type", ""); if (string.IsNullOrEmpty(typeStr)) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Creatures/BallastFloraBehavior.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Creatures/BallastFloraBehavior.cs index b5adbe740..710b21946 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Creatures/BallastFloraBehavior.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Creatures/BallastFloraBehavior.cs @@ -510,14 +510,14 @@ namespace Barotrauma.MapCreatures.Behavior List list = branches[hull]; if (!list.Any(HasAcidEmitter)) { - BallastFloraBranch randomBranh = branches[hull].GetRandom(); - randomBranh.SpawningItem = true; + BallastFloraBranch randomBranch = branches[hull].GetRandom(); + randomBranch.SpawningItem = true; ItemPrefab prefab = ItemPrefab.Find(null, AttackItemPrefab); - Entity.Spawner?.AddToSpawnQueue(prefab, Parent.Position + Offset + randomBranh.Position, Parent.Submarine, null, item => + Entity.Spawner?.AddToSpawnQueue(prefab, Parent.Position + Offset + randomBranch.Position, Parent.Submarine, onSpawned: item => { - randomBranh.AttackItem = item; - randomBranh.SpawningItem = false; + randomBranch.AttackItem = item; + randomBranch.SpawningItem = false; }); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelObjects/LevelTrigger.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelObjects/LevelTrigger.cs index 71a30f339..87d9e6887 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelObjects/LevelTrigger.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelObjects/LevelTrigger.cs @@ -213,9 +213,8 @@ namespace Barotrauma }; PhysicsBody.FarseerBody.OnCollision += PhysicsBody_OnCollision; PhysicsBody.FarseerBody.OnSeparation += PhysicsBody_OnSeparation; - PhysicsBody.FarseerBody.SetIsSensor(true); + PhysicsBody.FarseerBody.SetIsSensor(element.GetAttributeBool("sensor", true)); PhysicsBody.FarseerBody.BodyType = BodyType.Static; - PhysicsBody.FarseerBody.BodyType = BodyType.Kinematic; ColliderRadius = ConvertUnits.ToDisplayUnits(Math.Max(Math.Max(PhysicsBody.radius, PhysicsBody.width / 2.0f), PhysicsBody.height / 2.0f)); @@ -532,10 +531,9 @@ namespace Barotrauma } } - if (triggerOnce) + if (triggerOnce && triggeredOnce) { - if (triggeredOnce) { return; } - if (triggerers.Count > 0) { triggeredOnce = true; } + return; } foreach (Entity triggerer in triggerers) @@ -577,6 +575,12 @@ namespace Barotrauma GameMain.GameScreen.Cam.Shake = Math.Max(GameMain.GameScreen.Cam.Shake, cameraShake); } } + + if (triggerOnce && triggerers.Count > 0) + { + PhysicsBody.Enabled = false; + triggeredOnce = true; + } } public static void RemoveDistantTriggerers(PhysicsBody physicsBody, HashSet triggerers, Vector2 calculateDistanceTo) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Networking/EntitySpawner.cs b/Barotrauma/BarotraumaShared/SharedSource/Networking/EntitySpawner.cs index a4f18118c..b5f155b33 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Networking/EntitySpawner.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Networking/EntitySpawner.cs @@ -26,6 +26,7 @@ namespace Barotrauma public readonly Inventory Inventory; public readonly Submarine Submarine; public readonly float Condition; + public readonly int Quality; public bool SpawnIfInventoryFull = true; public bool IgnoreLimbSlots = false; @@ -33,28 +34,31 @@ namespace Barotrauma private readonly Action onSpawned; - public ItemSpawnInfo(ItemPrefab prefab, Vector2 worldPosition, Action onSpawned, float? condition = null) + public ItemSpawnInfo(ItemPrefab prefab, Vector2 worldPosition, Action onSpawned, float? condition = null, int? quality = null) { Prefab = prefab ?? throw new ArgumentException("ItemSpawnInfo prefab cannot be null."); Position = worldPosition; Condition = condition ?? prefab.Health; + Quality = quality ?? 0; this.onSpawned = onSpawned; } - public ItemSpawnInfo(ItemPrefab prefab, Vector2 position, Submarine sub, Action onSpawned, float? condition = null) + public ItemSpawnInfo(ItemPrefab prefab, Vector2 position, Submarine sub, Action onSpawned, float? condition = null, int? quality = null) { Prefab = prefab ?? throw new ArgumentException("ItemSpawnInfo prefab cannot be null."); Position = position; Submarine = sub; Condition = condition ?? prefab.Health; + Quality = quality ?? 0; this.onSpawned = onSpawned; } - public ItemSpawnInfo(ItemPrefab prefab, Inventory inventory, Action onSpawned, float? condition = null) + public ItemSpawnInfo(ItemPrefab prefab, Inventory inventory, Action onSpawned, float? condition = null, int? quality = null) { Prefab = prefab ?? throw new ArgumentException("ItemSpawnInfo prefab cannot be null."); Inventory = inventory; Condition = condition ?? prefab.Health; + Quality = quality ?? 0; this.onSpawned = onSpawned; } @@ -73,7 +77,8 @@ namespace Barotrauma } spawnedItem = new Item(Prefab, Vector2.Zero, null) { - Condition = Condition + Condition = Condition, + Quality = Quality }; var slot = Slot != InvSlotType.None ? Slot.ToEnumerable() : spawnedItem.AllowedSlots; if (!Inventory.Owner.Removed && !Inventory.TryPutItem(spawnedItem, null, slot)) @@ -94,7 +99,11 @@ namespace Barotrauma } else { - spawnedItem = new Item(Prefab, Position, Submarine); + spawnedItem = new Item(Prefab, Position, Submarine) + { + Condition = Condition, + Quality = Quality + }; } return spawnedItem; } @@ -241,7 +250,7 @@ namespace Barotrauma return "EntitySpawner"; } - public void AddToSpawnQueue(ItemPrefab itemPrefab, Vector2 worldPosition, float? condition = null, Action onSpawned = null) + public void AddToSpawnQueue(ItemPrefab itemPrefab, Vector2 worldPosition, float? condition = null, int? quality = null, Action onSpawned = null) { if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; } if (itemPrefab == null) @@ -251,10 +260,10 @@ namespace Barotrauma GameAnalyticsManager.AddErrorEventOnce("EntitySpawner.AddToSpawnQueue1:ItemPrefabNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return; } - spawnQueue.Enqueue(new ItemSpawnInfo(itemPrefab, worldPosition, onSpawned, condition)); + spawnQueue.Enqueue(new ItemSpawnInfo(itemPrefab, worldPosition, onSpawned, condition, quality)); } - public void AddToSpawnQueue(ItemPrefab itemPrefab, Vector2 position, Submarine sub, float? condition = null, Action onSpawned = null) + public void AddToSpawnQueue(ItemPrefab itemPrefab, Vector2 position, Submarine sub, float? condition = null, int? quality = null, Action onSpawned = null) { if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; } if (itemPrefab == null) @@ -264,10 +273,10 @@ namespace Barotrauma GameAnalyticsManager.AddErrorEventOnce("EntitySpawner.AddToSpawnQueue2:ItemPrefabNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return; } - spawnQueue.Enqueue(new ItemSpawnInfo(itemPrefab, position, sub, onSpawned, condition)); + spawnQueue.Enqueue(new ItemSpawnInfo(itemPrefab, position, sub, onSpawned, condition, quality)); } - public void AddToSpawnQueue(ItemPrefab itemPrefab, Inventory inventory, float? condition = null, Action onSpawned = null, bool spawnIfInventoryFull = true, bool ignoreLimbSlots = false, InvSlotType slot = InvSlotType.None) + public void AddToSpawnQueue(ItemPrefab itemPrefab, Inventory inventory, float? condition = null, int? quality = null, Action onSpawned = null, bool spawnIfInventoryFull = true, bool ignoreLimbSlots = false, InvSlotType slot = InvSlotType.None) { if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; } if (itemPrefab == null) @@ -277,7 +286,7 @@ namespace Barotrauma GameAnalyticsManager.AddErrorEventOnce("EntitySpawner.AddToSpawnQueue3:ItemPrefabNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return; } - spawnQueue.Enqueue(new ItemSpawnInfo(itemPrefab, inventory, onSpawned, condition) + spawnQueue.Enqueue(new ItemSpawnInfo(itemPrefab, inventory, onSpawned, condition, quality) { SpawnIfInventoryFull = spawnIfInventoryFull, IgnoreLimbSlots = ignoreLimbSlots, @@ -395,10 +404,6 @@ namespace Barotrauma { CreateNetworkEventProjSpecific(spawnedEntity, false); } - if (spawnedEntity is Item item) - { - item.Condition = ((ItemSpawnInfo)entitySpawnInfo).Condition; - } entitySpawnInfo.OnSpawned(spawnedEntity); } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Screens/GameScreen.cs b/Barotrauma/BarotraumaShared/SharedSource/Screens/GameScreen.cs index f506479fd..eecd32a46 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Screens/GameScreen.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Screens/GameScreen.cs @@ -244,7 +244,7 @@ namespace Barotrauma cam.TargetPos = targetPos; } - cam.MoveCamera((float)deltaTime, allowZoom: GUI.MouseOn == null); + cam.MoveCamera((float)deltaTime, allowZoom: GUI.MouseOn == null && !Inventory.IsMouseOnInventory); #endif foreach (Submarine sub in Submarine.Loaded) diff --git a/Barotrauma/BarotraumaShared/Submarines/Dugong.sub b/Barotrauma/BarotraumaShared/Submarines/Dugong.sub index 0d93cd70f..88858bb97 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Dugong.sub and b/Barotrauma/BarotraumaShared/Submarines/Dugong.sub differ diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index eefe78651..da875f257 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,3 +1,57 @@ +--------------------------------------------------------------------------------------------------------- +v0.15.13.0 +--------------------------------------------------------------------------------------------------------- + +Changes: +- Remove spawnpoint-based job assignment logic. Previously, the number of job-specific spawnpoints in the sub affected how many players the server would try to assign to a given job, which would often lead to players not getting the job they wanted to. +- Made the captain job optional (i.e. if no-one has captain in their preferences, no-one gets forced to play as one). +- Improvements to the Korean localization. + +Fixes: +- Fixed clients' characters getting reset in the multiplayer campaign if they're spectating at the end of the round. +- Fixed crashing when an event set fails to load any of its sub events. Caused certain mods to crash the game at 42% in the loading screen. +- Fixed crashing on startup when using mods that remove the small icons from job prefabs. +- Fixed bots being unable to find their way to the submarine if the switch to the "find safety" state outside the sub. +- Fixed crashing when a monster was just about to turn to a husk when the round ends. +- Fixed opened item disappearing when switching to the test mode from the sub editor. +- Fixed Artie Dolittle's ID card not working in the player's sub after he's hired. +- Fixed category labels (sufficient skills to fabricate, requires recipe, etc) disappearing from the fabricator's item list when searching. +- Fixed prisoner's uniform using a wrong texture file. +- Fixed inability to edit pulse laser's power consumption in the sub editor. +- Fixed an exploit in Pressure Stabilizer crafting recipe. +- Fixed an exploit in Fixfoam Grenade deconstruction recipe. +- Fixed crashing when selecting a gene splicer and hovering over its inventory slot in the sub editor. +- Fixed bots being unable to use hardened and dementonite tools. +- Fixed a typo in Tinkering cooldown reduction description. +- Fixed inactive reactors electrocuting low-skill characters when rewired. +- Fixed ignore orders carrying over when switching subs, causing them to target random items in the new sub. +- Fixed dementonite knives being sold in stores. +- Fixed contained items' impact sounds being played when the item they're inside hits the floor. +- Fixed True Potential instant kills not properly giving kill credit (achievements, other talents). +- Fixed Gene Harvester incorrectly checking the owner of the talent's submarine rather than the killer's. +- Fixed Insurance Policy not triggering properly. +- Fixed issues with input going through interfaces drawn over inventory slots. +- Fixed bots trying to treat talent afflictions. +- Fixed player-controlled creature attacks sometimes not hitting characters when they should. +- Fixed "x in command room" spam when dragging and dropping orders in multiplayer. +- Fixed pirate missions not being considered completed if any of the pirates have been removed (e.g. eaten or despawned). +- Fixed high-quality items not stacking in the fabricator's output slot. +- Fixed ice shards' colliders taying active after the shard has shattered. +- Fixed bots following the controlled character instead of the order giver in singleplayer. +- Fixed purchased medals spawning on the floor. +- Fixed vision obstruction effect "flickering" when moving the cursor around when an item UI is open. +- Fixed some pumps in Dugong having 0 power consumption. +- Fixed pumps deteriorating when they don't have power. +- Fixed batteries/supercapacitors deteriorating when not charging/discharging. +- Fixed afflictions applying face/body tints on monsters. +- Fixed "select matching items" selecting all gaps if you've selected both a door and its gap in the sub editor. +- Fixed door gaps not being selected if you use "select matching items" on a door in the sub editor. +- Fixed biome ambience loop volume not being affected by the sound volume setting. + +Modding: +- Made deconstruction recipes' mincondition accept items whose condition equals to the mincondition, not just items whose condition is higher. +- Fixed color values being used incorrectly in explosion flashes. + --------------------------------------------------------------------------------------------------------- v0.15.12.0 --------------------------------------------------------------------------------------------------------- diff --git a/Barotrauma/BarotraumaShared/config.xml b/Barotrauma/BarotraumaShared/config.xml index 4f6ecf964..8e811973a 100644 --- a/Barotrauma/BarotraumaShared/config.xml +++ b/Barotrauma/BarotraumaShared/config.xml @@ -21,7 +21,10 @@ losmode="Transparent" hudscale="1" inventoryscale="1" /> - + + +