diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/Limb.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/Limb.cs index 42ba80997..2e544f692 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/Limb.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/Limb.cs @@ -1113,7 +1113,7 @@ namespace Barotrauma } if (wearableItemComponent.AllowedSlots.Contains(InvSlotType.Bag)) { - depth -= depthStep * 2; + depth -= depthStep * 4; } wearableColor = wearableItemComponent.Item.GetSpriteColor(); } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/AbandonedOutpostMission.cs b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/AbandonedOutpostMission.cs index 55191b4b4..d5161fc4d 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/AbandonedOutpostMission.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/AbandonedOutpostMission.cs @@ -22,6 +22,7 @@ namespace Barotrauma public override void ClientReadInitial(IReadMessage msg) { + base.ClientReadInitial(msg); ushort targetItemCount = msg.ReadUInt16(); for (int i = 0; i < targetItemCount; i++) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/AlienRuinMission.cs b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/AlienRuinMission.cs index 586f9c37a..b943081b2 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/AlienRuinMission.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/AlienRuinMission.cs @@ -6,6 +6,7 @@ namespace Barotrauma { public override void ClientReadInitial(IReadMessage msg) { + base.ClientReadInitial(msg); existingTargets.Clear(); spawnedTargets.Clear(); allTargets.Clear(); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/BeaconMission.cs b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/BeaconMission.cs deleted file mode 100644 index 584e13d3e..000000000 --- a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/BeaconMission.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Barotrauma.Networking; - -namespace Barotrauma -{ - partial class BeaconMission : Mission - { - public override void ClientReadInitial(IReadMessage msg) - { - return; - } - } -} diff --git a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/CargoMission.cs b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/CargoMission.cs index 97bcbc4d5..23b228922 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/CargoMission.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/CargoMission.cs @@ -25,6 +25,7 @@ namespace Barotrauma } public override void ClientReadInitial(IReadMessage msg) { + base.ClientReadInitial(msg); items.Clear(); ushort itemCount = msg.ReadUInt16(); for (int i = 0; i < itemCount; i++) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/CombatMission.cs b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/CombatMission.cs index fc8cafcd4..9fb2b490b 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/CombatMission.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/CombatMission.cs @@ -20,10 +20,5 @@ namespace Barotrauma return descriptions[GameMain.Client.Character.TeamID == CharacterTeamType.Team1 ? 1 : 2]; } } - - public override void ClientReadInitial(IReadMessage msg) - { - //do nothing - } } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/EscortMission.cs b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/EscortMission.cs index 5fbdc15a5..230570e5e 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/EscortMission.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/EscortMission.cs @@ -6,6 +6,8 @@ namespace Barotrauma { public override void ClientReadInitial(IReadMessage msg) { + base.ClientReadInitial(msg); + byte characterCount = msg.ReadByte(); for (int i = 0; i < characterCount; i++) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/MineralMission.cs b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/MineralMission.cs index 66eb75c8b..3ce80fd05 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/MineralMission.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/MineralMission.cs @@ -12,6 +12,7 @@ namespace Barotrauma { public override void ClientReadInitial(IReadMessage msg) { + base.ClientReadInitial(msg); byte caveCount = msg.ReadByte(); for (int i = 0; i < caveCount; i++) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/Mission.cs b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/Mission.cs index 5af7dd9cf..e8b3064d4 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/Mission.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/Mission.cs @@ -102,6 +102,9 @@ namespace Barotrauma State = msg.ReadInt16(); } - public abstract void ClientReadInitial(IReadMessage msg); + public virtual void ClientReadInitial(IReadMessage msg) + { + state = msg.ReadInt16(); + } } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/MonsterMission.cs b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/MonsterMission.cs index 162968040..e5aab9f41 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/MonsterMission.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/MonsterMission.cs @@ -6,6 +6,7 @@ namespace Barotrauma { public override void ClientReadInitial(IReadMessage msg) { + base.ClientReadInitial(msg); byte monsterCount = msg.ReadByte(); for (int i = 0; i < monsterCount; i++) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/NestMission.cs b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/NestMission.cs index 9de9c32c0..dcc6ee187 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/NestMission.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/NestMission.cs @@ -8,6 +8,7 @@ namespace Barotrauma { public override void ClientReadInitial(IReadMessage msg) { + base.ClientReadInitial(msg); byte selectedCaveIndex = msg.ReadByte(); nestPosition = new Vector2( msg.ReadSingle(), diff --git a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/PirateMission.cs b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/PirateMission.cs index fa71317bc..d111e664c 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/PirateMission.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/PirateMission.cs @@ -6,6 +6,7 @@ namespace Barotrauma { public override void ClientReadInitial(IReadMessage msg) { + base.ClientReadInitial(msg); // duplicate code from escortmission, should possibly be combined, though additional loot items might be added so maybe not byte characterCount = msg.ReadByte(); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/SalvageMission.cs b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/SalvageMission.cs index 8755b9d40..6479ddb90 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/SalvageMission.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/SalvageMission.cs @@ -7,6 +7,7 @@ namespace Barotrauma { public override void ClientReadInitial(IReadMessage msg) { + base.ClientReadInitial(msg); bool usedExistingItem = msg.ReadBoolean(); if (usedExistingItem) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/ScanMission.cs b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/ScanMission.cs index bbf3c18f6..93dadacc4 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/ScanMission.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Events/Missions/ScanMission.cs @@ -25,6 +25,7 @@ namespace Barotrauma public override void ClientReadInitial(IReadMessage msg) { + base.ClientReadInitial(msg); startingItems.Clear(); ushort itemCount = msg.ReadUInt16(); for (int i = 0; i < itemCount; i++) diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs index f165a8006..6ed653ddc 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs @@ -1287,9 +1287,11 @@ namespace Barotrauma GUITextBlock traitBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), traitString, font: GUI.SmallFont); traitBlock.RectTransform.NonScaledSize = traitSize.Pad(traitBlock.Padding).ToPoint(); + GUIFrame endocrineFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.35f), nameLayout.RectTransform, Anchor.BottomCenter), style: null); + if (!(GameMain.NetworkMember is null)) { - GUIButton newCharacterBox = new GUIButton(new RectTransform(Vector2.One, nameLayout.RectTransform, Anchor.BottomCenter), text: GameMain.NetLobbyScreen.CampaignCharacterDiscarded ? TextManager.Get("settings") : TextManager.Get("createnew")) + GUIButton newCharacterBox = new GUIButton(new RectTransform(new Vector2(0.675f, 1f), endocrineFrame.RectTransform, Anchor.TopLeft), text: GameMain.NetLobbyScreen.CampaignCharacterDiscarded ? TextManager.Get("settings") : TextManager.Get("createnew")) { IgnoreLayoutGroups = true }; @@ -1336,6 +1338,16 @@ namespace Barotrauma } } + IEnumerable endocrineTalents = info.GetEndocrineTalents().Select(e => TalentPrefab.TalentPrefabs.Find(c => c.Identifier.Equals(e, StringComparison.OrdinalIgnoreCase))); + + if (endocrineTalents.Count() > 0) + { + GUIImage endocrineIcon = new GUIImage(new RectTransform(new Vector2(0.275f, 1f), endocrineFrame.RectTransform, anchor: Anchor.TopRight, scaleBasis: ScaleBasis.Normal), style: "EndocrineReminderIcon") + { + ToolTip = $"{TextManager.Get("afflictionname.endocrineboost")}\n\n{string.Join(", ", endocrineTalents.Select(e => e.DisplayName))}" + }; + } + GUILayoutGroup skillLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 1f), talentInfoLayoutGroup.RectTransform)) { Stretch = true }; string skillString = TextManager.Get("skills"); diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSettings.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSettings.cs index d3444ed00..49b528e7d 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSettings.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSettings.cs @@ -173,7 +173,7 @@ namespace Barotrauma } } - private void LoadKeyBinds(XElement element) + private void LoadKeyBinds(XElement element, Version gameVersion) { foreach (XAttribute attribute in element.Attributes()) { @@ -183,7 +183,6 @@ namespace Barotrauma keyMapping[(int)InputType.TakeHalfFromInventorySlot] = new KeyOrMouse(Keys.LeftShift); keyMapping[(int)InputType.TakeOneFromInventorySlot] = new KeyOrMouse(Keys.LeftControl); } - if (!Enum.TryParse(attribute.Name.ToString(), true, out InputType inputType)) { continue; } if (int.TryParse(attribute.Value.ToString(), out int mouseButtonInt)) @@ -199,6 +198,13 @@ namespace Barotrauma keyMapping[(int)inputType] = new KeyOrMouse(key); } } + //v0.15 added creature attacks that can be used with a character capable of speaking (with mudraptor or spineling genes), + //which causes the previous attack keybind R to conflict with the radio keybind + // -> automatically change it to F + if (gameVersion < new Version(0, 15, 0, 0)) + { + keyMapping[(int)InputType.Attack] = new KeyOrMouse(Keys.F); + } } private void LoadInventoryKeybinds(XElement element) @@ -223,10 +229,12 @@ namespace Barotrauma private void LoadControls(XDocument doc) { + var gameVersion = new Version(doc.Root.GetAttributeString("gameversion", "0.0.0.0")); + XElement keyMapping = doc.Root.Element("keymapping"); if (keyMapping != null) { - LoadKeyBinds(keyMapping); + LoadKeyBinds(keyMapping, gameVersion); } XElement inventoryKeyMapping = doc.Root.Element("inventorykeymapping"); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/MiniMap.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/MiniMap.cs index d94357008..890b2910a 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/MiniMap.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/MiniMap.cs @@ -147,14 +147,14 @@ namespace Barotrauma.Items.Components private GUIFrame submarineContainer; private GUIFrame hullInfoFrame; - private GUIScissorComponent scissorComponent; - private GUIComponent miniMapContainer; + private GUIScissorComponent? scissorComponent; + private GUIComponent? miniMapContainer; private GUIComponent miniMapFrame; private GUIComponent electricalFrame; private GUILayoutGroup reportFrame; private GUILayoutGroup searchBarFrame; private GUITextBox searchBar; - private GUIComponent searchAutoComplete; + private GUIComponent? searchAutoComplete; private ItemPrefab? searchedPrefab; @@ -184,7 +184,7 @@ namespace Barotrauma.Items.Components private ImmutableDictionary electricalChildren; private ImmutableDictionary doorChildren; - private ImmutableHashSet itemsFoundOnSub; + private ImmutableHashSet? itemsFoundOnSub; private ImmutableHashSet? MiniMapBlips; private float blipState; @@ -416,7 +416,7 @@ namespace Barotrauma.Items.Components hullInfoFrame.AddToGUIUpdateList(order: order + 1); if (currentMode == MiniMapMode.ItemFinder && searchBar.Selected) { - searchAutoComplete.AddToGUIUpdateList(order: order + 1); + searchAutoComplete?.AddToGUIUpdateList(order: order + 1); } } @@ -686,7 +686,7 @@ namespace Barotrauma.Items.Components private void ControlSearchTooltip(GUITextBox sender, Keys key) { - if (!searchAutoComplete.Visible) { return; } + if (searchAutoComplete is null || !searchAutoComplete.Visible) { return; } GUIListBox listBox = searchAutoComplete.GetChild(); if (listBox is null) { return; } @@ -705,15 +705,17 @@ namespace Barotrauma.Items.Components } } - private bool UpdateSearchTooltip(GUITextBox box, string text) + private bool UpdateSearchTooltip(GUITextBox box, string? text) { + if (text is null || itemsFoundOnSub is null || searchAutoComplete is null) { return false; } + MiniMapBlips = null; searchedPrefab = null; searchAutoComplete.Visible = true; SetAutoCompletePosition(searchAutoComplete, box); - GUIListBox listBox = searchAutoComplete.GetChild(); - if (listBox is null) { return false; } + GUIListBox? listBox = searchAutoComplete.GetChild(); + if (listBox?.Content is null) { return false; } bool first = true; @@ -722,9 +724,9 @@ namespace Barotrauma.Items.Components foreach (GUIComponent component in listBox.Content.Children) { component.Visible = false; - if (component.UserData is ItemPrefab prefab && itemsFoundOnSub.Contains(prefab)) + if (component.UserData is ItemPrefab { Name: { } prefabName} prefab && itemsFoundOnSub.Contains(prefab)) { - component.Visible = prefab.Name.ToLower().Contains(text.ToLower()); + component.Visible = prefabName.ToLower().Contains(text.ToLower()); if (component.Visible && first) { @@ -828,6 +830,7 @@ namespace Barotrauma.Items.Components MiniMapBlips = positions.ToImmutableHashSet(); + if (searchAutoComplete is null) { return; } searchAutoComplete.Visible = false; } @@ -1021,7 +1024,7 @@ namespace Barotrauma.Items.Components if (Voltage < MinVoltage || !miniMapGuiComponent.RectComponent.Visible) { continue; } - int durability = (int)(it.Condition / it.MaxCondition * 100f); + int durability = (int)(it.Condition / (it.MaxCondition / it.MaxRepairConditionMultiplier) * 100f); Color color = ToolBox.GradientLerp(durability / 100f, GUI.Style.Red, GUI.Style.Orange, GUI.Style.Green, GUI.Style.Green); if (GUI.MouseOn == component) @@ -1188,7 +1191,7 @@ namespace Barotrauma.Items.Components { Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle; spriteBatch.End(); - if (submarinePreview is { } texture) + if (submarinePreview is { } texture && miniMapContainer is { } mapContainer) { spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, blendState: BlendState.NonPremultiplied, effect: GameMain.GameScreen.BlueprintEffect, rasterizerState: GameMain.ScissorTestEnable); spriteBatch.GraphicsDevice.ScissorRectangle = submarineContainer.Rect; @@ -1200,7 +1203,7 @@ namespace Barotrauma.Items.Components Vector2 origin = new Vector2(texture.Width / 2f, texture.Height / 2f); float scale = currentMode == MiniMapMode.HullStatus ? 1.0f : Zoom; - spriteBatch.Draw(texture, miniMapContainer.Center, null, blueprintBlue, 0f, origin, scale, SpriteEffects.None, 0f); + spriteBatch.Draw(texture, mapContainer.Center, null, blueprintBlue, 0f, origin, scale, SpriteEffects.None, 0f); spriteBatch.End(); } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Repairable.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Repairable.cs index 01db669ab..fbf133ced 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Repairable.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Repairable.cs @@ -52,8 +52,24 @@ namespace Barotrauma.Items.Components public override bool ShouldDrawHUD(Character character) { - if (!HasRequiredItems(character, false) || character.SelectedConstruction != item) return false; - return item.ConditionPercentage < RepairThreshold || character.IsTraitor && item.ConditionPercentage > MinSabotageCondition || (CurrentFixer == character && (!item.IsFullCondition || (character.IsTraitor && item.ConditionPercentage > MinSabotageCondition))) || IsTinkerable(character); + if (!HasRequiredItems(character, false) || character.SelectedConstruction != item) { return false; } + if (character.IsTraitor && item.ConditionPercentage > MinSabotageCondition) { return true; } + + float maxRepairConditionMultiplier = GetMaxRepairConditionMultiplier(character); + if (item.Condition / maxRepairConditionMultiplier < RepairThreshold) { return true; } + + if (CurrentFixer == character) + { + float condition = item.Condition / item.MaxRepairConditionMultiplier; + float maxCondition = item.MaxCondition / item.MaxRepairConditionMultiplier; + if (condition < maxCondition * maxRepairConditionMultiplier) + { + return true; + } + } + if (IsTinkerable(character)) { return true; } + + return false; } partial void InitProjSpecific(XElement element) @@ -344,6 +360,7 @@ namespace Barotrauma.Items.Components ushort currentFixerID = msg.ReadUInt16(); currentFixerAction = (FixActions)msg.ReadRangedInteger(0, 2); CurrentFixer = currentFixerID != 0 ? Entity.FindEntityByID(currentFixerID) as Character : null; + item.MaxRepairConditionMultiplier = GetMaxRepairConditionMultiplier(CurrentFixer); } public void ClientWrite(IWriteMessage msg, object[] extraData = null) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Rope.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Rope.cs index b2a025ca9..25d45c773 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Rope.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Rope.cs @@ -84,6 +84,7 @@ namespace Barotrauma.Items.Components public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1) { if (target == null || target.Removed) { return; } + if (target.ParentInventory != null) { return; } Vector2 startPos = GetSourcePos(); startPos.Y = -startPos.Y; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Turret.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Turret.cs index e78bdf3b2..f4ba37137 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Turret.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Turret.cs @@ -177,6 +177,10 @@ namespace Barotrauma.Items.Components partial void LaunchProjSpecific() { recoilTimer = RetractionTime; + if (user != null) + { + recoilTimer /= 1 + user.GetStatValue(StatTypes.TurretAttackSpeed); + } PlaySound(ActionType.OnUse); Vector2 particlePos = GetRelativeFiringPosition(UseFiringOffsetForMuzzleFlash); foreach (ParticleEmitter emitter in particleEmitters) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Particles/Particle.cs b/Barotrauma/BarotraumaClient/ClientSource/Particles/Particle.cs index 7747a7b16..6b7cd2e8c 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Particles/Particle.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Particles/Particle.cs @@ -378,6 +378,7 @@ namespace Barotrauma.Particles handleCollision(gapFound, collisionNormal); } + collisionNormal = Vector2.Zero; if (velocity.X < 0.0f && position.X - prefab.CollisionRadius * size.X < hullRect.X) { if (prefab.DeleteOnCollision) { return UpdateResult.Delete; } diff --git a/Barotrauma/BarotraumaClient/LinuxClient.csproj b/Barotrauma/BarotraumaClient/LinuxClient.csproj index fb716d58a..33aa1207a 100644 --- a/Barotrauma/BarotraumaClient/LinuxClient.csproj +++ b/Barotrauma/BarotraumaClient/LinuxClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.1500.8.0 + 0.15.11.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma @@ -36,6 +36,7 @@ TRACE;CLIENT;LINUX;USE_STEAM;UNSTABLE x64 ..\bin\$(Configuration)Linux\ + true @@ -48,6 +49,7 @@ TRACE;CLIENT;LINUX;X64;USE_STEAM;UNSTABLE x64 ..\bin\$(Configuration)Linux\ + true diff --git a/Barotrauma/BarotraumaClient/MacClient.csproj b/Barotrauma/BarotraumaClient/MacClient.csproj index ca78c7537..cb3f8eac4 100644 --- a/Barotrauma/BarotraumaClient/MacClient.csproj +++ b/Barotrauma/BarotraumaClient/MacClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.1500.8.0 + 0.15.11.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma @@ -38,7 +38,8 @@ TRACE;CLIENT;OSX;USE_STEAM;RELEASE;NETCOREAPP;NETCOREAPP3_0;UNSTABLE x64 - ..\bin\$(Configuration)Mac + ..\bin\$(Configuration)Mac + true @@ -51,6 +52,7 @@ TRACE;CLIENT;OSX;X64;USE_STEAM;UNSTABLE x64 ..\bin\$(Configuration)Mac\ + true diff --git a/Barotrauma/BarotraumaClient/WindowsClient.csproj b/Barotrauma/BarotraumaClient/WindowsClient.csproj index 9ea6a921c..7645101b6 100644 --- a/Barotrauma/BarotraumaClient/WindowsClient.csproj +++ b/Barotrauma/BarotraumaClient/WindowsClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.1500.8.0 + 0.15.11.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma @@ -40,6 +40,7 @@ TRACE;CLIENT;WINDOWS;USE_STEAM x64 ..\bin\$(Configuration)Windows\ + true @@ -56,6 +57,7 @@ ..\bin\$(Configuration)Windows\ full true + true diff --git a/Barotrauma/BarotraumaServer/LinuxServer.csproj b/Barotrauma/BarotraumaServer/LinuxServer.csproj index 6bf02aa12..f0fec53ed 100644 --- a/Barotrauma/BarotraumaServer/LinuxServer.csproj +++ b/Barotrauma/BarotraumaServer/LinuxServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.1500.8.0 + 0.15.11.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer @@ -36,6 +36,7 @@ TRACE;SERVER;LINUX;USE_STEAM x64 ..\bin\$(Configuration)Linux\ + true @@ -48,6 +49,7 @@ TRACE;SERVER;LINUX;X64;USE_STEAM x64 ..\bin\$(Configuration)Linux\ + true diff --git a/Barotrauma/BarotraumaServer/MacServer.csproj b/Barotrauma/BarotraumaServer/MacServer.csproj index d24dffea7..f129e40bb 100644 --- a/Barotrauma/BarotraumaServer/MacServer.csproj +++ b/Barotrauma/BarotraumaServer/MacServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.1500.8.0 + 0.15.11.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer @@ -41,6 +41,7 @@ x64 ..\bin\ReleaseMac + true @@ -53,6 +54,7 @@ TRACE;SERVER;OSX;X64;USE_STEAM;UNSTABLE x64 ..\bin\$(Configuration)Mac\ + true diff --git a/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterInfo.cs b/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterInfo.cs index 0dba444c6..81abdaf26 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterInfo.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterInfo.cs @@ -26,6 +26,7 @@ namespace Barotrauma partial void OnExperienceChanged(int prevAmount, int newAmount) { + if (Character == null || Character.Removed) { return; } if (prevAmount != newAmount) { GameMain.NetworkMember.CreateEntityEvent(Character, new object[] { NetEntityEvent.Type.UpdateExperience }); diff --git a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/AbandonedOutpostMission.cs b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/AbandonedOutpostMission.cs index e649ec598..99e79fc47 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/AbandonedOutpostMission.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/AbandonedOutpostMission.cs @@ -11,6 +11,7 @@ namespace Barotrauma public override void ServerWriteInitial(IWriteMessage msg, Client c) { + base.ServerWriteInitial(msg, c); msg.Write((ushort)spawnedItems.Count); foreach (Item item in spawnedItems) { diff --git a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/AlienRuinMission.cs b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/AlienRuinMission.cs index 4723cb072..dd8138d18 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/AlienRuinMission.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/AlienRuinMission.cs @@ -6,6 +6,7 @@ namespace Barotrauma { public override void ServerWriteInitial(IWriteMessage msg, Client c) { + base.ServerWriteInitial(msg, c); msg.Write((ushort)existingTargets.Count); foreach (var t in existingTargets) { diff --git a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/BeaconMission.cs b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/BeaconMission.cs deleted file mode 100644 index 0f0a29d29..000000000 --- a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/BeaconMission.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Barotrauma.Networking; - -namespace Barotrauma -{ - partial class BeaconMission : Mission - { - public override void ServerWriteInitial(IWriteMessage msg, Client c) - { - return; - } - } -} diff --git a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/CargoMission.cs b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/CargoMission.cs index e230ab075..10f5ce5ad 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/CargoMission.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/CargoMission.cs @@ -6,6 +6,7 @@ namespace Barotrauma { public override void ServerWriteInitial(IWriteMessage msg, Client c) { + base.ServerWriteInitial(msg, c); msg.Write((ushort)items.Count); foreach (Item item in items) { diff --git a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/CombatMission.cs b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/CombatMission.cs index c7912eb2a..76e83ca8b 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/CombatMission.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/CombatMission.cs @@ -83,10 +83,5 @@ namespace Barotrauma } } } - - public override void ServerWriteInitial(IWriteMessage msg, Client c) - { - //do nothing - } } } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/EscortMission.cs b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/EscortMission.cs index 5cb7f95bb..060369f9a 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/EscortMission.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/EscortMission.cs @@ -9,6 +9,8 @@ namespace Barotrauma { public override void ServerWriteInitial(IWriteMessage msg, Client c) { + base.ServerWriteInitial(msg, c); + if (characters.Count == 0) { throw new InvalidOperationException("Server attempted to write escort mission data when no characters had been spawned."); diff --git a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/MineralMission.cs b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/MineralMission.cs index 8be6f27df..b3dd48bff 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/MineralMission.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/MineralMission.cs @@ -6,6 +6,7 @@ namespace Barotrauma { public override void ServerWriteInitial(IWriteMessage msg, Client c) { + base.ServerWriteInitial(msg, c); msg.Write((byte)caves.Count); foreach (var cave in caves) { diff --git a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/Mission.cs b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/Mission.cs index 4faee3e40..fc1b5041c 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/Mission.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/Mission.cs @@ -16,7 +16,10 @@ namespace Barotrauma GameServer.Log(TextManager.Get("MissionInfo") + ": " + header + " - " + message, ServerLog.MessageType.ServerMessage); } - public abstract void ServerWriteInitial(IWriteMessage msg, Client c); + public virtual void ServerWriteInitial(IWriteMessage msg, Client c) + { + msg.Write((ushort)State); + } public virtual void ServerWrite(IWriteMessage msg) { diff --git a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/MonsterMission.cs b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/MonsterMission.cs index e46a6bf95..937e23511 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/MonsterMission.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/MonsterMission.cs @@ -7,6 +7,8 @@ namespace Barotrauma { public override void ServerWriteInitial(IWriteMessage msg, Client c) { + base.ServerWriteInitial(msg, c); + if (monsters.Count == 0 && monsterPrefabs.Count > 0) { throw new InvalidOperationException("Server attempted to write monster mission data when no monsters had been spawned."); diff --git a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/NestMission.cs b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/NestMission.cs index d1b702aa1..7d5c88bb1 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/NestMission.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/NestMission.cs @@ -8,6 +8,7 @@ namespace Barotrauma public override void ServerWriteInitial(IWriteMessage msg, Client c) { + base.ServerWriteInitial(msg, c); msg.Write((byte)(selectedCave == null || Level.Loaded == null || !Level.Loaded.Caves.Contains(selectedCave) ? 255 : Level.Loaded.Caves.IndexOf(selectedCave))); msg.Write(nestPosition.X); msg.Write(nestPosition.Y); diff --git a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/PirateMission.cs b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/PirateMission.cs index 52b5687be..4eb529c2e 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/PirateMission.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/PirateMission.cs @@ -9,6 +9,8 @@ namespace Barotrauma { public override void ServerWriteInitial(IWriteMessage msg, Client c) { + base.ServerWriteInitial(msg, c); + // duplicate code from escortmission, should possibly be combined, though additional loot items might be added so maybe not if (characters.Count == 0) { diff --git a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/SalvageMission.cs b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/SalvageMission.cs index 1ba55eee5..292d53ce0 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/SalvageMission.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/SalvageMission.cs @@ -15,6 +15,8 @@ namespace Barotrauma public override void ServerWriteInitial(IWriteMessage msg, Client c) { + base.ServerWriteInitial(msg, c); + msg.Write(usedExistingItem); if (usedExistingItem) { diff --git a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/ScanMission.cs b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/ScanMission.cs index 3d3e4f171..dc5dbff31 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/ScanMission.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Events/Missions/ScanMission.cs @@ -6,6 +6,7 @@ namespace Barotrauma { public override void ServerWriteInitial(IWriteMessage msg, Client c) { + base.ServerWriteInitial(msg, c); msg.Write((ushort)startingItems.Count); foreach (var item in startingItems) { diff --git a/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs b/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs index 88069d824..7dafc70d0 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs @@ -214,7 +214,7 @@ namespace Barotrauma c.Character = null; } - if (c.HasSpawned && c.CharacterInfo != null && c.CharacterInfo.CauseOfDeath != null && c.CharacterInfo.CauseOfDeath?.Type != CauseOfDeathType.Disconnected) + if (c.HasSpawned && c.CharacterInfo != null && c.CharacterInfo.CauseOfDeath != null && c.CharacterInfo.CauseOfDeath.Type != CauseOfDeathType.Disconnected) { //the client has opted to spawn this round with Reaper's Tax if (c.WaitForNextRoundRespawn.HasValue && !c.WaitForNextRoundRespawn.Value) @@ -227,7 +227,7 @@ namespace Barotrauma } var characterInfo = c.Character?.Info ?? c.CharacterInfo; if (characterInfo == null) { continue; } - if (characterInfo.CauseOfDeath?.Type != CauseOfDeathType.Disconnected) + if (c.CharacterInfo.CauseOfDeath != null && characterInfo.CauseOfDeath.Type != CauseOfDeathType.Disconnected) { RespawnManager.ReduceCharacterSkills(characterInfo); } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/KarmaManager.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/KarmaManager.cs index e4976ad1a..b0f520261 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/KarmaManager.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/KarmaManager.cs @@ -518,14 +518,22 @@ namespace Barotrauma AdjustKarma(character, karmaIncrease, "Repaired item"); } - public void OnReactorOverHeating(Character character, float deltaTime) + public void OnReactorOverHeating(Item reactor, Character character, float deltaTime) { - AdjustKarma(character, -ReactorOverheatKarmaDecrease * deltaTime, "Caused reactor to overheat"); + if (reactor?.Submarine == null || character == null) { return; } + if (reactor.Submarine.TeamID == CharacterTeamType.FriendlyNPC || reactor.Submarine.TeamID == character.TeamID) + { + AdjustKarma(character, -ReactorOverheatKarmaDecrease * deltaTime, "Caused reactor to overheat"); + } } - public void OnReactorMeltdown(Character character) + public void OnReactorMeltdown(Item reactor, Character character) { - AdjustKarma(character, -ReactorMeltdownKarmaDecrease, "Caused a reactor meltdown"); + if (reactor?.Submarine == null || character == null) { return; } + if (reactor.Submarine.TeamID == CharacterTeamType.FriendlyNPC || reactor.Submarine.TeamID == character.TeamID) + { + AdjustKarma(character, -ReactorMeltdownKarmaDecrease, "Caused a reactor meltdown"); + } } public void OnExtinguishingFire(Character character, float deltaTime) diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/RespawnManager.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/RespawnManager.cs index 41c9a34a9..1d2ab8e2e 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/RespawnManager.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/RespawnManager.cs @@ -11,7 +11,7 @@ namespace Barotrauma.Networking /// /// How much skills drop towards the job's default skill levels when respawning midround in the campaign /// - const float SkillReductionOnCampaignMidroundRespawn = 0.5f; + const float SkillReductionOnCampaignMidroundRespawn = 0.75f; private DateTime despawnTime; diff --git a/Barotrauma/BarotraumaServer/WindowsServer.csproj b/Barotrauma/BarotraumaServer/WindowsServer.csproj index bb6b99dd3..3378b23f1 100644 --- a/Barotrauma/BarotraumaServer/WindowsServer.csproj +++ b/Barotrauma/BarotraumaServer/WindowsServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.1500.8.0 + 0.15.11.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer @@ -38,6 +38,7 @@ TRACE;SERVER;WINDOWS;USE_STEAM x64 ..\bin\$(Configuration)Windows\ + true @@ -54,6 +55,7 @@ ..\bin\$(Configuration)Windows\ full true + true diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs index 6cc7e4886..719417830 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs @@ -426,30 +426,35 @@ namespace Barotrauma } if (EscapeTarget != null) { + var door = EscapeTarget.ConnectedDoor; + bool isClosedDoor = door != null && !door.IsOpen; Vector2 diff = EscapeTarget.WorldPosition - Character.WorldPosition; float sqrDist = diff.LengthSquared(); - if (Character.CurrentHull == null || sqrDist < MathUtils.Pow2(50) || pathSteering == null || IsCurrentPathUnreachable || IsCurrentPathFinished) + bool isClose = sqrDist < MathUtils.Pow2(100); + if (Character.CurrentHull == null || isClose && !isClosedDoor || pathSteering == null || IsCurrentPathUnreachable || IsCurrentPathFinished) { // Very close to the target, outside, or at the end of the path -> try to steer through the gap SteeringManager.Reset(); pathSteering?.ResetPath(); - if (sqrDist < MathUtils.Pow2(50)) - { - // Very close -> just keep steering forward - var forward = VectorExtensions.Forward(Character.AnimController.Collider.Rotation + MathHelper.PiOver2); - SteeringManager.SteeringManual(deltaTime, forward); - } - else if (Character.CurrentHull == null) + Vector2 dir = Vector2.Normalize(diff); + if (Character.CurrentHull == null || isClose) { // Outside -> steer away from the target - SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(-diff)); + if (EscapeTarget.FlowTargetHull != null) + { + SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(EscapeTarget.WorldPosition - EscapeTarget.FlowTargetHull.WorldPosition)); + } + else + { + SteeringManager.SteeringManual(deltaTime, -dir); + } } else { // Still inside -> steer towards the target - SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(diff)); + SteeringManager.SteeringManual(deltaTime, dir); } - return sqrDist < MathUtils.Pow2(200); + return sqrDist < MathUtils.Pow2(250); } else if (pathSteering != null) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/HumanAIController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/HumanAIController.cs index b473ea46c..974af8a20 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/HumanAIController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/HumanAIController.cs @@ -250,7 +250,7 @@ namespace Barotrauma { rayEnd += SelectedAiTarget.Entity.Submarine.SimPosition; } - UseIndoorSteeringOutside = Submarine.PickBody(SimPosition, rayEnd, collisionCategory: Physics.CollisionLevel) != null; + UseIndoorSteeringOutside = Submarine.PickBody(SimPosition, rayEnd, collisionCategory: Physics.CollisionLevel | Physics.CollisionWall) != null; } } else @@ -340,7 +340,7 @@ namespace Barotrauma IsInsideCave = Character.CurrentHull == null && Level.Loaded?.Caves.FirstOrDefault(c => c.Area.Contains(Character.WorldPosition)) is Level.Cave; } - if (UseIndoorSteeringOutside || IsInsideCave || Character.Submarine != null || hasValidPath && IsCloseEnoughToTarget(maxSteeringBuffer) || IsCloseEnoughToTarget(steeringBuffer)) + if (UseIndoorSteeringOutside || IsInsideCave || Character.CurrentHull?.Submarine != null || hasValidPath && IsCloseEnoughToTarget(maxSteeringBuffer) || IsCloseEnoughToTarget(steeringBuffer)) { if (steeringManager != insideSteering) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/IndoorsSteeringManager.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/IndoorsSteeringManager.cs index 603f9da95..cf2635e9d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/IndoorsSteeringManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/IndoorsSteeringManager.cs @@ -1,4 +1,5 @@ -using Barotrauma.Items.Components; +using Barotrauma.Extensions; +using Barotrauma.Items.Components; using Microsoft.Xna.Framework; using System; using System.Linq; @@ -200,10 +201,14 @@ namespace Barotrauma currentTarget = target; Vector2 currentPos = host.SimPosition; pathFinder.InsideSubmarine = character.Submarine != null && !character.Submarine.Info.IsRuin; - pathFinder.ApplyPenaltyToOutsideNodes = character.Submarine != null && character.PressureProtection <= 0; + pathFinder.ApplyPenaltyToOutsideNodes = character.Submarine != null && character.PressureProtection <= 0; var newPath = pathFinder.FindPath(currentPos, target, character.Submarine, "(Character: " + character.Name + ")", minGapSize, startNodeFilter, endNodeFilter, nodeFilter, checkVisibility: checkVisibility); bool useNewPath = needsNewPath || currentPath == null || currentPath.CurrentNode == null || character.Submarine != null && findPathTimer < -1 && Math.Abs(character.AnimController.TargetMovement.X) <= 0; - if (!useNewPath && currentPath != null && currentPath.CurrentNode != null && newPath.Nodes.Any() && !newPath.Unreachable) + if (newPath.Unreachable || newPath.Nodes.None()) + { + useNewPath = false; + } + else if (!useNewPath && currentPath != null && currentPath.CurrentNode != null) { // Check if the new path is the same as the old, in which case we just ignore it and continue using the old path (or the progress would reset). if (IsIdenticalPath()) @@ -215,7 +220,7 @@ namespace Barotrauma // Use the new path if it has significantly lower cost (don't change the path if it has marginally smaller cost. This reduces navigating backwards due to new path that is calculated from the node just behind us). float t = (float)currentPath.CurrentIndex / (currentPath.Nodes.Count - 1); useNewPath = newPath.Cost < currentPath.Cost * MathHelper.Lerp(0.95f, 0, t); - if (!useNewPath) + if (!useNewPath && character.Submarine != null) { // It's possible that the current path was calculated from a start point that is no longer valid. // Therefore, let's accept also paths with a greater cost than the current, if the current node is much farther than the new start node. @@ -557,10 +562,14 @@ namespace Barotrauma { //the node we're heading towards is the last one in the path, and at a door //the door needs to be open for the character to reach the node - if (currentWaypoint.ConnectedDoor.LinkedGap != null && currentWaypoint.ConnectedDoor.LinkedGap.IsRoomToRoom) + if (currentWaypoint.ConnectedDoor.LinkedGap != null) { - shouldBeOpen = true; - door = currentWaypoint.ConnectedDoor; + // Keep the airlock doors closed, but not in ruins/wrecks + if (currentWaypoint.ConnectedDoor.LinkedGap.IsRoomToRoom || currentWaypoint.Submarine?.Info.IsRuin != null || currentWaypoint.Submarine?.Info.IsWreck != null) + { + shouldBeOpen = true; + door = currentWaypoint.ConnectedDoor; + } } } else diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFindDivingGear.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFindDivingGear.cs index 012c3a858..c42d0c6f0 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFindDivingGear.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFindDivingGear.cs @@ -39,6 +39,10 @@ namespace Barotrauma return; } targetItem = character.Inventory.FindItemByTag(gearTag, true); + if (targetItem == null && gearTag == LIGHT_DIVING_GEAR) + { + targetItem = character.Inventory.FindItemByTag(HEAVY_DIVING_GEAR, true); + } if (targetItem == null || !character.HasEquippedItem(targetItem, slotType: InvSlotType.OuterClothes | InvSlotType.Head | InvSlotType.InnerClothes) && targetItem.ContainedItems.Any(i => i.HasTag(OXYGEN_SOURCE) && i.Condition > 0)) { TryAddSubObjective(ref getDivingGear, () => @@ -74,10 +78,7 @@ namespace Barotrauma } else { - // Seek oxygen that has at least 10% condition left, if we are inside a friendly sub. - // The margin helps us to survive, because we might need some oxygen before we can find more oxygen. - // When we are venturing outside of our sub, let's just suppose that we have enough oxygen with us and optimize it so that we don't keep switching off half used tanks. - float min = character.Submarine != Submarine.MainSub ? 0.01f : MIN_OXYGEN; + float min = GetMinOxygen(character); if (targetItem.OwnInventory != null && targetItem.OwnInventory.AllItems.None(it => it != null && it.HasTag(OXYGEN_SOURCE) && it.Condition > min)) { TryAddSubObjective(ref getOxygen, () => @@ -160,5 +161,20 @@ namespace Barotrauma getOxygen = null; targetItem = null; } + + public static float GetMinOxygen(Character character) + { + // Seek oxygen that has at least 10% condition left, if we are inside a friendly sub. + // The margin helps us to survive, because we might need some oxygen before we can find more oxygen. + // When we are venturing outside of our sub, let's just suppose that we have enough oxygen with us and optimize it so that we don't keep switching off half used tanks. + float min = 0.01f; + float minOxygen = character.IsInFriendlySub ? MIN_OXYGEN : min; + if (minOxygen > min && character.Inventory.AllItems.Any(i => i.HasTag("oxygensource") && i.ConditionPercentage >= minOxygen)) + { + // There's a valid oxygen tank in the inventory -> no need to swap the tank too early. + minOxygen = min; + } + return minOxygen; + } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFindSafety.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFindSafety.cs index fe528d9dc..2c8f6a40b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFindSafety.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFindSafety.cs @@ -55,8 +55,8 @@ namespace Barotrauma { if (HumanAIController.NeedsDivingGear(character.CurrentHull, out bool needsSuit) && (needsSuit ? - !HumanAIController.HasDivingSuit(character, conditionPercentage: AIObjectiveFindDivingGear.MIN_OXYGEN) : - !HumanAIController.HasDivingGear(character, conditionPercentage: AIObjectiveFindDivingGear.MIN_OXYGEN))) + !HumanAIController.HasDivingSuit(character, conditionPercentage: AIObjectiveFindDivingGear.GetMinOxygen(character)) : + !HumanAIController.HasDivingGear(character, conditionPercentage: AIObjectiveFindDivingGear.GetMinOxygen(character)))) { Priority = 100; } @@ -131,11 +131,11 @@ namespace Barotrauma bool needsEquipment = false; if (needsDivingSuit) { - needsEquipment = !HumanAIController.HasDivingSuit(character, AIObjectiveFindDivingGear.MIN_OXYGEN); + needsEquipment = !HumanAIController.HasDivingSuit(character, AIObjectiveFindDivingGear.GetMinOxygen(character)); } else if (needsDivingGear) { - needsEquipment = !HumanAIController.HasDivingGear(character, AIObjectiveFindDivingGear.MIN_OXYGEN); + needsEquipment = !HumanAIController.HasDivingGear(character, AIObjectiveFindDivingGear.GetMinOxygen(character)); } if (needsEquipment) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs index f4e156d20..a67611486 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs @@ -260,7 +260,7 @@ namespace Barotrauma } } bool needsEquipment = false; - float minOxygen = character.Submarine == null ? 0 : AIObjectiveFindDivingGear.MIN_OXYGEN; + float minOxygen = AIObjectiveFindDivingGear.GetMinOxygen(character); if (needsDivingSuit) { needsEquipment = !HumanAIController.HasDivingSuit(character, minOxygen); @@ -374,7 +374,7 @@ namespace Barotrauma if (checkScooterTimer <= 0) { useScooter = false; - checkScooterTimer = checkScooterTime; + checkScooterTimer = checkScooterTime * Rand.Range(0.75f, 1.25f); string scooterTag = "scooter"; string batteryTag = "mobilebattery"; Item scooter = null; @@ -525,9 +525,22 @@ namespace Barotrauma { character.CursorPosition -= character.Submarine.Position; } - Vector2 dir = Vector2.Normalize(character.CursorPosition - character.Position); - if (!MathUtils.IsValid(dir)) { dir = Vector2.UnitY; } - SteeringManager.SteeringManual(1.0f, dir); + Vector2 diff = character.CursorPosition - character.Position; + Vector2 dir = Vector2.Normalize(diff); + float sqrDist = diff.LengthSquared(); + if (sqrDist > MathUtils.Pow2(CloseEnough * 1.5f)) + { + SteeringManager.SteeringManual(1.0f, dir); + } + else + { + float dot = Vector2.Dot(dir, VectorExtensions.Forward(character.AnimController.Collider.Rotation + MathHelper.PiOver2)); + bool isFacing = dot > 0.9f; + if (!isFacing && sqrDist > MathUtils.Pow2(CloseEnough)) + { + SteeringManager.SteeringManual(1.0f, dir); + } + } character.SetInput(InputType.Aim, false, true); character.SetInput(InputType.Shoot, false, true); } @@ -535,7 +548,7 @@ namespace Barotrauma private bool useScooter; private float checkScooterTimer; - private readonly float checkScooterTime = 0.2f; + private readonly float checkScooterTime = 0.5f; public Hull GetTargetHull() => GetTargetHull(Target); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveIdle.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveIdle.cs index 8d496ac2c..4be1b47fd 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveIdle.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveIdle.cs @@ -282,7 +282,7 @@ namespace Barotrauma } } newTargetTimer -= deltaTime; - if (!character.IsClimbing && IsSteeringFinished()) + if (!character.IsClimbing && (PathSteering == null || PathSteering.CurrentPath == null || IsSteeringFinished())) { Wander(deltaTime); } @@ -393,9 +393,10 @@ namespace Barotrauma hullWeights.Clear(); foreach (var hull in Hull.hullList) { + if (character.Submarine == null) { break; } if (HumanAIController.UnsafeHulls.Contains(hull)) { continue; } if (hull.Submarine == null) { continue; } - if (character.Submarine == null) { break; } + if (hull.Submarine.Info.IsRuin || hull.Submarine.Info.IsWreck) { continue; } if (character.TeamID == CharacterTeamType.FriendlyNPC && !character.IsEscorted) { if (hull.Submarine.TeamID != character.TeamID) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveReturn.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveReturn.cs index 4ed0d0ee3..78d80ac98 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveReturn.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveReturn.cs @@ -88,6 +88,28 @@ namespace Barotrauma targetHull = d.Item.CurrentHull; break; } + if (targetHull != null && !targetHull.IsTaggedAirlock()) + { + // Target the closest airlock + float closestDist = 0; + Hull airlock = null; + foreach (Hull hull in Hull.hullList) + { + if (hull.Submarine != targetHull.Submarine) { continue; } + if (!hull.IsTaggedAirlock()) { continue; } + float dist = Vector2.DistanceSquared(targetHull.Position, hull.Position); + if (airlock == null || closestDist <= 0 || dist < closestDist) + { + airlock = hull; + closestDist = dist; + } + + } + if (airlock != null) + { + targetHull = airlock; + } + } if (targetHull != null) { RemoveSubObjective(ref moveInCaveObjective); @@ -95,7 +117,8 @@ namespace Barotrauma TryAddSubObjective(ref moveInsideObjective, constructor: () => new AIObjectiveGoTo(targetHull, character, objectiveManager) { - AllowGoingOutside = true + AllowGoingOutside = true, + endNodeFilter = n => n.Waypoint.Submarine == targetHull.Submarine }, onCompleted: () => RemoveSubObjective(ref moveInsideObjective), onAbandon: () => Abandon = true); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PathFinder.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PathFinder.cs index 2736e235b..e46839e24 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PathFinder.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PathFinder.cs @@ -198,7 +198,7 @@ namespace Barotrauma } float xDiff = Math.Abs(start.X - node.TempPosition.X); float yDiff = Math.Abs(start.Y - node.TempPosition.Y); - if (InsideSubmarine) + if (InsideSubmarine && !(node.Waypoint.Submarine?.Info?.IsRuin ?? false)) { //higher cost for vertical movement when inside the sub if (yDiff > 1.0f && node.Waypoint.Ladders == null && node.Waypoint.Stairs == null) @@ -215,6 +215,13 @@ namespace Barotrauma //much higher cost to waypoints that are outside if (node.Waypoint.CurrentHull == null && ApplyPenaltyToOutsideNodes) { node.TempDistance *= 10.0f; } + //optimization: + //node extremely far, don't try to use it as a start node + if (node.TempDistance > 800.0f) + { + continue; + } + //prefer nodes that are closer to the end position node.TempDistance += (Math.Abs(end.X - node.TempPosition.X) + Math.Abs(end.Y - node.TempPosition.Y)) / 100.0f; @@ -248,19 +255,17 @@ namespace Barotrauma PathNode startNode = null; foreach (PathNode node in sortedNodes) { - if (startNode == null || node.TempDistance < startNode.TempDistance) + if (nodeFilter != null && !nodeFilter(node)) { continue; } + if (startNodeFilter != null && !startNodeFilter(node)) { continue; } + // Always check the visibility for the start node + if (!IsWaypointVisible(node, start)) { continue; } + if (node.IsBlocked()) { continue; } + if (node.Waypoint.ConnectedGap != null) { - if (nodeFilter != null && !nodeFilter(node)) { continue; } - if (startNodeFilter != null && !startNodeFilter(node)) { continue; } - // Always check the visibility for the start node - if (!IsWaypointVisible(node, start)) { continue; } - if (node.IsBlocked()) { continue; } - if (node.Waypoint.ConnectedGap != null) - { - if (!CanFitThroughGap(node.Waypoint.ConnectedGap, minGapSize)) { continue; } - } - startNode = node; + if (!CanFitThroughGap(node.Waypoint.ConnectedGap, minGapSize)) { continue; } } + startNode = node; + break; } if (startNode == null) @@ -301,19 +306,17 @@ namespace Barotrauma PathNode endNode = null; foreach (PathNode node in sortedNodes) { - if (endNode == null || node.TempDistance < endNode.TempDistance) + if (nodeFilter != null && !nodeFilter(node)) { continue; } + if (endNodeFilter != null && !endNodeFilter(node)) { continue; } + // Only check the visibility for the end node when allowed (fix leaks) + if (!IsWaypointVisible(node, end, checkVisibility: checkVisibility)) { continue; } + if (node.IsBlocked()) { continue; } + if (node.Waypoint.ConnectedGap != null) { - if (nodeFilter != null && !nodeFilter(node)) { continue; } - if (endNodeFilter != null && !endNodeFilter(node)) { continue; } - // Only check the visibility for the end node when allowed (fix leaks) - if (!IsWaypointVisible(node, end, checkVisibility: checkVisibility)) { continue; } - if (node.IsBlocked()) { continue; } - if (node.Waypoint.ConnectedGap != null) - { - if (!CanFitThroughGap(node.Waypoint.ConnectedGap, minGapSize)) { continue; } - } - endNode = node; + if (!CanFitThroughGap(node.Waypoint.ConnectedGap, minGapSize)) { continue; } } + endNode = node; + break; } if (endNode == null) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs index 2a6ece320..5913768c7 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs @@ -1103,7 +1103,7 @@ namespace Barotrauma public void Update(float deltaTime, Camera cam) { - if (!character.Enabled || Frozen || Invalid) { return; } + if (!character.Enabled || character.Removed || Frozen || Invalid || Collider == null || Collider.Removed) { return; } while (impactQueue.Count > 0) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs index 4118df6c9..8edc9b797 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs @@ -4579,9 +4579,9 @@ namespace Barotrauma private readonly Dictionary abilityResistances = new Dictionary(); - public float GetAbilityResistance(string resistanceId) + public float GetAbilityResistance(AfflictionPrefab affliction) { - return abilityResistances.TryGetValue(resistanceId, out float value) ? value : 1f; + return abilityResistances.TryGetValue(affliction.Identifier, out float value) ? value : abilityResistances.TryGetValue(affliction.AfflictionType, out float typeValue) ? typeValue : 1f; } public void ChangeAbilityResistance(string resistanceId, float value) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs index 08c342288..cd9c653a5 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs @@ -226,6 +226,15 @@ namespace Barotrauma return UnlockedTalents.Where(t => talentTree.TalentIsInTree(t)); } + /// + /// Endocrine boosters can unlock talents outside the user's talent tree. This method is used to specifically get them + /// + public IEnumerable GetEndocrineTalents() + { + if (!TalentTree.JobTalentTrees.TryGetValue(Job.Prefab.Identifier, out TalentTree talentTree)) { return Enumerable.Empty(); } + + return UnlockedTalents.Where(t => !talentTree.TalentIsInTree(t)); + } public int AdditionalTalentPoints { get; set; } @@ -1233,10 +1242,9 @@ namespace Barotrauma { Character?.CheckTalents(AbilityEffectType.OnGainMissionExperience, experienceGainMultiplier); } - experienceGainMultiplier.Value += Character.GetStatValue(StatTypes.ExperienceGainMultiplier); + experienceGainMultiplier.Value += Character?.GetStatValue(StatTypes.ExperienceGainMultiplier) ?? 0; amount = (int)(amount * experienceGainMultiplier.Value); - if (amount < 0) { return; } ExperiencePoints += amount; @@ -1252,8 +1260,8 @@ namespace Barotrauma OnExperienceChanged(prevAmount, ExperiencePoints); } - const int BaseExperienceRequired = 50; - const int AddedExperienceRequiredPerLevel = 450; + const int BaseExperienceRequired = -50; + const int AddedExperienceRequiredPerLevel = 550; public int GetTotalTalentPoints() { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs index 8a6f55e00..9980cb396 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs @@ -458,7 +458,7 @@ namespace Barotrauma { resistance += afflictions[i].GetResistance(affliction); } - return 1 - ((1 - resistance) * Character.GetAbilityResistance(affliction.Identifier)); + return 1 - ((1 - resistance) * Character.GetAbilityResistance(affliction)); } public float GetStatValue(StatTypes statType) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityGiveResistance.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityGiveResistance.cs index af08e66bc..253dd787b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityGiveResistance.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityGiveResistance.cs @@ -10,7 +10,7 @@ namespace Barotrauma.Abilities public CharacterAbilityGiveResistance(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement) { resistanceId = abilityElement.GetAttributeString("resistanceid", abilityElement.GetAttributeString("resistance", string.Empty)); - multiplier = abilityElement.GetAttributeFloat("multiplier", 1f); + multiplier = abilityElement.GetAttributeFloat("multiplier", 1f); // rename this to resistance for consistency if (string.IsNullOrEmpty(resistanceId)) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/GoToMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/GoToMission.cs index 3b077be2c..cb8508f9d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/GoToMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/GoToMission.cs @@ -13,16 +13,5 @@ namespace Barotrauma { State = 1; } - -#if CLIENT - public override void ClientReadInitial(IReadMessage msg) - { - } -#elif SERVER - - public override void ServerWriteInitial(IWriteMessage msg, Client c) - { - } -#endif } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/Mission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/Mission.cs index a0c9c2c07..507d7b61f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/Mission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/Mission.cs @@ -347,7 +347,7 @@ namespace Barotrauma if (!(GameMain.GameSession.GameMode is CampaignMode campaign)) { return; } int reward = GetReward(Submarine.MainSub); - float baseExperienceGain = reward * 0.1f; + float baseExperienceGain = reward * 0.09f; float difficultyMultiplier = 1 + level.Difficulty / 100f; baseExperienceGain *= difficultyMultiplier; diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSettings.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSettings.cs index 56915b462..b8b37bcc3 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSettings.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSettings.cs @@ -942,6 +942,7 @@ namespace Barotrauma } doc.Root.Add( + new XAttribute("gameversion", GameMain.Version.ToString()), new XAttribute("language", TextManager.Language), new XAttribute("masterserverurl", MasterServerUrl), new XAttribute("autocheckupdates", AutoCheckUpdates), diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/GeneticMaterial.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/GeneticMaterial.cs index 3f65446a4..ae34d86fe 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/GeneticMaterial.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/GeneticMaterial.cs @@ -158,7 +158,7 @@ namespace Barotrauma.Items.Components if (!CanBeCombinedWith(otherGeneticMaterial)) { return false; } float conditionIncrease = Rand.Range(ConditionIncreaseOnCombineMin, ConditionIncreaseOnCombineMax); - conditionIncrease *= 1.0f + user.GetStatValue(StatTypes.GeneticMaterialRefineBonus); + conditionIncrease += user.GetStatValue(StatTypes.GeneticMaterialRefineBonus); if (item.Prefab == otherGeneticMaterial.item.Prefab) { item.Condition = Math.Max(item.Condition, otherGeneticMaterial.item.Condition) + conditionIncrease; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Holdable.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Holdable.cs index 1449bf5cf..e88c44e43 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Holdable.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Holdable.cs @@ -781,7 +781,7 @@ namespace Barotrauma.Items.Components if (!aim) { var rope = GetRope(); - if (rope != null && rope.SnapWhenNotAimed) + if (rope != null && rope.SnapWhenNotAimed && rope.Item.ParentInventory == null) { rope.Snap(); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/RangedWeapon.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/RangedWeapon.cs index 0966ea92f..a07db8e19 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/RangedWeapon.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/RangedWeapon.cs @@ -198,7 +198,11 @@ namespace Barotrauma.Items.Components Vector2 barrelPos = TransformedBarrelPos + item.body.SimPosition; float rotation = (Item.body.Dir == 1.0f) ? Item.body.Rotation : Item.body.Rotation - MathHelper.Pi; float spread = GetSpread(character) * Rand.Range(-0.5f, 0.5f); - LastProjectile?.Item.GetComponent()?.Snap(); + var lastProjectile = LastProjectile; + if (lastProjectile != projectile) + { + lastProjectile?.Item.GetComponent()?.Snap(); + } float damageMultiplier = 1f + item.GetQualityModifier(Quality.StatType.AttackMultiplier); projectile.Shoot(character, character.AnimController.AimSourceSimPos, barrelPos, rotation + spread, ignoredBodies: limbBodies.ToList(), createNetworkEvent: false, damageMultiplier); projectile.Item.GetComponent()?.Attach(Item, projectile.Item); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Reactor.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Reactor.cs index bac4219d8..8655b2618 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Reactor.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Reactor.cs @@ -494,15 +494,12 @@ namespace Barotrauma.Items.Components { float prevFireTimer = fireTimer; fireTimer += MathHelper.Lerp(deltaTime * 2.0f, deltaTime, item.Condition / item.MaxCondition); - - #if SERVER if (fireTimer > Math.Min(5.0f, FireDelay / 2) && blameOnBroken?.Character?.SelectedConstruction == item) { - GameMain.Server.KarmaManager.OnReactorOverHeating(blameOnBroken.Character, deltaTime); + GameMain.Server.KarmaManager.OnReactorOverHeating(item, blameOnBroken.Character, deltaTime); } #endif - if (fireTimer >= FireDelay && prevFireTimer < fireDelay) { new FireSource(item.WorldPosition); @@ -591,7 +588,7 @@ namespace Barotrauma.Items.Components GameServer.Log("Reactor meltdown!", ServerLog.MessageType.ItemInteraction); if (GameMain.Server != null) { - GameMain.Server.KarmaManager.OnReactorMeltdown(blameOnBroken?.Character); + GameMain.Server.KarmaManager.OnReactorMeltdown(item, blameOnBroken?.Character); } #endif } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs index f44619825..8cc3945de 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs @@ -614,10 +614,17 @@ namespace Barotrauma.Items.Components return; } + //target very far from the item -> update the item's transform to make sure it's inside the same sub as the target (or outside) + if (Math.Abs(stickJoint.JointTranslation) > 100.0f) + { + item.UpdateTransform(); + } + if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) { if (StickTargetRemoved() || - (!StickPermanently && (stickJoint.JointTranslation < stickJoint.LowerLimit * 0.9f || stickJoint.JointTranslation > stickJoint.UpperLimit * 0.9f))) + (!StickPermanently && (stickJoint.JointTranslation < stickJoint.LowerLimit * 0.9f || stickJoint.JointTranslation > stickJoint.UpperLimit * 0.9f)) || + Math.Abs(stickJoint.JointTranslation) > 100.0f) //failsafe unstick if the target is still extremely far { Unstick(); #if SERVER diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Repairable.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Repairable.cs index d36c11e6f..3ff601550 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Repairable.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Repairable.cs @@ -406,15 +406,7 @@ namespace Barotrauma.Items.Components fixDuration /= 1 + CurrentFixer.GetStatValue(StatTypes.RepairSpeed) + currentRepairItem?.Prefab.AddedRepairSpeedMultiplier ?? 0f; fixDuration /= 1 + item.GetQualityModifier(Quality.StatType.RepairSpeed); - // kind of rough to keep this in update, but seems most robust - if (requiredSkills.Any(s => s != null && s.Identifier.Equals("mechanical", StringComparison.OrdinalIgnoreCase))) - { - item.MaxRepairConditionMultiplier = 1 + CurrentFixer.GetStatValue(StatTypes.MaxRepairConditionMultiplierMechanical); - } - if (requiredSkills.Any(s => s != null && s.Identifier.Equals("electrical", StringComparison.OrdinalIgnoreCase))) - { - item.MaxRepairConditionMultiplier = 1 + CurrentFixer.GetStatValue(StatTypes.MaxRepairConditionMultiplierElectrical); - } + item.MaxRepairConditionMultiplier = GetMaxRepairConditionMultiplier(CurrentFixer); if (currentFixerAction == FixActions.Repair) { @@ -489,6 +481,21 @@ namespace Barotrauma.Items.Components } } + private float GetMaxRepairConditionMultiplier(Character character) + { + if (character == null) { return 1.0f; } + // kind of rough to keep this in update, but seems most robust + if (requiredSkills.Any(s => s != null && s.Identifier.Equals("mechanical", StringComparison.OrdinalIgnoreCase))) + { + return 1 + character.GetStatValue(StatTypes.MaxRepairConditionMultiplierMechanical); + } + if (requiredSkills.Any(s => s != null && s.Identifier.Equals("electrical", StringComparison.OrdinalIgnoreCase))) + { + return 1 + character.GetStatValue(StatTypes.MaxRepairConditionMultiplierElectrical); + } + return 1.0f; + } + private bool IsTinkerable(Character character) { if (!character.HasAbilityFlag(AbilityFlags.CanTinker)) { return false; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Rope.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Rope.cs index de4ae2389..6e9836551 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Rope.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Rope.cs @@ -95,6 +95,10 @@ namespace Barotrauma.Items.Components } } snapped = value; + if (!snapped) + { + snapTimer = 0; + } } } @@ -113,6 +117,7 @@ namespace Barotrauma.Items.Components System.Diagnostics.Debug.Assert(target != null); this.source = source; this.target = target; + Snapped = false; ApplyStatusEffects(ActionType.OnUse, 1.0f, worldPosition: item.WorldPosition); IsActive = true; } @@ -148,6 +153,7 @@ namespace Barotrauma.Items.Components #endif var projectile = target.GetComponent(); if (projectile == null) { return; } + if (SnapOnCollision) { raycastTimer += deltaTime; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs index 33a9253af..2fd8b35e8 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs @@ -1323,7 +1323,7 @@ namespace Barotrauma } Submarine = parentInventory.Owner.Submarine; - if (body != null) body.Submarine = Submarine; + if (body != null) { body.Submarine = Submarine; } return CurrentHull; } @@ -1733,10 +1733,18 @@ namespace Barotrauma public void UpdateTransform() { if (body == null) { return; } - Submarine prevSub = Submarine; - FindHull(); + var projectile = GetComponent(); + if (projectile?.StickTarget?.UserData is Limb limb) + { + Submarine = body.Submarine = limb.character?.Submarine; + currentHull = limb.character?.CurrentHull; + } + else + { + FindHull(); + } if (Submarine == null && prevSub != null) { @@ -1814,6 +1822,12 @@ namespace Barotrauma { if (transformDirty) { return false; } + var projectile = GetComponent(); + if (projectile?.IgnoredBodies != null) + { + if (projectile.IgnoredBodies.Contains(f2.Body)) { return false; } + } + contact.GetWorldManifold(out Vector2 normal, out _); if (contact.FixtureA.Body == f1.Body) { normal = -normal; } float impact = Vector2.Dot(f1.Body.LinearVelocity, -normal); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs index eefafeeab..698b5fbde 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs @@ -1964,11 +1964,11 @@ namespace Barotrauma Vector2 entranceDir = Vector2.Zero; if (g.IsHorizontal) { - entranceDir = Vector2.UnitX * Math.Sign(g.WorldPosition.X - g.linkedTo[0].WorldPosition.X); + entranceDir = Vector2.UnitX * 2 * Math.Sign(g.WorldPosition.X - g.linkedTo[0].WorldPosition.X); } else { - entranceDir = Vector2.UnitY * Math.Sign(g.WorldPosition.Y - g.linkedTo[0].WorldPosition.Y); + entranceDir = Vector2.UnitY * 2 * Math.Sign(g.WorldPosition.Y - g.linkedTo[0].WorldPosition.Y); } var entranceWayPoint = new WayPoint(g.WorldPosition + entranceDir * 64.0f, SpawnType.Path, null) { diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index 9ef824a3c..de4346bc7 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,148 +1,69 @@ --------------------------------------------------------------------------------------------------------- -v0.1500.8.0 +v0.15.11.0 --------------------------------------------------------------------------------------------------------- -Additions and changes: -- More improvements and fixes to the alien ruins and the new fractal guardians. -- Improvements to character animations and sprites. -- Made ruin scan/clear missions available in outposts. -- Talent adjustments and fixes. -- Adjustments to outpost distribution: natural formations greatly reduced in the 1st zone, cities slightly reduced in the 1st zone, outposts (including specialized ones) increased in the 3rd and 4th zone. -- Made magnesium a little more common in stores and wrecks. -- Temporarily disabled magnesium exploding in water to prevent issues with talents related to it. -- Added an additonal ambience track for the ruins. -- New sounds for alien ruins and the guardians. -- Portable pumps turn off automatically when not attached to a wall. - -Fixes: -- Fixed outpost events always unlocking the same escort mission. -- Fixed server occasionally failing to end the round and spamming the clients with XP notifications. Happened when the server was trying to give experience for the completed missions and there were clients in the server whose character had been removed (unstable only). -- Fixed shotgun shells not having a fabrication recipe (unstable only). -- Fixed thermal goggles being sold in outposts (unstable only). -- Fixes to ruin waypoint generation (unstable only). -- Fixes to pathfinding outside ruins (unstable only). -- Fixed oxygen generator output constantly decreasing due to the changes in the previous build (unstable only). -- Fixed long item names being unreadable on the fabricator UI. -- The hints about flooded rooms and ballast flora aren't shown in ruins, wrecks or enemy subs. -- Fixed "setclientcharacter" command crashing the server if the specified character is not found. -- Fixed autofilling subs with supplies sometimes causing high-quality items to appear on the floor near containers (unstable only). -- Fixed guardian spears being fabricatable (unstable only). -- Fixed "stowaway" event triggering an event cooldown, preventing monsters from spawning at the beginning of the round. -- Fixed clients (excluding the host) always considering friendly fire to be disabled, leading to minor cosmetic desyncs when a player applies afflictions on another one (i.e. there was a brief delay before the afflictions update client-side). -- Fixed inability to apply buffs on the crew when friendly fire is disabled. -- Fixed ItemContainers only applying the StatusEffects from the first matching Containable, even if there's multiple. Prevented the artifact-specific effects of artifact holder from executing. -- Fixed "giveaffliction" command's limbtype argument not working in multiplayer. +- New icons for the new ruin missions. +- Slightly reduced the amount of experience given by missions and increased the amount of experience required to unlock a talent point. +- Made escort missions more common. +- The creature attack keybind is automatically switched from R to the new default keybind F when loading up the new update for the first time. +- Fixes to ruin waypoints. +- Fixes to outdoors pathfinding. +- Fixes to fractal guardians' aiming. --------------------------------------------------------------------------------------------------------- -v0.1500.7.0 +v0.15.10.0 --------------------------------------------------------------------------------------------------------- -Additions and changes: -- More improvements and fixes to the alien ruins and the new fractal guardians. -- Added a colored border to high-quality items' inventory slots. -- Changed the look of the skill/xp notifications to accommodate the larger numbers of notifications you can get from talents and skillbooks. -- Added a fabricator and deconstructor to Azimuth and slightly lowered its maximum speed. -- Increased Azimuth's battery out relay max power. -- Field Medic now only triggers on missions. -- Reduced gravity sphere's force to make it possible to escape it with a diving suit on. -- Diving suit and human ragdoll damagemodifier changes: the suits now offer less protection, but humans have a bit more natural protection towards physical damage types. - -Fixes: -- Fixed outpost generator sometimes using ruin hallways in normal outposts (unstable only). -- Fixed ability to put fuel rods in reactors with the Reactor PDA (unstable only). -- Fixed Reactor PDA interface popping up when the item is picked up (unstable only). -- Fixed talents that increase max mission count increasing it every round (unstable only). -- Fixed talent unlock notifications being shown at the beginning of every round (unstable only). -- Fixed husks holding hands in an incorrect orientation when they run (unstable only). -- Fixed "all-seeing eye" talent crashing the game (unstable only). -- Fixed high-quality rods disappearing when deconstructed (unstable only). -- Fixes to the colliders of the new items (unstable only). -- Dementonite tools aren't sold in outposts (unstable only). -- Fixed buccaneer talent's power attack ability not working (unstable only). -- Fixed "strengthened alloys" not unlocking the hardened tool recipes (unstable only). -- Fixes to ruin waypoints (unstable only). -- Fixed limbs without a sprite (e.g. carrier's invisible limb that only serves as a spotlight) causing a crash (unstable only). -- Fixed hidden items appearing in the job loadout preview if there are other items of the same type that are not hidden (didn't affect any vanilla loadouts). -- Fixed diving suits hiding the weapons held in the bag slot. -- Fixes to oxygen generator logic: the generator now periodically recalculates how to distribute the oxygen between the vents, as opposed to doing it once at the start of the round. Just doing it once caused issues if there were e.g. vents or doors that are initially open between the rooms. -- Fixed some connection panels in alien ruins being rewireable without a screwdriver, when they shouldn't be rewireable at all (unstable only). -- Fixed monster ranged attacks playing a damage sound when they "hit", when the monster shoots (unstable). -- Fixed moving the cursor on an UI element interrupting the usage of scooters or other items that are used by holding LMB and RMB (unstable only). -- Fixed characters sometimes getting "stuck" when swimming in partially filled multi-hull rooms. Happened because the bottom of the current hull was used as the "floor" if the actual floor was too far below, even if there was another hull below the current one, causing the ragdoll to switch to walking animation and being unable to move because it's not touching the floor (unstable only). -- Fixed characters getting permanently stunned if they get a forced stun (e.g. by getting hit by a door) while godmode is on. -- Fixed console errors when an item a bot has been ordered to target was removed between rounds (e.g. an ignore order targeting a mission item that gets removed at the end of the round). -- The "Still Kicking" talent doesn't remove genetic afflictions or buffs (unstable only). +- Fixed character skills reducing after every round. +- Fixed psychosis artifact doing burn damage when picked up. +- Fixed a bunch of pathfinding issues when bots are trying to navigate out from the ruins and/or return back to the sub. +- Fixed bots not being able to swap oxygen tanks in the ruins. +- Fixed railgun lights having an excessively high power consumption, causing them to immediately drain the supercapacitors. +- Fixed occasional crashes when clearing the item search bar that is already empty in the status monitor. +- Fixed ruin generator sometimes leaving empty space between some of the modules and the hallways connected to them. +- Fixed alien gas vents affecting the monsters inside ruins. +- Fixed background wall not extending all the way to the edge of one of the outpost docking modules. +- Fixed harpoon rope sometimes being drawn when it's already snapped. --------------------------------------------------------------------------------------------------------- -v0.1500.6.0 +v0.15.9.0 --------------------------------------------------------------------------------------------------------- -Additions and changes: -- Improvements and additions to the alien ruins and the new fractal guardians. -- More improvements and fixes to the overhauled character sprites and animations. -- Upgrade system reworked to work better in conjunction with new talents and quality systems. Quality of life upgrades made better or cheaper, hull upgrades are less effective towards the lategame but are better early, reorganized categories. -- Talent adjustments and balancing. -- Nerfed thermal goggles: some enemies are invisible to them and targets behind walls are much less clear. -- Removed the "burndamage" damage type (not the same as "burn") that was added as a temporary workaround to allow pulse lasers to bypass monster's damage modifiers. -- Made welding tools a bit less effective early to compensate for increases to their effectiveness from quality/talents. -- Fuel tanks, rods, grenades and other quality-based items can be stacked again. Items of different qualities still can't be put in the same stack. -- Endocrine Booster now gives a random talent. -- New sprite for the mudraptor beak grown by splicing mudraptor genes. -- Fabricating fuel rods now requirse electrical skills instead of mechanical. -- Reactor now requires electrical skills instead of mechanical to repair. -- When the status monitor receives the oxygen/water level for a hull, it registers it on all the linked hulls as well (-> no need to put an oxygen/water detector in all the hulls of a multi-hull room). -- Changed how skillbooks work: the skills are gained when you "finish" reading the book instead of continuously to prevent UI message spam and overlap, the books can be used on others in the health interface or by hitting them with the book. -- Color the selected (but unapplied) talent icons orange instead of changing the icon in the talent UI, made the apply button flash when there's unapplied talents. -- Merged status monitor's status and hull condition tabs. -- Halved concussion's damage threshold to make it possible for more sources of damage to trigger it, + halved the probability to compensate. - -Fixes: -- Fixed high-quality batteries/tanks (or other items with an increased max condition) spawning in non-full condition (unstable only). -- Fixed ropes sometimes crashing the game (unstable only). -- Fixed some items occasionally disappearing from outposts when re-entering them. The most noticeable symptom was wires disappearing from the outpost's airlock, preventing the hatch from opening (unstable only). -- Fixed multiplayer campaign characters resetting if they're dead when the round ends. -- Fixed clients who aren't currently controlling a character not getting XP in the mp campaign (unstable only). -- The overdosed NPC in the "good samaritan" event can't die until the player has triggered the event (completing the event after the NPC had already died made no sense). -- Fixed paralyzant (and many other meds that don't do direct damage) not triggering guards. -- Fixed sonar monitor's UI being unnecessarily small. -- Fixed contained items inside contained items (e.g. magazines in a rifle on a weapon holder) not rotating in the sub editor. -- Fixed boarding axe (unstable only). -- Fixed signal source being wrong on delayed electrical signals (= signals that were delayed for the next frame after they'd passed through 10 steps). Most noticeably affected status monitors that need to know which oxygen/water detector a signal came from. -- Fixed WifiComponents delaying the signals based on the number of receivers, not how many steps the signal has actually taken, contributing to the previous issue. -- Hopefully fixed an oversight in sub editor where changing ItemComponent color with HSV picker would create an error in the console. -- Fixed inability to hit downed characters with short melee weapons like the diving knife. -- Fixed inability to sell nasonov and faraday artifacts (unstable only). -- Fixed concussion description (unstable only). -- Fixes gender-specific affliction sound effects (e.g. vomiting) not playing (unstable only). -- Fixed humans' "aim source position" being too low, causing aim to be slightly off (unstable only). -- Fixed artifact transport case displaying as empty when there's a nasonov/faraday artifact inside (unstable only). -- Fixed "infiltration" event getting stuck on one of the conversation options. -- Fixed ruin's physics bodies being dynamic in mirrored levels (causing them to sink). -- Backwards compatibility: assign skin colors to characters saved in previous versions. -- Assign random skin/hair colors to characters without one configured instead of defaulting to white. Fixes all tutorial characters having white skin/hair. -Modding: -- Added support for tileable light textures for Structures by using XML element that has the same syntax as does for Items. -- Added "InPressure" property to characters. - ---------------------------------------------------------------------------------------------------------- -v0.1500.5.0 ---------------------------------------------------------------------------------------------------------- - -Additions and changes: +Alien ruin overhaul: - Overhauled ruins: completely remade sprites, monsters, layouts, items and puzzles. - New Scan mission: scan an Alien ruin by placing down provided scanners at target locations and take the scanners back to the outpost. - New Alien Ruin mission: kill the guardians inhabiting the ruin and destroy their pods. -- Improvements and fixes to the overhauled character sprites and animations. -- More talent improvements and additions. -- Cap the amount argument of the spawnitem command to 100 to prevent freezing/crashing when trying to spawn a ridiculous amount of the item. -- Nerfed concussions: they now require a larger amount of damage to the head to trigger and slowly heal by themselves. -- Added "unlocktalents [job]" command. -- Don't reset the selected limb when reopening the health interface. -- Bots no longer ignore unconscious targets that regenerate health (i.e. they will finish off downed husks to prevent them from getting back up again). -- The health interface displays a prediction of how much a medical item will reduce/increase the afflictions. -- Certain afflictions make the characters' face change color a bit. -- Added button to randomize character appearance in the character customization menus. -- Permanently reduce character skills when respawning mid-round. The talent system makes it easier to gain skills and permanent improvements to the character, and this change is intended to balance that out. +- Added an additional ambience track for the ruins. + +Character overhaul: +- Completely remade character sprites, ragdolls and animations. +- Option to customize the starting crew in the single player campaign. +- More customization options (skin, hair and facial hair colors, more accessories). +- Added a button to randomize character appearance in the character customization menus. + +Health system improvements: +- Streamlined the health interface. +- Allow administering meds by clicking on the "suitable treatments" suggestions in the health interface. +- The health interface displays a prediction of how much a medical item will reduce/increase the afflictions when hovering the cursor over one. +- Certain afflictions can make the characters' face or body change color. +- Physical injuries to the head can cause concussions. +- Improvements to the blood particle effects when a character is bleeding. +- Damage to arms reduces aiming accuracy. +- Crippled legs slow the player down more. + +Talent system: +- The new talent system allows you to unlock things such as special skills, buffs and fabrication recipes in the course of a campaign, with experience points gained from completing missions. +- Three different talent trees for all the character classes. +- Dozens of new items. +- Item quality system: certain talents allow you to fabricate higher-quality versions of items. +- Characters lose some skill points when respawning mid-round. The talent system makes it easier to gain skills and permanent improvements to the character, and this change is intended to balance that out. + +Overhauled status monitor: +- Improved visuals. +- Indicates the locations of the crew's ID cards. +- Indicates the locations of alerts. +- Electrical view, indicating locations and health of junction boxes, reactor and batteries. +- Allows searching for items and indicating the hulls in which they're located. Balance changes: - Reduced loot in wrecks. @@ -151,185 +72,44 @@ Balance changes: - Disabled stacking quality-based items (experimental change, feedback is welcome). - Reduced diving suits damage resistances. - Buffed vigor and haste. -- Modifed characters' base vitalities. +- Modified characters' base vitalities. - Adjustments to monster stats. - Reduced mission experience gains, level difficulty affects mission experience. - -Fixes: -- Fixed crash when firing a syring gun (unstable only). -- Fixed crashing when using meds in multiplayer with friendly fire turned off (unstable only). -- Fixed inability to repair with hardened/dementonite wrenches (unstable only). -- Fixed item quality not persisting between rounds (unstable only). -- Fixed fabricator not outputting high-quality items in full condition if the item's quality modifiers increase the max condition (unstable). -- Display the max condition of the required item on the fabricator (i.e. show that depleted fuel needs to be fabricated from depleted fuel rods). -- Fixed holdable components that block players (e.g. mudraptor shells) causing a "you are removing a body that is not in the simulation" exception when ending a round (unstable only). -- Fixed handheld status monitor and electrical monitor UIs popping up when picking up the item. -- Fixed tracer particles not starting from the position of ranged weapons' barrel. -- Fixed inability to open the pause menu when the cursor is over an inventory slot. -- Fixed handcuffs dropping off from characters' hands when they die or turn into a husk. -- Fixed ability to crouch on ladders (unstable only). -- Fixed loadsub command. - ---------------------------------------------------------------------------------------------------------- -v0.1500.4.0 ---------------------------------------------------------------------------------------------------------- - -- Overhauled character sprites, ragdolls and animations (WIP). -- Option to customize the starting crew in the single player campaign. -- Talent improvements and additions. -- Merged the talent and character tabs in the tab menu. -- Disable deconstructor button when there's no deconstructable items in the input slots (also applies to research terminals which are technically deconstructors). - -Fixes: -- Fixed inability to install/update mods that have periods in the name. -- Fixed stack sizes being displayed incorrectly on items with multiple inventories, e.g. deconstructor (unstable only). -- Fixed depleted fuel not being craftable (unstable only). -- Fixed leftmost inventory slot overlapping with the chatbox (unstable only). -- Fixed medic bots trying to treat genetic afflictions (unstable only). -- Fixed nav terminals "current_position_x" output being in pixels when "current_position_y" is in meters. -- Fixed tall subs overlapping with the buttons on the status monitor (unstable only). -- Fixed status monitor's item finder not finding wires (unstable only). -- Cargo scooters can't be put in toolbelts, crates, bandoliers or each other (unstable only). -- Fixed status monitor elements getting misaligned when 1st viewing it while linked to another interface and then individually or vice versa (unstable only). -- Fixed minerals sometimes spawning in unreachable spots in mining missions (on cells that are next to a cave, but at the wrong side of that cell if there's empty space behind it). -- Fixed items' "allow swapping" property being editable in-game. -- Fixed tainted genetic materials becoming untainted when saving and loading (unstable only). -- Fixed genetic material effects' strengths changing when saving and reloading (unstable only). -- Fixed tainted genetic materials sometimes giving the user hammerhead matriarch's genetic effects. -- Fixed inability to tinker loaders (unstable only). -- Fixed RegEx components with a non-continuous output always sending a signal out after being loaded. -- Fixed pirate subs sometimes spawning inside floating ice chunks. -- Fixed recommended treatments not changing when the strengths of the displayed afflictions change. -- Fixed cargo scooters working with a battery in an incorrect slot (unstable only). -- Fixed cargo scooters and volatile fulgurium fuel rods being craftable by anyone (unstable only). -- Fixed misaligned nav terminal and status monitor in pirate humpback. -- Fixed crash when ordering friendly NPCs (e.g. hostages) to return to the sub. - ---------------------------------------------------------------------------------------------------------- -v0.1500.3.0 ---------------------------------------------------------------------------------------------------------- +- Made welding tools a bit less effective early to compensate for increases to their effectiveness from quality/talents. +- Upgrade system reworked to work better in conjunction with new talents and quality systems. Quality of life upgrades made better or cheaper, hull upgrades are less effective towards the lategame but are better early, reorganized categories. +- Diving suit and human ragdoll damagemodifier changes: the suits now offer less protection, but humans have a bit more natural protection towards physical damage types. +- Adjustments to outpost distribution: natural formations greatly reduced in the 1st zone, cities slightly reduced in the 1st zone, outposts (including specialized ones) increased in the 3rd and 4th zone. +- Made magnesium a little more common in stores and wrecks. Additions and changes: -- More talents and talent-related items (all talent trees now functional and most of the talents implemented). - -Changes: -- Ignore hidden afflictions when determining treatment suggestions to show in the health interface. -- Visualize leaks on the status monitor's hull condition tab (unstable only). -- Added "condition_out" output to outpost O2 generator (unstable only). - -Fixes: -- Fixed crashing when reloading sprites or resetting to prefab in the sub editor. -- Fixed ability to combine unidentified genetic materials with other genetic materials (unstable only). -- Organ damage doesn't cause concussions (unstable only). -- Fixed talent menu being accessible if you leave it open and switch to a game mode where it shouldn't be accessible (unstable only). -- Fixed ability to contain items other than batteries in cargo scooter's battery slot (unstable only). -- Damaging the mudraptor beak given by mudraptor genes damages the head instead of torso, added damage protection to the beak (unstable only). -- Items that are set to be hidden in menus aren't shown in the status monitor's item finder (unstable only). -- Fixed status monitor's item finder not showing wearable items (unstable only). -- Fixed "in use by xxxx" warning being always visible when using a Reactor PDA (unstable only). -- Fixed Reactor PDA rendering over the command interface (unstable only). -- Fixed assault rifle crosshair being drawn when it's in the bag slot (unstable only). -- Fixed equip buttons not being drawn on equipped items that can only be put to other equip slots, but not on the non-limb slots (e.g. assault rifle). - -Modding: -- Option to make property conditionals target contained items using the attribute targetcontaineditem="true". - ---------------------------------------------------------------------------------------------------------- -v0.1500.2.0 ---------------------------------------------------------------------------------------------------------- - -Additions and changes: -- A bunch more talents and talent-related items. +- Gene splicing. You can find alien genetic material inside ruins (and for the time being, wrecks), and use these materials to gain special abilities and buffs. The materials can be processed using a Research Station (which atm can be found in research outposts) and applied on a character using a Gene Splicer. - Added a new "Return" order for ordering bots to return back to the main submarine. - Bots can now use level waypoints to help them navigate around when they are outside the submarine. -- Characters can now only have a single "Movement" category order at a time. -- Added condition_out pin to various items. -- Adjusted the color of the status terminal to be more greener. -- Added door and hatch position indicators to status monitor. -- Made alerts and job icons in status monitor be consistent in size. -- Combined genetic materials show the descriptions of both of the materials in the tooltip. -- The talent menu is disabled when not controlling a human character or playing the campaign. -- Disabled toggling the sonar mode by pressing the Run key. -- Changed default creature attack key to F because R conflicts with the radio keybind. -- Adjustments to how far creatures can see and hear the submarine and it's devices from. Moving fast now makes more noise, moving slowly less, and the monsters can't see the sub from as far as before. Effectively it should now be more viable tactic to shut the engines down and keep silent. -- Reduce sonar ping's sound range from 10000 to 8000 to make it possible to spot (some) monsters before they target the sub. -- Made a couple of monsters unable to eat characters (hammerheads, terminal cells, leucocytes, molochs, spinelings and watchers). - -Fixes: -- Fixed crash when loading a container that has no containable restrictions and contains items (e.g. if you put items in a deconstructor and start a new round). -- Fixed bots not swapping oxygen tanks when they are outside and going to a target that is inside. -- Fixed issues with bot combat behavior when outside the submarine. -- Fixed ability to hold 2-handed items with one hand by trying insert them into an occupied slot in a container that can't hold the item. -- Fixed genetic materia's effects not always disappearing when unequipping the material (unstable only). -- Fixed light components staying powered indefinitely when in a container or inventory (didn't seem to be noticeable on any other vanilla items than sonar beacons, which stayed active indefinitely). -- Fixed some outpost events being possible to activate even if the target NPC is dead. -- Fixed ability to swap contained non-interactable items. -- Fixed inability to adjust max mission count in a dedicated server. -- Fixed ID overlaps when loading outpost modules that contain items which spawn with some contained item (e.g. alien battery cells or magazines). -- Fixed characters in the transition phase of a husk infection (i.e. after the stinger has appeared) getting stunned at the start of every round. -- Fixed cargo missions sometimes only rewarding the players for 1 crate even when transporting more. -- Fixed heavy scooter working even if the battery is not in the correct slot, added an icon to the battery slot (unstable only). -- Fixed the "use as treatment" tooltip showing up when trying to drop an item that can't be used as a treatment on the health interface. -- Fixed characters with spineling/raptor genes turning into husks when they die (unstable only). -- Fixed any amount of damage triggering mollusc gene's vigor buff (unstable only), making it easy to max the vigor with tools that do damage every frame (e.g. plasma cutter). -- Fixed genetic materials refining to 100% when combined with stabilozine (unstable only). -- Fixed gene splicer slot's tooltip staying visible when you close the health interface while your cursor is on the slot (unstable only). -- Fixed gene splicer slot sometimes being misaligned when opening the health interface for the 1st time (unstable only). -- Fixed concussion's description being used as its name (unstable only). -- Fixed ability to recursively stack bandoliers, toolbelts and heavy scooters. - -Modding: -- Option to make afflictions draw a full-screen overlay when active. - ---------------------------------------------------------------------------------------------------------- -v0.1500.1.0 ---------------------------------------------------------------------------------------------------------- - -Additions and changes: -- Gene splicing. You can find alien genetic material inside ruins (and for the time being, wrecks), and use these materials to gain special abilities and buffs. The materials can be processed using a Research Station (which atm can be found in research outpost) and applied on a character using a Gene Splicer. -- Added WIP talent trees for security officers and assistants. -- Streamlined the health interface. -- Allow administering meds by clicking on the "suitable treatments" suggestions in the health interface. -- Physical injuries to the head can cause concussions. -- Play editor music in multiplayer lobby. +- Play editor music in the multiplayer lobby. - Option to specify the amount of items to spawn with the "spawnitem" command. - Optimized cave vent and ballast flora spore particles. - Added a 5 second "cooldown" before a junction box broken by overloading can take damage from overloading again. Prevents continuous fires and particles when continuously repairing an overloaded junction box. - Small monsters don't eat the inventory contents of a character they're eating (the items drop instead). - Disabled new status monitor features from handheld status monitors. - Round water and oxygen percentage readings on the status monitor (e.g. 99.999998% shows up as 100% instead of 99%). - -Fixes: -- Fixed crashing when an attack is applied on a character from a source other than another character, e.g. propeller (unstable only). -- Fixed current_position_y output not working on nav terminals (unstable only). -- Fixed fuel rods having a bullet as a contained indicator (unstable only). -- Removed duplicate welcome messages from humpack's terminal. -- Fixed start and spectate buttons shrinking in the server lobby every time they're hidden and re-enabled. -- Fixed contained items inside contained items not moving when repositioning a container in the sub editor (e.g. when moving a weapon holder that contains a weapon with a magazine). -- Fixed issues with inaccurate tooltips and incorrectly blocked out order nodes in character-specific command interface. -- Fixed contained items' status effects appearing at the top-left corner of the container if the contained items are not visible (e.g. particle-emitting fuel rods would emit the particles from the top-left corner of the reactor instead of the center). -- Fixed hanging wires not getting selected when selecting the items they're connected to. -- Fixed "divide by zero" console error when scaling construction barrier. -- Fixed ability to wire item between two submarines as long as you stay inside the same sub. -- Fixed crew list background blocking mouse input (again). -- Fixed crashing when the majority of the players are controlling characters belonging to a non-player team while the sub is at the end of the level (e.g. if you're alone in the sub and take control of a monster with console commands). - -Modding: -- Option to configure minimum damage for OnDamage status effects that require a specific type of affliction (see the "vigor on damage" affliction for an usage example). - ---------------------------------------------------------------------------------------------------------- -v0.1500.0.0 ---------------------------------------------------------------------------------------------------------- - -Additions and changes: -- Groundwork for the upcoming talent system: completing missions gives the characters experience points which can be used to unlock special abilities or buffs. Currently only the captain has talents implemented. -- Improved bot chatter when orders are being given, rearranged, or dismissed. -- Damage to arms reduces aiming accuracy. -- Crippled legs slow the player down more. -- Improvements to the blood particle effects when a character is bleeding. +- Adjustments to how far creatures can see and hear the submarine and it's devices from. Moving fast now makes more noise, moving slowly less, and the monsters can't see the sub from as far as before. Effectively it should now be more viable tactic to shut the engines down and keep silent. +- Reduce sonar ping's sound range from 10000 to 8000 to make it possible to spot (some) monsters before they target the sub. +- Made a couple of monsters unable to eat characters (hammerheads, terminal cells, leucocytes, molochs, spinelings and watchers). +- Changed default creature attack key to F because R conflicts with the radio keybind. +- Disabled toggling the sonar mode by pressing the Run key. +- Added condition_out pin to various items. +- Bots no longer ignore unconscious targets that regenerate health (i.e. they will finish off downed husks to prevent them from getting back up again). +- Fabricating fuel rods now requires electrical skills instead of mechanical. +- Reactor now requires electrical skills instead of mechanical to repair. +- When the status monitor receives the oxygen/water level for a hull, it registers it on all the linked hulls as well (-> no need to put an oxygen/water detector in all the hulls of a multi-hull room). +- Removed the "burndamage" damage type (not the same as "burn") that was added as a temporary workaround to allow pulse lasers to bypass monster's damage modifiers. +- Changed the look of the skill/xp notifications to accommodate the larger numbers of notifications you can get from talents and skillbooks. +- Added a fabricator and deconstructor to Azimuth and slightly lowered its maximum speed. +- Increased Azimuth's battery out relay max power. +- Temporarily disabled magnesium exploding in water to prevent issues with talents related to it. - Added "targetlimb" argument to the giveaffliction command (allows applying the affliction to a specific limb). - Players who wander inside a respawn shuttle don't get automatically killed when the shuttle despawns if they weren't part of the respawning crew. -- Bots no longer ignore severe fire in reactor, engine, or command rooms. The intention for them ignoring the severe fires was to prevent unwanted casualities when the fire can be left untreated and wait for it to fade out when not ordered to extinguish fires. +- Bots no longer ignore severe fires in reactor, engine, or command rooms. The intention for them ignoring the severe fires was to prevent unwanted casualities when the fire can be left untreated and wait for it to fade out when not ordered to extinguish fires. - Buffs are transferred to AI-controlled husks when a character transforms. - Projectiles shift to the left in multi-slot loaders when firing. - Option to make terminals use a monospaced font. @@ -344,14 +124,61 @@ Additions and changes: - Lever state is visualized on its sprite. - Enabled NVidia Optimus on Windows. -Overhauled status monitor: -- Improved visuals. -- Indicates the locations of the crew's ID cards. -- Indicates the locations of alerts. -- Electrical view, indicating locations and health of junction boxes, reactor and batteries. -- Allows searching for items and indicating the hulls in which they're located. - Fixes: +- Fixed crashing when an attack is applied on a character from a source other than another character, e.g. propeller (unstable only). +- Fixed current_position_y output not working on nav terminals (unstable only). +- Fixed fuel rods having a bullet as a contained indicator (unstable only). +- Removed duplicate welcome messages from humpack's terminal. +- Fixed start and spectate buttons shrinking in the server lobby every time they're hidden and re-enabled. +- Fixed contained items inside contained items not moving when repositioning a container in the sub editor (e.g. when moving a weapon holder that contains a weapon with a magazine). +- Fixed issues with inaccurate tooltips and incorrectly blocked out order nodes in character-specific command interface. +- Fixed contained items' status effects appearing at the top-left corner of the container if the contained items are not visible (e.g. particle-emitting fuel rods would emit the particles from the top-left corner of the reactor instead of the center). +- Fixed hanging wires not getting selected when selecting the items they're connected to. +- Fixed "divide by zero" console error when scaling construction barrier. +- Fixed ability to wire items between two submarines as long as you stay inside the same sub. +- Fixed crew list background blocking mouse input (again). +- Fixed crashing when the majority of the players are controlling characters belonging to a non-player team while the sub is at the end of the level (e.g. if you're alone in the sub and take control of a monster with console commands). +- Fixed cargo missions sometimes only rewarding the players for 1 crate even when transporting more. +- Fixed the "use as treatment" tooltip showing up when trying to drop an item that can't be used as a treatment on the health interface. +- Fixed characters in the transition phase of a husk infection (i.e. after the stinger has appeared) getting stunned at the start of every round. +- Fixed inability to adjust max mission count in a dedicated server. +- Fixed light components staying powered indefinitely when in a container or inventory (didn't seem to be noticeable on any other vanilla items than sonar beacons, which stayed active indefinitely). +- Fixed some outpost events being possible to activate even if the target NPC is dead. +- Fixed ability to swap contained non-interactable items. +- Fixed crash when loading a container that has no containable restrictions and contains items (e.g. if you put items in a deconstructor and start a new round). +- Fixed bots not swapping oxygen tanks when they are outside and going to a target that is inside. +- Fixed issues with bot combat behavior when outside the submarine. +- Fixed ability to hold 2-handed items with one hand by trying to insert them into an occupied slot in a container that can't hold the item. +- Fixed misaligned nav terminal and status monitor in pirate humpback. +- Fixed inability to install/update mods that have periods in the name. +- Fixed nav terminals "current_position_x" output being in pixels when "current_position_y" is in meters. +- Fixed minerals sometimes spawning in unreachable spots in mining missions (on cells that are next to a cave, but at the wrong side of that cell if there's empty space behind it). +- Fixed items' "allow swapping" property being editable in-game. +- Fixed RegEx components with a non-continuous output always sending a signal out after being loaded. +- Fixed pirate subs sometimes spawning inside floating ice chunks. +- Fixed tracer particles not starting from the position of ranged weapons' barrel. +- Fixed inability to open the pause menu when the cursor is over an inventory slot. +- Fixed handcuffs dropping off from characters' hands when they die or turn into a husk. +- Fixed loadsub command. +- Cap the amount argument of the spawnitem command to 100 to prevent freezing/crashing when trying to spawn a ridiculous amount of the item. +- Fixed "infiltration" event getting stuck on one of the conversation options. +- Fixed signal source being wrong on delayed electrical signals (= signals that were delayed for the next frame after they'd passed through 10 steps). Most noticeably affected status monitors that need to know which oxygen/water detector a signal came from. +- Fixed WifiComponents delaying the signals based on the number of receivers, not how many steps the signal has actually taken, contributing to the previous issue. +- Hopefully fixed an oversight in the sub editor where changing ItemComponent colors with the HSV picker would create an error in the console. +- Fixed paralyzant (and many other meds that don't do direct damage) not triggering guards. +- Fixed sonar monitor's UI being unnecessarily small. +- Fixed contained items inside contained items (e.g. magazines in a rifle on a weapon holder) not rotating in the sub editor. +- The overdosed NPC in the "good samaritan" event can't die until the player has triggered the event (completing the event after the NPC had already died made no sense). +- Fixed console errors when an item a bot has been ordered to target was removed between rounds (e.g. an ignore order targeting a mission item that gets removed at the end of the round). +- Fixes to oxygen generator logic: the generator now periodically recalculates how to distribute the oxygen between the vents, as opposed to doing it once at the start of the round. Just doing it once caused issues if there were e.g. vents or doors that are initially open between the rooms. +- Fixed characters sometimes getting "stuck" when swimming in partially filled multi-hull rooms. Happened because the bottom of the current hull was used as the "floor" if the actual floor was too far below, even if there was another hull below the current one, causing the ragdoll to switch to walking animation and being unable to move because it's not touching the floor (unstable only). +- Fixed outpost events always unlocking the same escort mission. +- The hints about flooded rooms and ballast flora aren't shown in ruins, wrecks or enemy subs. +- Fixed "stowaway" event triggering an event cooldown, preventing monsters from spawning at the beginning of the round. +- Fixed clients (excluding the host) always considering friendly fire to be disabled, leading to minor cosmetic desyncs when a player applies afflictions on another one (i.e. there was a brief delay before the afflictions update client-side). +- Fixed inability to apply buffs on the crew when friendly fire is disabled. +- Fixed ItemContainers only applying the StatusEffects from the first matching Containable, even if there's multiple. Prevented the artifact-specific effects of artifact holder from executing. +- Fixed "giveaffliction" command's limbtype argument not working in multiplayer. - Fixed "linesperlogfile" server setting doing nothing. - Fixed discharge coils not working when triggered by via a wired button. - Fixed hatch waypoint and platforms on Remora Drone. @@ -364,6 +191,12 @@ Fixes: Modding: - Implemented an item variant system that works similar to the character variants: you can create new items that inherit the properties of another item and only modify specific aspects of it, reducing the amount of duplicate XML code. See "Depleted Fuel Rod" in engineer_talent_items.xml for an usage example. +- Option to configure minimum damage for OnDamage status effects that require a specific type of affliction (see the "vigor on damage" affliction for an usage example). +- Option to make afflictions draw a full-screen overlay when active. +- Option to make property conditionals target contained items using the attribute targetcontaineditem="true". +- Added support for tileable light textures for Structures by using XML element that has the same syntax as does for Items. +- Added "InPressure" property to characters. +- Fixed hidden items appearing in the job loadout preview if there are other items of the same type that are not hidden (didn't affect any vanilla loadouts). - Removed error message when trying to transfer items to a husk monster and inventory sizes don't match - Submarine upgrades can be disallowed by category instead of having to do it separately for each upgrade in the sub editor. - Fixed a modding related crash when trying to apply a property value of a wrong type using status effects. @@ -984,7 +817,7 @@ v0.12.0.1 --------------------------------------------------------------------------------------------------------- - Adjustments and balancing to monster spawns. -- Modifed meds, buffs and poisons fabrication times. +- Modified meds, buffs and poisons fabrication times. - Potential fix to occasional disconnects with an "index was outside the bounds of the array (ENTITY_POSITION)" error message. Happened when lots of items and characters were being created and removed in rapid succession, for example when using turrets against large numbers of enemies. - Fixed a rare crash caused by an "index out of range" exception in Hull.Update after loading or mirroring certain custom submarines. - Fixed submarine class not affecting the depth at which a submarine starts taking pressure damage.